/*
*
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel 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 <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <glib.h>
#include <ell/ell.h>
#include <ofono/types.h>
#include "smsutil.h"
#include "stkutil.h"
#include "simutil.h"
#include "util.h"
enum stk_data_object_flag {
DATAOBJ_FLAG_MANDATORY = 1,
DATAOBJ_FLAG_MINIMUM = 2,
DATAOBJ_FLAG_CR = 4,
DATAOBJ_FLAG_LIST = 8,
};
struct stk_file_iter {
const uint8_t *start;
unsigned int pos;
unsigned int max;
uint8_t len;
const uint8_t *file;
};
struct stk_tlv_builder {
struct comprehension_tlv_builder ctlv;
uint8_t *value;
unsigned int len;
unsigned int max_len;
};
typedef bool (*dataobj_handler)(struct comprehension_tlv_iter *, void *);
typedef bool (*dataobj_writer)(struct stk_tlv_builder *, const void *, bool);
/*
* Defined in TS 102.223 Section 8.13
* The type of gsm sms can be SMS-COMMAND AND SMS-SUBMIT. According to 23.040,
* the maximum length is 164 bytes. But for SMS-SUBMIT, sms may be packed by
* ME. Thus the maximum length of messsage could be 160 bytes, instead of 140
* bytes. So the total maximum length could be 184 bytes. Refer TS 31.111,
* section 6.4.10 for details.
*/
struct gsm_sms_tpdu {
unsigned int len;
uint8_t tpdu[184];
};
#define CHECK_TEXT_AND_ICON(text, icon_id) \
if (status != STK_PARSE_RESULT_OK) \
return status; \
\
if ((text == NULL || text[0] == '\0') && icon_id != 0) \
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD; \
static char *decode_text(uint8_t dcs, int len, const unsigned char *data)
{
char *utf8;
enum sms_charset charset;
if (sms_dcs_decode(dcs, NULL, &charset, NULL, NULL) == FALSE)
return NULL;
switch (charset) {
case SMS_CHARSET_7BIT:
{
long written;
unsigned long max_to_unpack = len * 8 / 7;
uint8_t *unpacked = unpack_7bit(data, len, 0, false,
max_to_unpack,
&written, 0);
if (unpacked == NULL)
return NULL;
utf8 = convert_gsm_to_utf8(unpacked, written,
NULL, NULL, 0);
l_free(unpacked);
break;
}
case SMS_CHARSET_8BIT:
utf8 = convert_gsm_to_utf8(data, len, NULL, NULL, 0);
break;
case SMS_CHARSET_UCS2:
utf8 = l_utf8_from_ucs2be(data, len);
break;
default:
utf8 = NULL;
}
return utf8;
}
/* For data object only to indicate its existence */
static bool parse_dataobj_common_bool(struct comprehension_tlv_iter *iter,
bool *out)
{
if (comprehension_tlv_iter_get_length(iter) != 0)
return false;
*out = true;
return true;
}
/* For data object that only has one byte */
static bool parse_dataobj_common_byte(struct comprehension_tlv_iter *iter,
uint8_t *out)
{
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
*out = data[0];
return true;
}
/* For data object that only has text terminated by '\0' */
static bool parse_dataobj_common_text(struct comprehension_tlv_iter *iter,
char **text)
{
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
*text = l_malloc(len + 1);
memcpy(*text, data, len);
(*text)[len] = '\0';
return true;
}
/* For data object that only has a byte array with undetermined length */
static bool parse_dataobj_common_byte_array(struct comprehension_tlv_iter *iter,
struct stk_common_byte_array *array)
{
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
array->len = len;
array->array = l_malloc(len);
memcpy(array->array, data, len);
return true;
}
static void stk_file_iter_init(struct stk_file_iter *iter,
const uint8_t *start, unsigned int len)
{
iter->start = start;
iter->max = len;
iter->pos = 0;
}
static bool stk_file_iter_next(struct stk_file_iter *iter)
{
unsigned int pos = iter->pos;
const unsigned int max = iter->max;
const uint8_t *start = iter->start;
unsigned int i;
uint8_t last_type;
if (pos + 2 >= max)
return false;
/* SIM EFs always start with ROOT MF, 0x3f */
if (start[iter->pos] != 0x3f)
return false;
last_type = 0x3f;
for (i = pos + 2; i < max; i += 2) {
/*
* Check the validity of file type.
* According to TS 11.11, each file id contains of two bytes,
* in which the first byte is the type of file. For GSM is:
* 0x3f: master file
* 0x7f: 1st level dedicated file
* 0x5f: 2nd level dedicated file
* 0x2f: elementary file under the master file
* 0x6f: elementary file under 1st level dedicated file
* 0x4f: elementary file under 2nd level dedicated file
*/
switch (start[i]) {
case 0x2f:
if (last_type != 0x3f)
return false;
break;
case 0x6f:
if (last_type != 0x7f)
return false;
break;
case 0x4f:
if (last_type != 0x5f)
return false;
break;
case 0x7f:
if (last_type != 0x3f)
return false;
break;
case 0x5f:
if (last_type != 0x7f)
return false;
break;
default:
return false;
}
if ((start[i] == 0x2f) || (start[i] == 0x6f) ||
(start[i] == 0x4f)) {
if (i + 1 >= max)
return false;
iter->file = start + pos;
iter->len = i - pos + 2;
iter->pos = i + 2;
return true;
}
last_type = start[i];
}
return false;
}
/* Defined in TS 102.223 Section 8.1 */
static bool parse_dataobj_address(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_address *addr = user;
const uint8_t *data;
unsigned int len;
char *number;
len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
number = l_malloc(len * 2 - 1);
addr->ton_npi = data[0];
addr->number = number;
sim_extract_bcd_number(data + 1, len - 1, addr->number);
return true;
}
/* Defined in TS 102.223 Section 8.2 */
static bool parse_dataobj_alpha_id(struct comprehension_tlv_iter *iter,
void *user)
{
char **alpha_id = user;
const uint8_t *data;
unsigned int len;
char *utf8;
len = comprehension_tlv_iter_get_length(iter);
if (len == 0) {
*alpha_id = NULL;
return true;
}
data = comprehension_tlv_iter_get_data(iter);
utf8 = sim_string_to_utf8(data, len);
if (utf8 == NULL)
return false;
*alpha_id = utf8;
return true;
}
/* Defined in TS 102.223 Section 8.3 */
static bool parse_dataobj_subaddress(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_subaddress *subaddr = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
if (len > sizeof(subaddr->subaddr))
return false;
data = comprehension_tlv_iter_get_data(iter);
subaddr->len = len;
memcpy(subaddr->subaddr, data, len);
subaddr->has_subaddr = true;
return true;
}
/* Defined in TS 102.223 Section 8.4 */
static bool parse_dataobj_ccp(struct comprehension_tlv_iter *iter, void *user)
{
struct stk_ccp *ccp = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
if (len > sizeof(ccp->ccp))
return false;
data = comprehension_tlv_iter_get_data(iter);
ccp->len = len;
memcpy(ccp->ccp, data, len);
return true;
}
/* Defined in TS 31.111 Section 8.5 */
static bool parse_dataobj_cbs_page(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_cbs_page *cp = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
if (len > sizeof(cp->page))
return false;
data = comprehension_tlv_iter_get_data(iter);
cp->len = len;
memcpy(cp->page, data, len);
return true;
}
/* Described in TS 102.223 Section 8.8 */
static bool parse_dataobj_duration(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_duration *duration = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] > 0x02)
return false;
if (data[1] == 0)
return false;
duration->unit = data[0];
duration->interval = data[1];
return true;
}
/* Defined in TS 102.223 Section 8.9 */
static bool parse_dataobj_item(struct comprehension_tlv_iter *iter, void *user)
{
struct stk_item *item = user;
const uint8_t *data;
unsigned int len;
char *utf8;
len = comprehension_tlv_iter_get_length(iter);
if (len == 0)
return true;
if (len == 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* The identifier is between 0x01 and 0xFF */
if (data[0] == 0)
return false;
utf8 = sim_string_to_utf8(data + 1, len - 1);
if (utf8 == NULL)
return false;
item->id = data[0];
item->text = utf8;
return true;
}
/* Defined in TS 102.223 Section 8.10 */
static bool parse_dataobj_item_id(struct comprehension_tlv_iter *iter,
void *user)
{
uint8_t *id = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
*id = data[0];
return true;
}
/* Defined in TS 102.223 Section 8.11 */
static bool parse_dataobj_response_len(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_response_length *response_len = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
response_len->min = data[0];
response_len->max = data[1];
return true;
}
/* Defined in TS 102.223 Section 8.12 */
static bool parse_dataobj_result(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_result *result = user;
const uint8_t *data;
unsigned int len;
uint8_t *additional;
len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
if ((len < 2) && ((data[0] == 0x20) || (data[0] == 0x21) ||
(data[0] == 0x26) || (data[0] == 0x38) ||
(data[0] == 0x39) || (data[0] == 0x3a) ||
(data[0] == 0x3c) || (data[0] == 0x3d)))
return false;
additional = l_malloc(len - 1);
result->type = data[0];
result->additional_len = len - 1;
result->additional = additional;
memcpy(result->additional, data + 1, len - 1);
return true;
}
/* Defined in TS 102.223 Section 8.13 */
static bool parse_dataobj_gsm_sms_tpdu(struct comprehension_tlv_iter *iter,
void *user)
{
struct gsm_sms_tpdu *tpdu = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len < 1 || len > sizeof(tpdu->tpdu))
return false;
data = comprehension_tlv_iter_get_data(iter);
tpdu->len = len;
memcpy(tpdu->tpdu, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.14 */
static bool parse_dataobj_ss(struct comprehension_tlv_iter *iter, void *user)
{
struct stk_ss *ss = user;
const uint8_t *data;
unsigned int len;
char *s;
len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
s = l_malloc(len * 2 - 1);
ss->ton_npi = data[0];
ss->ss = s;
sim_extract_bcd_number(data + 1, len - 1, ss->ss);
return true;
}
/* Defined in TS 102.223 Section 8.15 */
static bool parse_dataobj_text(struct comprehension_tlv_iter *iter, void *user)
{
char **text = user;
unsigned int len = comprehension_tlv_iter_get_length(iter);
const uint8_t *data;
char *utf8;
if (len <= 1) {
*text = l_new(char, 1);
return true;
}
data = comprehension_tlv_iter_get_data(iter);
utf8 = decode_text(data[0], len - 1, data + 1);
if (utf8 == NULL)
return false;
*text = utf8;
return true;
}
/* Defined in TS 102.223 Section 8.16 */
static bool parse_dataobj_tone(struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.17 */
static bool parse_dataobj_ussd(struct comprehension_tlv_iter *iter, void *user)
{
struct stk_ussd_string *us = user;
unsigned int len = comprehension_tlv_iter_get_length(iter);
const uint8_t *data = comprehension_tlv_iter_get_data(iter);
if (len <= 1 || len > 161)
return false;
us->dcs = data[0];
us->len = len - 1;
memcpy(us->string, data + 1, us->len);
return true;
}
/* Defined in TS 102.223 Section 8.18 */
static bool parse_dataobj_file_list(struct comprehension_tlv_iter *iter,
void *user)
{
struct l_queue **out = user;
struct l_queue *fl;
const uint8_t *data;
unsigned int len;
struct stk_file *sf;
struct stk_file_iter sf_iter;
len = comprehension_tlv_iter_get_length(iter);
if (len < 5)
return false;
data = comprehension_tlv_iter_get_data(iter);
stk_file_iter_init(&sf_iter, data + 1, len - 1);
fl = l_queue_new();
while (stk_file_iter_next(&sf_iter)) {
sf = l_new(struct stk_file, 1);
sf->len = sf_iter.len;
memcpy(sf->file, sf_iter.file, sf_iter.len);
l_queue_push_tail(fl, sf);
}
if (sf_iter.pos != sf_iter.max)
goto error;
*out = fl;
return true;
error:
l_queue_destroy(fl, l_free);
return false;
}
/* Defined in TS 102.223 Section 8.19 */
static bool parse_dataobj_location_info(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_location_info *li = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if ((len != 5) && (len != 7) && (len != 9))
return false;
data = comprehension_tlv_iter_get_data(iter);
sim_parse_mcc_mnc(data, li->mcc, li->mnc);
li->lac_tac = (data[3] << 8) + data[4];
if (len >= 7) {
li->has_ci = true;
li->ci = (data[5] << 8) + data[6];
}
if (len == 9) {
li->has_ext_ci = true;
li->ext_ci = (data[7] << 8) + data[8];
}
return true;
}
/*
* Defined in TS 102.223 Section 8.20.
*
* According to 3GPP TS 24.008, Section 10.5.1.4, IMEI is composed of
* 15 digits and totally 8 bytes are used to represent it.
*
* Bits 1-3 of first byte represent the type of identity, and they
* are 0 1 0 separately for IMEI. Bit 4 of first byte is the odd/even
* indication, and it's 1 to indicate IMEI has odd number of digits (15).
* The rest bytes are coded using BCD coding.
*
* For example, if the IMEI is "123456789012345", then it's coded as
* "1A 32 54 76 98 10 32 54".
*/
static bool parse_dataobj_imei(struct comprehension_tlv_iter *iter,
void *user)
{
char *imei = user;
const uint8_t *data;
unsigned int len;
static const char digit_lut[] = "0123456789*#abc\0";
len = comprehension_tlv_iter_get_length(iter);
if (len != 8)
return false;
data = comprehension_tlv_iter_get_data(iter);
if ((data[0] & 0x0f) != 0x0a)
return false;
/* Assume imei is at least 16 bytes long (15 for imei + null) */
imei[0] = digit_lut[(data[0] & 0xf0) >> 4];
extract_bcd_number(data + 1, 7, imei + 1);
return true;
}
/* Defined in TS 102.223 Section 8.21 */
static bool parse_dataobj_help_request(struct comprehension_tlv_iter *iter,
void *user)
{
bool *ret = user;
return parse_dataobj_common_bool(iter, ret);
}
/* Defined in TS 102.223 Section 8.22 */
static bool parse_dataobj_network_measurement_results(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *nmr = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len != 0x10)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* Assume network measurement result is 16 bytes long */
memcpy(nmr, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.23 */
static bool parse_dataobj_default_text(struct comprehension_tlv_iter *iter,
void *user)
{
char **text = user;
unsigned int len = comprehension_tlv_iter_get_length(iter);
const uint8_t *data = comprehension_tlv_iter_get_data(iter);
char *utf8;
/* DCS followed by some text, cannot be 1 */
if (len <= 1)
return false;
utf8 = decode_text(data[0], len - 1, data + 1);
if (utf8 == NULL)
return false;
*text = utf8;
return true;
}
/* Defined in TS 102.223 Section 8.24 */
static bool parse_dataobj_items_next_action_indicator(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_items_next_action_indicator *inai = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len < 1) || (len > sizeof(inai->list)))
return false;
data = comprehension_tlv_iter_get_data(iter);
inai->len = len;
memcpy(inai->list, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.25 */
static bool parse_dataobj_event_list(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_event_list *el = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len == 0)
return true;
if (len > sizeof(el->list))
return false;
data = comprehension_tlv_iter_get_data(iter);
el->len = len;
memcpy(el->list, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.26 */
static bool parse_dataobj_cause(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_cause *cause = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len == 1) || (len > sizeof(cause->cause)))
return false;
cause->has_cause = true;
if (len == 0)
return true;
data = comprehension_tlv_iter_get_data(iter);
cause->len = len;
memcpy(cause->cause, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.27 */
static bool parse_dataobj_location_status(struct comprehension_tlv_iter *iter,
void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.28 */
static bool parse_dataobj_transaction_id(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_transaction_id *ti = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len < 1) || (len > sizeof(ti->list)))
return false;
data = comprehension_tlv_iter_get_data(iter);
ti->len = len;
memcpy(ti->list, data, len);
return true;
}
/* Defined in TS 31.111 Section 8.29 */
static bool parse_dataobj_bcch_channel_list(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_bcch_channel_list *bcl = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
unsigned int i;
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
bcl->num = len * 8 / 10;
for (i = 0; i < bcl->num; i++) {
unsigned int index = i * 10 / 8;
unsigned int occupied = i * 10 % 8;
bcl->channels[i] = (data[index] << (2 + occupied)) +
(data[index + 1] >> (6 - occupied));
}
bcl->has_list = true;
return true;
}
/* Defined in TS 102.223 Section 8.30 */
static bool parse_dataobj_call_control_requested_action(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.31 */
static bool parse_dataobj_icon_id(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_icon_id *id = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
id->qualifier = data[0];
id->id = data[1];
return true;
}
/* Defined in TS 102.223 Section 8.32 */
static bool parse_dataobj_item_icon_id_list(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_item_icon_id_list *iiil = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len < 2) || (len > 127))
return false;
data = comprehension_tlv_iter_get_data(iter);
iiil->qualifier = data[0];
iiil->len = len - 1;
memcpy(iiil->list, data + 1, iiil->len);
return true;
}
/* Defined in TS 102.223 Section 8.33 */
static bool parse_dataobj_card_reader_status(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.34 */
static bool parse_dataobj_card_atr(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_card_atr *ca = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len < 1) || (len > sizeof(ca->atr)))
return false;
data = comprehension_tlv_iter_get_data(iter);
ca->len = len;
memcpy(ca->atr, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.35 */
static bool parse_dataobj_c_apdu(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_c_apdu *ca = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
unsigned int pos;
if ((len < 4) || (len > 241))
return false;
data = comprehension_tlv_iter_get_data(iter);
ca->cla = data[0];
ca->ins = data[1];
ca->p1 = data[2];
ca->p2 = data[3];
pos = 4;
/*
* lc is 0 has the same meaning as lc is absent. But le is 0 means
* the maximum number of bytes expected in the response data field
* is 256. So we need to rely on has_le to know if it presents.
*/
if (len > 5) {
ca->lc = data[4];
if (ca->lc > sizeof(ca->data))
return false;
pos += ca->lc + 1;
if (len - pos > 1)
return false;
memcpy(ca->data, data+5, ca->lc);
}
if (len - pos > 0) {
ca->le = data[len - 1];
ca->has_le = true;
}
return true;
}
/* Defined in TS 102.223 Section 8.36 */
static bool parse_dataobj_r_apdu(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_r_apdu *ra = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len < 2) || (len > 239))
return false;
data = comprehension_tlv_iter_get_data(iter);
ra->sw1 = data[len-2];
ra->sw2 = data[len-1];
if (len > 2) {
ra->len = len - 2;
memcpy(ra->data, data, ra->len);
} else
ra->len = 0;
return true;
}
/* Defined in TS 102.223 Section 8.37 */
static bool parse_dataobj_timer_id(struct comprehension_tlv_iter *iter,
void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.38 */
static bool parse_dataobj_timer_value(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_timer_value *tv = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 3)
return false;
data = comprehension_tlv_iter_get_data(iter);
tv->hour = sms_decode_semi_octet(data[0]);
tv->minute = sms_decode_semi_octet(data[1]);
tv->second = sms_decode_semi_octet(data[2]);
tv->has_value = true;
return true;
}
/* Defined in TS 102.223 Section 8.39 */
static bool parse_dataobj_datetime_timezone(
struct comprehension_tlv_iter *iter, void *user)
{
struct sms_scts *scts = user;
const uint8_t *data;
int offset = 0;
if (comprehension_tlv_iter_get_length(iter) != 7)
return false;
data = comprehension_tlv_iter_get_data(iter);
sms_decode_scts(data, 7, &offset, scts);
return true;
}
/* Defined in TS 102.223 Section 8.40 */
static bool parse_dataobj_at_command(struct comprehension_tlv_iter *iter,
void *user)
{
char **command = user;
return parse_dataobj_common_text(iter, command);
}
/* Defined in TS 102.223 Section 8.41 */
static bool parse_dataobj_at_response(struct comprehension_tlv_iter *iter,
void *user)
{
char **response = user;
return parse_dataobj_common_text(iter, response);
}
/* Defined in TS 102.223 Section 8.42 */
static bool parse_dataobj_bc_repeat_indicator(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_bc_repeat *bc_repeat = user;
if (!parse_dataobj_common_byte(iter, &bc_repeat->value))
return false;
bc_repeat->has_bc_repeat = true;
return true;
}
/* Defined in 102.223 Section 8.43 */
static bool parse_dataobj_imm_resp(struct comprehension_tlv_iter *iter,
void *user)
{
bool *ret = user;
return parse_dataobj_common_bool(iter, ret);
}
/* Defined in 102.223 Section 8.44 */
static bool parse_dataobj_dtmf_string(struct comprehension_tlv_iter *iter,
void *user)
{
char **dtmf = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
*dtmf = l_malloc(len * 2 + 1);
sim_extract_bcd_number(data, len, *dtmf);
return true;
}
/* Defined in 102.223 Section 8.45 */
static bool parse_dataobj_language(struct comprehension_tlv_iter *iter,
void *user)
{
char *lang = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
/*
* This is a 2 character pair as defined in ISO 639, coded using
* GSM default 7 bit alphabet with bit 8 set to 0. Since the english
* letters have the same mapping in GSM as ASCII, no conversion
* is required here
*/
memcpy(lang, data, len);
lang[len] = '\0';
return true;
}
/* Defined in 31.111 Section 8.46 */
static bool parse_dataobj_timing_advance(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_timing_advance *ta = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
ta->has_value = true;
ta->status = data[0];
ta->advance = data[1];
return true;
}
/* Defined in 102.223 Section 8.47 */
static bool parse_dataobj_browser_id(struct comprehension_tlv_iter *iter,
void *user)
{
uint8_t *byte = user;
if (!parse_dataobj_common_byte(iter, byte) || *byte > 4)
return false;
return true;
}
/* Defined in TS 102.223 Section 8.48 */
static bool parse_dataobj_url(struct comprehension_tlv_iter *iter, void *user)
{
char **url = user;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len == 0) {
*url = NULL;
return true;
}
return parse_dataobj_common_text(iter, url);
}
/* Defined in TS 102.223 Section 8.49 */
static bool parse_dataobj_bearer(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.50 */
static bool parse_dataobj_provisioning_file_reference(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_file *f = user;
const uint8_t *data;
struct stk_file_iter sf_iter;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len < 1) || (len > 8))
return false;
data = comprehension_tlv_iter_get_data(iter);
stk_file_iter_init(&sf_iter, data, len);
stk_file_iter_next(&sf_iter);
if (sf_iter.pos != sf_iter.max)
return false;
f->len = len;
memcpy(f->file, data, len);
return true;
}
/* Defined in 102.223 Section 8.51 */
static bool parse_dataobj_browser_termination_cause(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.52 */
static bool parse_dataobj_bearer_description(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_bearer_description *bd = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
bd->type = data[0];
/* Parse only the packet data service bearer parameters */
if (bd->type != STK_BEARER_TYPE_GPRS_UTRAN)
return false;
if (len < 7)
return false;
bd->gprs.precedence = data[1];
bd->gprs.delay = data[2];
bd->gprs.reliability = data[3];
bd->gprs.peak = data[4];
bd->gprs.mean = data[5];
bd->gprs.pdp_type = data[6];
return true;
}
/* Defined in TS 102.223 Section 8.53 */
static bool parse_dataobj_channel_data(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.54 */
static bool parse_dataobj_channel_data_length(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.55 */
static bool parse_dataobj_buffer_size(struct comprehension_tlv_iter *iter,
void *user)
{
uint16_t *size = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
*size = (data[0] << 8) + data[1];
return true;
}
/* Defined in TS 102.223 Section 8.56 */
static bool parse_dataobj_channel_status(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *status = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* Assume channel status is 2 bytes long */
memcpy(status, data, 2);
return true;
}
/* Defined in TS 102.223 Section 8.57 */
static bool parse_dataobj_card_reader_id(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_card_reader_id *cr_id = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
cr_id->len = len;
memcpy(cr_id->id, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.58 */
static bool parse_dataobj_other_address(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_other_address *oa = user;
const uint8_t *data;
uint8_t len = comprehension_tlv_iter_get_length(iter);
if (len == 0) {
oa->type = STK_ADDRESS_AUTO;
return true;
}
if ((len != 5) && (len != 17))
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] != STK_ADDRESS_IPV4 && data[0] != STK_ADDRESS_IPV6)
return false;
oa->type = data[0];
if (oa->type == STK_ADDRESS_IPV4)
memcpy(&oa->addr.ipv4, data + 1, 4);
else
memcpy(&oa->addr.ipv6, data + 1, 16);
return true;
}
/* Defined in TS 102.223 Section 8.59 */
static bool parse_dataobj_uicc_te_interface(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_uicc_te_interface *uti = user;
const uint8_t *data;
uint8_t len = comprehension_tlv_iter_get_length(iter);
if (len != 3)
return false;
data = comprehension_tlv_iter_get_data(iter);
uti->protocol = data[0];
uti->port = (data[1] << 8) + data[2];
return true;
}
/* Defined in TS 102.223 Section 8.60 */
static bool parse_dataobj_aid(struct comprehension_tlv_iter *iter, void *user)
{
struct stk_aid *aid = user;
const uint8_t *data;
uint8_t len = comprehension_tlv_iter_get_length(iter);
if ((len > 16) || (len < 12))
return false;
data = comprehension_tlv_iter_get_data(iter);
aid->len = len;
memcpy(aid->aid, data, len);
return true;
}
/*
* Defined in TS 102.223 Section 8.61. According to it, the technology field
* can have at most 127 bytes. However, all the defined values are only 1 byte,
* so we just use 1 byte to represent it.
*/
static bool parse_dataobj_access_technology(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.62 */
static bool parse_dataobj_display_parameters(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_display_parameters *dp = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 3)
return false;
data = comprehension_tlv_iter_get_data(iter);
dp->height = data[0];
dp->width = data[1];
dp->effects = data[2];
return true;
}
/* Defined in TS 102.223 Section 8.63 */
static bool parse_dataobj_service_record(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_service_record *sr = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len < 3)
return false;
data = comprehension_tlv_iter_get_data(iter);
sr->tech_id = data[0];
sr->serv_id = data[1];
sr->len = len - 2;
sr->serv_rec = l_malloc(sr->len);
memcpy(sr->serv_rec, data + 2, sr->len);
return true;
}
/* Defined in TS 102.223 Section 8.64 */
static bool parse_dataobj_device_filter(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_device_filter *df = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* According to TS 102.223, everything except BT & IRDA is RFU */
if (data[0] != STK_TECHNOLOGY_BLUETOOTH &&
data[0] != STK_TECHNOLOGY_IRDA)
return false;
df->tech_id = data[0];
df->len = len - 1;
df->dev_filter = l_malloc(df->len);
memcpy(df->dev_filter, data + 1, df->len);
return true;
}
/* Defined in TS 102.223 Section 8.65 */
static bool parse_dataobj_service_search(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_service_search *ss = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* According to TS 102.223, everything except BT & IRDA is RFU */
if (data[0] != STK_TECHNOLOGY_BLUETOOTH &&
data[0] != STK_TECHNOLOGY_IRDA)
return false;
ss->tech_id = data[0];
ss->len = len - 1;
ss->ser_search = l_malloc(ss->len);
memcpy(ss->ser_search, data + 1, ss->len);
return true;
}
/* Defined in TS 102.223 Section 8.66 */
static bool parse_dataobj_attribute_info(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_attribute_info *ai = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* According to TS 102.223, everything except BT & IRDA is RFU */
if (data[0] != STK_TECHNOLOGY_BLUETOOTH &&
data[0] != STK_TECHNOLOGY_IRDA)
return false;
ai->tech_id = data[0];
ai->len = len - 1;
ai->attr_info = l_malloc(ai->len);
memcpy(ai->attr_info, data + 1, ai->len);
return true;
}
/* Defined in TS 102.223 Section 8.67 */
static bool parse_dataobj_service_availability(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.68 */
static bool parse_dataobj_remote_entity_address(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_remote_entity_address *rea = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
data = comprehension_tlv_iter_get_data(iter);
switch (data[0]) {
case 0x00:
if (len != 7)
return false;
break;
case 0x01:
if (len != 5)
return false;
break;
default:
return false;
}
rea->has_address = true;
rea->coding_type = data[0];
memcpy(&rea->addr, data + 1, len - 1);
return true;
}
/* Defined in TS 102.223 Section 8.69 */
static bool parse_dataobj_esn(struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *esn = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len != 4)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* Assume esn is 4 bytes long */
memcpy(esn, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.70 */
static bool parse_dataobj_network_access_name(
struct comprehension_tlv_iter *iter,
void *user)
{
char **apn = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
uint8_t label_size;
uint8_t offset = 0;
char decoded_apn[100];
if (len == 0 || len > 100)
return false;
data = comprehension_tlv_iter_get_data(iter);
/*
* As specified in TS 23 003 Section 9
* The APN consists of one or more labels. Each label is coded as
* a one octet length field followed by that number of octets coded
* as 8 bit ASCII characters
*/
while (len) {
label_size = *data;
if (label_size == 0 || label_size > (len - 1))
return false;
memcpy(decoded_apn + offset, data + 1, label_size);
data += label_size + 1;
offset += label_size;
len -= label_size + 1;
if (len)
decoded_apn[offset++] = '.';
}
decoded_apn[offset] = '\0';
*apn = l_strdup(decoded_apn);
return true;
}
/* Defined in TS 102.223 Section 8.71 */
static bool parse_dataobj_cdma_sms_tpdu(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.72 */
static bool parse_dataobj_text_attr(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_text_attribute *attr = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len > sizeof(attr->attributes))
return false;
data = comprehension_tlv_iter_get_data(iter);
memcpy(attr->attributes, data, len);
attr->len = len;
return true;
}
/* Defined in TS 31.111 Section 8.72 */
static bool parse_dataobj_pdp_act_par(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_pdp_act_par *pcap = user;
const uint8_t *data;
unsigned int len;
len = comprehension_tlv_iter_get_length(iter);
if (len > sizeof(pcap->par))
return false;
data = comprehension_tlv_iter_get_data(iter);
memcpy(pcap->par, data, len);
pcap->len = len;
return true;
}
/* Defined in TS 102.223 Section 8.73 */
static bool parse_dataobj_item_text_attribute_list(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_item_text_attribute_list *ital = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if ((len > sizeof(ital->list)) || (len % 4 != 0))
return false;
data = comprehension_tlv_iter_get_data(iter);
memcpy(ital->list, data, len);
ital->len = len;
return true;
}
/* Defined in TS 31.111 Section 8.73 */
static bool parse_dataobj_utran_meas_qualifier(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/*
* Defined in TS 102.223 Section 8.74.
*
* According to 3GPP TS 24.008, Section 10.5.1.4, IMEISV is composed of
* 16 digits and totally 9 bytes are used to represent it.
*
* Bits 1-3 of first byte represent the type of identity, and they
* are 0 1 1 separately for IMEISV. Bit 4 of first byte is the odd/even
* indication, and it's 0 to indicate IMEISV has odd number of digits (16).
* The rest bytes are coded using BCD coding.
*
* For example, if the IMEISV is "1234567890123456", then it's coded as
* "13 32 54 76 98 10 32 54 F6".
*/
static bool parse_dataobj_imeisv(struct comprehension_tlv_iter *iter,
void *user)
{
char *imeisv = user;
const uint8_t *data;
unsigned int len;
static const char digit_lut[] = "0123456789*#abc\0";
len = comprehension_tlv_iter_get_length(iter);
if (len != 9)
return false;
data = comprehension_tlv_iter_get_data(iter);
if ((data[0] & 0x0f) != 0x03)
return false;
if (data[8] >> 4 != 0x0f)
return false;
/* Assume imeisv is at least 17 bytes long (16 for imeisv + null) */
imeisv[0] = digit_lut[data[0] >> 4];
extract_bcd_number(data + 1, 7, imeisv + 1);
imeisv[15] = digit_lut[data[8] & 0x0f];
imeisv[16] = '\0';
return true;
}
/* Defined in TS 102.223 Section 8.75 */
static bool parse_dataobj_network_search_mode(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.76 */
static bool parse_dataobj_battery_state(struct comprehension_tlv_iter *iter,
void *user)
{
uint8_t *byte = user;
return parse_dataobj_common_byte(iter, byte);
}
/* Defined in TS 102.223 Section 8.77 */
static bool parse_dataobj_browsing_status(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.78 */
static bool parse_dataobj_frame_layout(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_frame_layout *fl = user;
const uint8_t *data;
uint8_t len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] != STK_LAYOUT_HORIZONTAL &&
data[0] != STK_LAYOUT_VERTICAL)
return false;
fl->layout = data[0];
fl->len = len - 1;
memcpy(fl->size, data + 1, fl->len);
return true;
}
/* Defined in TS 102.223 Section 8.79 */
static bool parse_dataobj_frames_info(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_frames_info *fi = user;
const uint8_t *data;
uint8_t len = comprehension_tlv_iter_get_length(iter);
unsigned int i;
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] > 0x0f)
return false;
if ((len == 1 && data[0] != 0) || (len > 1 && data[0] == 0))
return false;
if (len % 2 == 0)
return false;
if (len == 1)
return true;
fi->id = data[0];
fi->len = (len - 1) / 2;
for (i = 0; i < len; i++) {
fi->list[i].height = data[i * 2 + 1] & 0x1f;
fi->list[i].width = data[i * 2 + 2] & 0x7f;
}
return true;
}
/* Defined in TS 102.223 Section 8.80 */
static bool parse_dataobj_frame_id(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_frame_id *fi = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] >= 0x10)
return false;
fi->has_id = true;
fi->id = data[0];
return true;
}
/* Defined in TS 102.223 Section 8.81 */
static bool parse_dataobj_meid(struct comprehension_tlv_iter *iter,
void *user)
{
uint8_t *meid = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 8)
return false;
data = comprehension_tlv_iter_get_data(iter);
/* Assume meid is 8 bytes long */
memcpy(meid, data, 8);
return true;
}
/* Defined in TS 102.223 Section 8.82 */
static bool parse_dataobj_mms_reference(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_mms_reference *mr = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
mr->len = len;
memcpy(mr->ref, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.83 */
static bool parse_dataobj_mms_id(struct comprehension_tlv_iter *iter,
void *user)
{
struct stk_mms_id *mi = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
mi->len = len;
memcpy(mi->id, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.84 */
static bool parse_dataobj_mms_transfer_status(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_mms_transfer_status *mts = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
mts->len = len;
memcpy(mts->status, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.85 */
static bool parse_dataobj_mms_content_id(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_mms_content_id *mci = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
mci->len = len;
memcpy(mci->id, data, len);
return true;
}
/* Defined in TS 102.223 Section 8.86 */
static bool parse_dataobj_mms_notification(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_common_byte_array *array = user;
return parse_dataobj_common_byte_array(iter, array);
}
/* Defined in TS 102.223 Section 8.87 */
static bool parse_dataobj_last_envelope(struct comprehension_tlv_iter *iter,
void *user)
{
bool *ret = user;
return parse_dataobj_common_bool(iter, ret);
}
/* Defined in TS 102.223 Section 8.88 */
static bool parse_dataobj_registry_application_data(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_registry_application_data *rad = user;
const uint8_t *data;
char *utf8;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 5)
return false;
data = comprehension_tlv_iter_get_data(iter);
utf8 = decode_text(data[2], len - 4, data + 4);
if (utf8 == NULL)
return false;
rad->name = utf8;
rad->port = (data[0] << 8) + data[1];
rad->type = data[3];
return true;
}
/* Defined in TS 102.223 Section 8.89 */
static bool parse_dataobj_activate_descriptor(
struct comprehension_tlv_iter *iter, void *user)
{
uint8_t *byte = user;
const uint8_t *data;
if (comprehension_tlv_iter_get_length(iter) != 1)
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] != 0x01)
return false;
*byte = data[0];
return true;
}
/* Defined in TS 102.223 Section 8.90 */
static bool parse_dataobj_broadcast_network_info(
struct comprehension_tlv_iter *iter, void *user)
{
struct stk_broadcast_network_information *bni = user;
const uint8_t *data;
unsigned int len = comprehension_tlv_iter_get_length(iter);
if (len < 2)
return false;
data = comprehension_tlv_iter_get_data(iter);
if (data[0] > 0x03)
return false;
bni->tech = data[0];
bni->len = len - 1;
memcpy(bni->loc_info, data + 1, bni->len);
return true;
}
static dataobj_handler handler_for_type(enum stk_data_object_type type)
{
switch (type) {
case STK_DATA_OBJECT_TYPE_ADDRESS:
return parse_dataobj_address;
case STK_DATA_OBJECT_TYPE_ALPHA_ID:
return parse_dataobj_alpha_id;
case STK_DATA_OBJECT_TYPE_SUBADDRESS:
return parse_dataobj_subaddress;
case STK_DATA_OBJECT_TYPE_CCP:
return parse_dataobj_ccp;
case STK_DATA_OBJECT_TYPE_CBS_PAGE:
return parse_dataobj_cbs_page;
case STK_DATA_OBJECT_TYPE_DURATION:
return parse_dataobj_duration;
case STK_DATA_OBJECT_TYPE_ITEM:
return parse_dataobj_item;
case STK_DATA_OBJECT_TYPE_ITEM_ID:
return parse_dataobj_item_id;
case STK_DATA_OBJECT_TYPE_RESPONSE_LENGTH:
return parse_dataobj_response_len;
case STK_DATA_OBJECT_TYPE_RESULT:
return parse_dataobj_result;
case STK_DATA_OBJECT_TYPE_GSM_SMS_TPDU:
return parse_dataobj_gsm_sms_tpdu;
case STK_DATA_OBJECT_TYPE_SS_STRING:
return parse_dataobj_ss;
case STK_DATA_OBJECT_TYPE_TEXT:
return parse_dataobj_text;
case STK_DATA_OBJECT_TYPE_TONE:
return parse_dataobj_tone;
case STK_DATA_OBJECT_TYPE_USSD_STRING:
return parse_dataobj_ussd;
case STK_DATA_OBJECT_TYPE_FILE_LIST:
return parse_dataobj_file_list;
case STK_DATA_OBJECT_TYPE_LOCATION_INFO:
return parse_dataobj_location_info;
case STK_DATA_OBJECT_TYPE_IMEI:
return parse_dataobj_imei;
case STK_DATA_OBJECT_TYPE_HELP_REQUEST:
return parse_dataobj_help_request;
case STK_DATA_OBJECT_TYPE_NETWORK_MEASUREMENT_RESULTS:
return parse_dataobj_network_measurement_results;
case STK_DATA_OBJECT_TYPE_DEFAULT_TEXT:
return parse_dataobj_default_text;
case STK_DATA_OBJECT_TYPE_ITEMS_NEXT_ACTION_INDICATOR:
return parse_dataobj_items_next_action_indicator;
case STK_DATA_OBJECT_TYPE_EVENT_LIST:
return parse_dataobj_event_list;
case STK_DATA_OBJECT_TYPE_CAUSE:
return parse_dataobj_cause;
case STK_DATA_OBJECT_TYPE_LOCATION_STATUS:
return parse_dataobj_location_status;
case STK_DATA_OBJECT_TYPE_TRANSACTION_ID:
return parse_dataobj_transaction_id;
case STK_DATA_OBJECT_TYPE_BCCH_CHANNEL_LIST:
return parse_dataobj_bcch_channel_list;
case STK_DATA_OBJECT_TYPE_CALL_CONTROL_REQUESTED_ACTION:
return parse_dataobj_call_control_requested_action;
case STK_DATA_OBJECT_TYPE_ICON_ID:
return parse_dataobj_icon_id;
case STK_DATA_OBJECT_TYPE_ITEM_ICON_ID_LIST:
return parse_dataobj_item_icon_id_list;
case STK_DATA_OBJECT_TYPE_CARD_READER_STATUS:
return parse_dataobj_card_reader_status;
case STK_DATA_OBJECT_TYPE_CARD_ATR:
return parse_dataobj_card_atr;
case STK_DATA_OBJECT_TYPE_C_APDU:
return parse_dataobj_c_apdu;
case STK_DATA_OBJECT_TYPE_R_APDU:
return parse_dataobj_r_apdu;
case STK_DATA_OBJECT_TYPE_TIMER_ID:
return parse_dataobj_timer_id;
case STK_DATA_OBJECT_TYPE_TIMER_VALUE:
return parse_dataobj_timer_value;
case STK_DATA_OBJECT_TYPE_DATETIME_TIMEZONE:
return parse_dataobj_datetime_timezone;
case STK_DATA_OBJECT_TYPE_AT_COMMAND:
return parse_dataobj_at_command;
case STK_DATA_OBJECT_TYPE_AT_RESPONSE:
return parse_dataobj_at_response;
case STK_DATA_OBJECT_TYPE_BC_REPEAT_INDICATOR:
return parse_dataobj_bc_repeat_indicator;
case STK_DATA_OBJECT_TYPE_IMMEDIATE_RESPONSE:
return parse_dataobj_imm_resp;
case STK_DATA_OBJECT_TYPE_DTMF_STRING:
return parse_dataobj_dtmf_string;
case STK_DATA_OBJECT_TYPE_LANGUAGE:
return parse_dataobj_language;
case STK_DATA_OBJECT_TYPE_BROWSER_ID:
return parse_dataobj_browser_id;
case STK_DATA_OBJECT_TYPE_TIMING_ADVANCE:
return parse_dataobj_timing_advance;
case STK_DATA_OBJECT_TYPE_URL:
return parse_dataobj_url;
case STK_DATA_OBJECT_TYPE_BEARER:
return parse_dataobj_bearer;
case STK_DATA_OBJECT_TYPE_PROVISIONING_FILE_REF:
return parse_dataobj_provisioning_file_reference;
case STK_DATA_OBJECT_TYPE_BROWSER_TERMINATION_CAUSE:
return parse_dataobj_browser_termination_cause;
case STK_DATA_OBJECT_TYPE_BEARER_DESCRIPTION:
return parse_dataobj_bearer_description;
case STK_DATA_OBJECT_TYPE_CHANNEL_DATA:
return parse_dataobj_channel_data;
case STK_DATA_OBJECT_TYPE_CHANNEL_DATA_LENGTH:
return parse_dataobj_channel_data_length;
case STK_DATA_OBJECT_TYPE_BUFFER_SIZE:
return parse_dataobj_buffer_size;
case STK_DATA_OBJECT_TYPE_CHANNEL_STATUS:
return parse_dataobj_channel_status;
case STK_DATA_OBJECT_TYPE_CARD_READER_ID:
return parse_dataobj_card_reader_id;
case STK_DATA_OBJECT_TYPE_OTHER_ADDRESS:
return parse_dataobj_other_address;
case STK_DATA_OBJECT_TYPE_UICC_TE_INTERFACE:
return parse_dataobj_uicc_te_interface;
case STK_DATA_OBJECT_TYPE_AID:
return parse_dataobj_aid;
case STK_DATA_OBJECT_TYPE_ACCESS_TECHNOLOGY:
return parse_dataobj_access_technology;
case STK_DATA_OBJECT_TYPE_DISPLAY_PARAMETERS:
return parse_dataobj_display_parameters;
case STK_DATA_OBJECT_TYPE_SERVICE_RECORD:
return parse_dataobj_service_record;
case STK_DATA_OBJECT_TYPE_DEVICE_FILTER:
return parse_dataobj_device_filter;
case STK_DATA_OBJECT_TYPE_SERVICE_SEARCH:
return parse_dataobj_service_search;
case STK_DATA_OBJECT_TYPE_ATTRIBUTE_INFO:
return parse_dataobj_attribute_info;
case STK_DATA_OBJECT_TYPE_SERVICE_AVAILABILITY:
return parse_dataobj_service_availability;
case STK_DATA_OBJECT_TYPE_REMOTE_ENTITY_ADDRESS:
return parse_dataobj_remote_entity_address;
case STK_DATA_OBJECT_TYPE_ESN:
return parse_dataobj_esn;
case STK_DATA_OBJECT_TYPE_NETWORK_ACCESS_NAME:
return parse_dataobj_network_access_name;
case STK_DATA_OBJECT_TYPE_CDMA_SMS_TPDU:
return parse_dataobj_cdma_sms_tpdu;
case STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE:
return parse_dataobj_text_attr;
case STK_DATA_OBJECT_TYPE_PDP_ACTIVATION_PARAMETER:
return parse_dataobj_pdp_act_par;
case STK_DATA_OBJECT_TYPE_ITEM_TEXT_ATTRIBUTE_LIST:
return parse_dataobj_item_text_attribute_list;
case STK_DATA_OBJECT_TYPE_UTRAN_MEASUREMENT_QUALIFIER:
return parse_dataobj_utran_meas_qualifier;
case STK_DATA_OBJECT_TYPE_IMEISV:
return parse_dataobj_imeisv;
case STK_DATA_OBJECT_TYPE_NETWORK_SEARCH_MODE:
return parse_dataobj_network_search_mode;
case STK_DATA_OBJECT_TYPE_BATTERY_STATE:
return parse_dataobj_battery_state;
case STK_DATA_OBJECT_TYPE_BROWSING_STATUS:
return parse_dataobj_browsing_status;
case STK_DATA_OBJECT_TYPE_FRAME_LAYOUT:
return parse_dataobj_frame_layout;
case STK_DATA_OBJECT_TYPE_FRAMES_INFO:
return parse_dataobj_frames_info;
case STK_DATA_OBJECT_TYPE_FRAME_ID:
return parse_dataobj_frame_id;
case STK_DATA_OBJECT_TYPE_MEID:
return parse_dataobj_meid;
case STK_DATA_OBJECT_TYPE_MMS_REFERENCE:
return parse_dataobj_mms_reference;
case STK_DATA_OBJECT_TYPE_MMS_ID:
return parse_dataobj_mms_id;
case STK_DATA_OBJECT_TYPE_MMS_TRANSFER_STATUS:
return parse_dataobj_mms_transfer_status;
case STK_DATA_OBJECT_TYPE_MMS_CONTENT_ID:
return parse_dataobj_mms_content_id;
case STK_DATA_OBJECT_TYPE_MMS_NOTIFICATION:
return parse_dataobj_mms_notification;
case STK_DATA_OBJECT_TYPE_LAST_ENVELOPE:
return parse_dataobj_last_envelope;
case STK_DATA_OBJECT_TYPE_REGISTRY_APPLICATION_DATA:
return parse_dataobj_registry_application_data;
case STK_DATA_OBJECT_TYPE_ACTIVATE_DESCRIPTOR:
return parse_dataobj_activate_descriptor;
case STK_DATA_OBJECT_TYPE_BROADCAST_NETWORK_INFO:
return parse_dataobj_broadcast_network_info;
default:
return NULL;
}
}
static void destroy_stk_item(gpointer pointer)
{
struct stk_item *item = pointer;
l_free(item->text);
l_free(item);
}
static bool parse_item_list(struct comprehension_tlv_iter *iter, void *data)
{
struct l_queue **out = data;
uint16_t tag = STK_DATA_OBJECT_TYPE_ITEM;
struct comprehension_tlv_iter iter_old;
struct stk_item item;
struct l_queue *list = l_queue_new();
unsigned int count = 0;
bool has_empty = false;
do {
comprehension_tlv_iter_copy(iter, &iter_old);
memset(&item, 0, sizeof(item));
count++;
if (!parse_dataobj_item(iter, &item))
continue;
if (item.id == 0) {
has_empty = true;
continue;
}
l_queue_push_tail(list, l_memdup(&item, sizeof(item)));
} while (comprehension_tlv_iter_next(iter) == TRUE &&
comprehension_tlv_iter_get_tag(iter) == tag);
comprehension_tlv_iter_copy(&iter_old, iter);
if (!has_empty || count == 1) {
*out = list;
return true;
}
l_queue_destroy(list, destroy_stk_item);
return false;
}
static bool parse_provisioning_list(struct comprehension_tlv_iter *iter,
void *data)
{
struct l_queue **out = data;
uint16_t tag = STK_DATA_OBJECT_TYPE_PROVISIONING_FILE_REF;
struct comprehension_tlv_iter iter_old;
struct stk_file file;
struct l_queue *list = l_queue_new();
do {
comprehension_tlv_iter_copy(iter, &iter_old);
memset(&file, 0, sizeof(file));
if (!parse_dataobj_provisioning_file_reference(iter, &file))
continue;
l_queue_push_tail(list, l_memdup(&file, sizeof(file)));
} while (comprehension_tlv_iter_next(iter) == TRUE &&
comprehension_tlv_iter_get_tag(iter) == tag);
comprehension_tlv_iter_copy(&iter_old, iter);
*out = list;
return true;
}
static dataobj_handler list_handler_for_type(enum stk_data_object_type type)
{
switch (type) {
case STK_DATA_OBJECT_TYPE_ITEM:
return parse_item_list;
case STK_DATA_OBJECT_TYPE_PROVISIONING_FILE_REF:
return parse_provisioning_list;
default:
return NULL;
}
}
struct dataobj_handler_entry {
enum stk_data_object_type type;
int flags;
void *data;
};
static enum stk_command_parse_result parse_dataobj(
struct comprehension_tlv_iter *iter,
enum stk_data_object_type type, ...)
{
GSList *entries = NULL;
GSList *l;
va_list args;
bool minimum_set = true;
bool parse_error = false;
va_start(args, type);
while (type != STK_DATA_OBJECT_TYPE_INVALID) {
struct dataobj_handler_entry *entry;
entry = g_new0(struct dataobj_handler_entry, 1);
entry->type = type;
entry->flags = va_arg(args, int);
entry->data = va_arg(args, void *);
type = va_arg(args, enum stk_data_object_type);
entries = g_slist_prepend(entries, entry);
}
va_end(args);
entries = g_slist_reverse(entries);
l = entries;
while (comprehension_tlv_iter_next(iter) == TRUE) {
dataobj_handler handler;
struct dataobj_handler_entry *entry;
GSList *l2;
for (l2 = l; l2; l2 = l2->next) {
entry = l2->data;
if (comprehension_tlv_iter_get_tag(iter) == entry->type)
break;
/* Can't skip over mandatory objects */
if (entry->flags & DATAOBJ_FLAG_MANDATORY) {
l2 = NULL;
break;
}
}
if (l2 == NULL) {
if (comprehension_tlv_get_cr(iter) == TRUE)
parse_error = true;
continue;
}
if (entry->flags & DATAOBJ_FLAG_LIST)
handler = list_handler_for_type(entry->type);
else
handler = handler_for_type(entry->type);
if (!handler(iter, entry->data))
parse_error = true;
l = l2->next;
}
for (; l; l = l->next) {
struct dataobj_handler_entry *entry = l->data;
if (entry->flags & DATAOBJ_FLAG_MANDATORY)
minimum_set = false;
}
g_slist_free_full(entries, g_free);
if (!minimum_set)
return STK_PARSE_RESULT_MISSING_VALUE;
if (parse_error)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static void destroy_display_text(struct stk_command *command)
{
l_free(command->display_text.text);
}
static enum stk_command_parse_result parse_display_text(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_display_text *obj = &command->display_text;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_DISPLAY)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_display_text;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_TEXT,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->text,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_IMMEDIATE_RESPONSE, 0,
&obj->immediate_response,
STK_DATA_OBJECT_TYPE_DURATION, 0,
&obj->duration,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->text, obj->icon_id.id);
return status;
}
static void destroy_get_inkey(struct stk_command *command)
{
l_free(command->get_inkey.text);
}
static enum stk_command_parse_result parse_get_inkey(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_get_inkey *obj = &command->get_inkey;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_get_inkey;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_TEXT,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->text,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_DURATION, 0,
&obj->duration,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->text, obj->icon_id.id);
return status;
}
static void destroy_get_input(struct stk_command *command)
{
l_free(command->get_input.text);
l_free(command->get_input.default_text);
}
static enum stk_command_parse_result parse_get_input(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_get_input *obj = &command->get_input;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_get_input;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_TEXT,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->text,
STK_DATA_OBJECT_TYPE_RESPONSE_LENGTH,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->resp_len,
STK_DATA_OBJECT_TYPE_DEFAULT_TEXT, 0,
&obj->default_text,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->text, obj->icon_id.id);
return status;
}
static enum stk_command_parse_result parse_more_time(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static void destroy_play_tone(struct stk_command *command)
{
l_free(command->play_tone.alpha_id);
}
static enum stk_command_parse_result parse_play_tone(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_play_tone *obj = &command->play_tone;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_EARPIECE)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_play_tone;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_TONE, 0,
&obj->tone,
STK_DATA_OBJECT_TYPE_DURATION, 0,
&obj->duration,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static enum stk_command_parse_result parse_poll_interval(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_poll_interval *obj = &command->poll_interval;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_DURATION,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->duration,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_setup_menu(struct stk_command *command)
{
l_free(command->setup_menu.alpha_id);
l_queue_destroy(command->setup_menu.items, destroy_stk_item);
}
static enum stk_command_parse_result parse_setup_menu(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_setup_menu *obj = &command->setup_menu;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_setup_menu;
status = parse_dataobj(iter,
STK_DATA_OBJECT_TYPE_ALPHA_ID,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ITEM,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM |
DATAOBJ_FLAG_LIST, &obj->items,
STK_DATA_OBJECT_TYPE_ITEMS_NEXT_ACTION_INDICATOR, 0,
&obj->next_act,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_ITEM_ICON_ID_LIST, 0,
&obj->item_icon_id_list,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_ITEM_TEXT_ATTRIBUTE_LIST, 0,
&obj->item_text_attr_list,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static void destroy_select_item(struct stk_command *command)
{
l_free(command->select_item.alpha_id);
l_queue_destroy(command->select_item.items, destroy_stk_item);
}
static enum stk_command_parse_result parse_select_item(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_select_item *obj = &command->select_item;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
status = parse_dataobj(iter,
STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ITEM,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM |
DATAOBJ_FLAG_LIST, &obj->items,
STK_DATA_OBJECT_TYPE_ITEMS_NEXT_ACTION_INDICATOR, 0,
&obj->next_act,
STK_DATA_OBJECT_TYPE_ITEM_ID, 0,
&obj->item_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_ITEM_ICON_ID_LIST, 0,
&obj->item_icon_id_list,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_ITEM_TEXT_ATTRIBUTE_LIST, 0,
&obj->item_text_attr_list,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
command->destructor = destroy_select_item;
if (status == STK_PARSE_RESULT_OK && l_queue_isempty(obj->items))
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static void destroy_send_sms(struct stk_command *command)
{
l_free(command->send_sms.alpha_id);
l_free(command->send_sms.cdma_sms.array);
}
static enum stk_command_parse_result parse_send_sms(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_send_sms *obj = &command->send_sms;
enum stk_command_parse_result status;
struct gsm_sms_tpdu gsm_tpdu;
struct stk_address sc_address = { 0, NULL };
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_NETWORK)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
memset(&gsm_tpdu, 0, sizeof(gsm_tpdu));
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ADDRESS, 0,
&sc_address,
STK_DATA_OBJECT_TYPE_GSM_SMS_TPDU, 0,
&gsm_tpdu,
STK_DATA_OBJECT_TYPE_CDMA_SMS_TPDU, 0,
&obj->cdma_sms,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
command->destructor = destroy_send_sms;
if (status != STK_PARSE_RESULT_OK)
goto out;
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
if (status != STK_PARSE_RESULT_OK)
goto out;
if (gsm_tpdu.len == 0 && obj->cdma_sms.len == 0) {
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
goto out;
}
if (gsm_tpdu.len > 0 && obj->cdma_sms.len > 0) {
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
goto out;
}
/* We don't process CDMA pdus for now */
if (obj->cdma_sms.len > 0)
goto out;
/* packing is needed */
if (command->qualifier & 0x01) {
if (!sms_decode_unpacked_stk_pdu(gsm_tpdu.tpdu, gsm_tpdu.len,
&obj->gsm_sms)) {
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
goto out;
}
goto set_addr;
}
if (sms_decode(gsm_tpdu.tpdu, gsm_tpdu.len, TRUE,
gsm_tpdu.len, &obj->gsm_sms) == FALSE) {
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
goto out;
}
if (obj->gsm_sms.type != SMS_TYPE_SUBMIT &&
obj->gsm_sms.type != SMS_TYPE_COMMAND) {
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
goto out;
}
set_addr:
if (sc_address.number == NULL)
goto out;
if (strlen(sc_address.number) > 20) {
status = STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
goto out;
}
strcpy(obj->gsm_sms.sc_addr.address, sc_address.number);
obj->gsm_sms.sc_addr.numbering_plan = sc_address.ton_npi & 15;
obj->gsm_sms.sc_addr.number_type = (sc_address.ton_npi >> 4) & 7;
out:
l_free(sc_address.number);
return status;
}
static void destroy_send_ss(struct stk_command *command)
{
l_free(command->send_ss.alpha_id);
l_free(command->send_ss.ss.ss);
}
static enum stk_command_parse_result parse_send_ss(struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_send_ss *obj = &command->send_ss;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_NETWORK)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_send_ss;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_SS_STRING,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->ss,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_send_ussd(struct stk_command *command)
{
l_free(command->send_ussd.alpha_id);
}
static enum stk_command_parse_result parse_send_ussd(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_send_ussd *obj = &command->send_ussd;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_NETWORK)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_send_ussd;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_USSD_STRING,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->ussd_string,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_setup_call(struct stk_command *command)
{
l_free(command->setup_call.alpha_id_usr_cfm);
l_free(command->setup_call.addr.number);
l_free(command->setup_call.alpha_id_call_setup);
}
static enum stk_command_parse_result parse_setup_call(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_setup_call *obj = &command->setup_call;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_NETWORK)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_setup_call;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id_usr_cfm,
STK_DATA_OBJECT_TYPE_ADDRESS,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->addr,
STK_DATA_OBJECT_TYPE_CCP, 0,
&obj->ccp,
STK_DATA_OBJECT_TYPE_SUBADDRESS, 0,
&obj->subaddr,
STK_DATA_OBJECT_TYPE_DURATION, 0,
&obj->duration,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id_usr_cfm,
STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id_call_setup,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id_call_setup,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr_usr_cfm,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr_call_setup,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id_usr_cfm, obj->icon_id_usr_cfm.id);
CHECK_TEXT_AND_ICON(obj->alpha_id_call_setup,
obj->icon_id_call_setup.id);
return status;
}
static void destroy_refresh(struct stk_command *command)
{
l_queue_destroy(command->refresh.file_list, l_free);
l_free(command->refresh.alpha_id);
}
static enum stk_command_parse_result parse_refresh(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_refresh *obj = &command->refresh;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_refresh;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_FILE_LIST, 0,
&obj->file_list,
STK_DATA_OBJECT_TYPE_AID, 0,
&obj->aid,
STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static enum stk_command_parse_result parse_polling_off(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static enum stk_command_parse_result parse_provide_local_info(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static enum stk_command_parse_result parse_setup_event_list(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_setup_event_list *obj = &command->setup_event_list;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_EVENT_LIST,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->event_list,
STK_DATA_OBJECT_TYPE_INVALID);
}
static enum stk_command_parse_result parse_perform_card_apdu(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_perform_card_apdu *obj = &command->perform_card_apdu;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CARD_READER_0) ||
(command->dst > STK_DEVICE_IDENTITY_TYPE_CARD_READER_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_C_APDU,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->c_apdu,
STK_DATA_OBJECT_TYPE_INVALID);
}
static enum stk_command_parse_result parse_power_off_card(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CARD_READER_0) ||
(command->dst > STK_DEVICE_IDENTITY_TYPE_CARD_READER_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static enum stk_command_parse_result parse_power_on_card(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CARD_READER_0) ||
(command->dst > STK_DEVICE_IDENTITY_TYPE_CARD_READER_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static enum stk_command_parse_result parse_get_reader_status(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
switch (command->qualifier) {
case STK_QUALIFIER_TYPE_CARD_READER_STATUS:
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
break;
case STK_QUALIFIER_TYPE_CARD_READER_ID:
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CARD_READER_0) ||
(command->dst >
STK_DEVICE_IDENTITY_TYPE_CARD_READER_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
break;
default:
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
}
return STK_PARSE_RESULT_OK;
}
static enum stk_command_parse_result parse_timer_mgmt(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_timer_mgmt *obj = &command->timer_mgmt;
enum stk_data_object_flag value_flags = 0;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->qualifier & 3) == 0) /* Start a timer */
value_flags = DATAOBJ_FLAG_MANDATORY;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_TIMER_ID,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->timer_id,
STK_DATA_OBJECT_TYPE_TIMER_VALUE, value_flags,
&obj->timer_value,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_setup_idle_mode_text(struct stk_command *command)
{
l_free(command->setup_idle_mode_text.text);
}
static enum stk_command_parse_result parse_setup_idle_mode_text(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_setup_idle_mode_text *obj =
&command->setup_idle_mode_text;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_setup_idle_mode_text;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_TEXT,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->text,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->text, obj->icon_id.id);
return status;
}
static void destroy_run_at_command(struct stk_command *command)
{
l_free(command->run_at_command.alpha_id);
l_free(command->run_at_command.at_command);
}
static enum stk_command_parse_result parse_run_at_command(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_run_at_command *obj = &command->run_at_command;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_run_at_command;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_AT_COMMAND,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->at_command,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static void destroy_send_dtmf(struct stk_command *command)
{
l_free(command->send_dtmf.alpha_id);
l_free(command->send_dtmf.dtmf);
}
static enum stk_command_parse_result parse_send_dtmf(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_send_dtmf *obj = &command->send_dtmf;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_NETWORK)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_send_dtmf;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_DTMF_STRING,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->dtmf,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static enum stk_command_parse_result parse_language_notification(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_language_notification *obj =
&command->language_notification;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_LANGUAGE, 0,
&obj->language,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_launch_browser(struct stk_command *command)
{
l_free(command->launch_browser.url);
l_free(command->launch_browser.bearer.array);
l_queue_destroy(command->launch_browser.prov_file_refs, l_free);
l_free(command->launch_browser.text_gateway_proxy_id);
l_free(command->launch_browser.alpha_id);
l_free(command->launch_browser.network_name.array);
l_free(command->launch_browser.text_usr);
l_free(command->launch_browser.text_passwd);
}
static enum stk_command_parse_result parse_launch_browser(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_launch_browser *obj = &command->launch_browser;
if (command->qualifier > 3 || command->qualifier == 1)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_launch_browser;
return parse_dataobj(iter,
STK_DATA_OBJECT_TYPE_BROWSER_ID, 0,
&obj->browser_id,
STK_DATA_OBJECT_TYPE_URL,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->url,
STK_DATA_OBJECT_TYPE_BEARER, 0,
&obj->bearer,
STK_DATA_OBJECT_TYPE_PROVISIONING_FILE_REF,
DATAOBJ_FLAG_LIST,
&obj->prov_file_refs,
STK_DATA_OBJECT_TYPE_TEXT, 0,
&obj->text_gateway_proxy_id,
STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_NETWORK_ACCESS_NAME, 0,
&obj->network_name,
STK_DATA_OBJECT_TYPE_TEXT, 0,
&obj->text_usr,
STK_DATA_OBJECT_TYPE_TEXT, 0,
&obj->text_passwd,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_open_channel(struct stk_command *command)
{
l_free(command->open_channel.alpha_id);
l_free(command->open_channel.apn);
l_free(command->open_channel.text_usr);
l_free(command->open_channel.text_passwd);
}
static enum stk_command_parse_result parse_open_channel(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_open_channel *obj = &command->open_channel;
enum stk_command_parse_result status;
if (command->qualifier >= 0x08)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_open_channel;
/*
* parse the Open Channel data objects related to packet data service
* bearer
*/
status = parse_dataobj(iter,
STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_BEARER_DESCRIPTION,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->bearer_desc,
STK_DATA_OBJECT_TYPE_BUFFER_SIZE,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->buf_size,
STK_DATA_OBJECT_TYPE_NETWORK_ACCESS_NAME, 0,
&obj->apn,
STK_DATA_OBJECT_TYPE_OTHER_ADDRESS, 0,
&obj->local_addr,
STK_DATA_OBJECT_TYPE_TEXT, 0,
&obj->text_usr,
STK_DATA_OBJECT_TYPE_TEXT, 0,
&obj->text_passwd,
STK_DATA_OBJECT_TYPE_UICC_TE_INTERFACE, 0,
&obj->uti,
STK_DATA_OBJECT_TYPE_OTHER_ADDRESS, 0,
&obj->data_dest_addr,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static void destroy_close_channel(struct stk_command *command)
{
l_free(command->close_channel.alpha_id);
}
static enum stk_command_parse_result parse_close_channel(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_close_channel *obj = &command->close_channel;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CHANNEL_1) ||
(command->dst > STK_DEVICE_IDENTITY_TYPE_CHANNEL_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_close_channel;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static void destroy_receive_data(struct stk_command *command)
{
l_free(command->receive_data.alpha_id);
}
static enum stk_command_parse_result parse_receive_data(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_receive_data *obj = &command->receive_data;
enum stk_command_parse_result status;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CHANNEL_1) ||
(command->dst > STK_DEVICE_IDENTITY_TYPE_CHANNEL_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_receive_data;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_CHANNEL_DATA_LENGTH,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->data_len,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static void destroy_send_data(struct stk_command *command)
{
l_free(command->send_data.alpha_id);
l_free(command->send_data.data.array);
}
static enum stk_command_parse_result parse_send_data(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_send_data *obj = &command->send_data;
enum stk_command_parse_result status;
if (command->qualifier > STK_SEND_DATA_IMMEDIATELY)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if ((command->dst < STK_DEVICE_IDENTITY_TYPE_CHANNEL_1) ||
(command->dst > STK_DEVICE_IDENTITY_TYPE_CHANNEL_7))
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_send_data;
status = parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_CHANNEL_DATA,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->data,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
CHECK_TEXT_AND_ICON(obj->alpha_id, obj->icon_id.id);
return status;
}
static enum stk_command_parse_result parse_get_channel_status(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
return STK_PARSE_RESULT_OK;
}
static void destroy_service_search(struct stk_command *command)
{
l_free(command->service_search.alpha_id);
l_free(command->service_search.serv_search.ser_search);
l_free(command->service_search.dev_filter.dev_filter);
}
static enum stk_command_parse_result parse_service_search(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_service_search *obj = &command->service_search;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_service_search;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_SERVICE_SEARCH,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->serv_search,
STK_DATA_OBJECT_TYPE_DEVICE_FILTER, 0,
&obj->dev_filter,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destroy_get_service_info(struct stk_command *command)
{
l_free(command->get_service_info.alpha_id);
l_free(command->get_service_info.attr_info.attr_info);
}
static enum stk_command_parse_result parse_get_service_info(
struct stk_command *command,
struct comprehension_tlv_iter *iter)
{
struct stk_command_get_service_info *obj = &command->get_service_info;
if (command->src != STK_DEVICE_IDENTITY_TYPE_UICC)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
if (command->dst != STK_DEVICE_IDENTITY_TYPE_TERMINAL)
return STK_PARSE_RESULT_DATA_NOT_UNDERSTOOD;
command->destructor = destroy_get_service_info;
return parse_dataobj(iter, STK_DATA_OBJECT_TYPE_ALPHA_ID, 0,
&obj->alpha_id,
STK_DATA_OBJECT_TYPE_ICON_ID, 0,
&obj->icon_id,
STK_DATA_OBJECT_TYPE_ATTRIBUTE_INFO,
DATAOBJ_FLAG_MANDATORY | DATAOBJ_FLAG_MINIMUM,
&obj->attr_info,
STK_DATA_OBJECT_TYPE_TEXT_ATTRIBUTE, 0,
&obj->text_attr,
STK_DATA_OBJECT_TYPE_FRAME_ID, 0,
&obj->frame_id,
STK_DATA_OBJECT_TYPE_INVALID);
}
static void destr