stkutil: Add the Provide Local Info response builder

This commit is contained in:
Andrzej Zaborowski 2010-05-27 06:59:44 +02:00 committed by Denis Kenzior
parent 280d8d4283
commit 8868becca1
2 changed files with 500 additions and 0 deletions

View File

@ -3165,6 +3165,17 @@ static gboolean stk_tlv_builder_append_byte(struct stk_tlv_builder *iter,
return TRUE;
}
static gboolean stk_tlv_builder_append_short(struct stk_tlv_builder *iter,
unsigned short num)
{
if (iter->len + 2 > iter->max_len)
return FALSE;
iter->value[iter->len++] = num >> 8;
iter->value[iter->len++] = num & 0xff;
return TRUE;
}
static gboolean stk_tlv_builder_append_gsm_packed(struct stk_tlv_builder *iter,
const char *text)
{
@ -3383,6 +3394,118 @@ static gboolean build_dataobj_text(struct stk_tlv_builder *tlv,
return stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.19 */
static gboolean build_dataobj_location_info(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct stk_location_info *li = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_LOCATION_INFO;
guint8 mccmnc[3];
if (li->mcc[0] == 0)
/*
* "If no location information is available for an access
* technology, the respective data object shall have
* length zero."
*/
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_close_container(tlv);
sim_encode_mcc_mnc(mccmnc, li->mcc, li->mnc);
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_bytes(tlv, mccmnc, 3) &&
stk_tlv_builder_append_short(tlv, li->lac_tac) &&
(li->has_ci == FALSE ||
stk_tlv_builder_append_short(tlv, li->ci)) &&
(li->has_ext_ci == FALSE ||
stk_tlv_builder_append_short(tlv, li->ext_ci)) &&
(li->has_eutran_ci == FALSE ||
(stk_tlv_builder_append_short(tlv, li->eutran_ci >> 12) &&
stk_tlv_builder_append_short(tlv,
(li->eutran_ci << 4) | 0xf))) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.20
*
* See format note in parse_dataobj_imei.
*/
static gboolean build_dataobj_imei(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
char byte0[3];
const char *imei = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_IMEI;
unsigned char value[8];
if (imei == NULL)
return TRUE;
if (strlen(imei) != 15)
return FALSE;
byte0[0] = '*';
byte0[1] = imei[0];
byte0[2] = '\0';
sim_encode_bcd_number(byte0, value);
sim_encode_bcd_number(imei + 1, value + 1);
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_bytes(tlv, value, 8) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.22 */
static gboolean build_dataobj_network_measurement_results(
struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct stk_common_byte_array *nmr = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_NETWORK_MEASUREMENT_RESULTS;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
(nmr->len == 0 ||
stk_tlv_builder_append_bytes(tlv, nmr->array, nmr->len)) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in 3GPP 31.111 Section 8.29 */
static gboolean build_dataobj_bcch_channel_list(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct stk_bcch_ch_list *list = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_BCCH_CHANNEL_LIST;
int i, bytes, pos, shift;
unsigned char value;
/* To distinguish between no BCCH Channel List data object and
* an empty object in a sequence of empty and non-empty objects,
* .channels must be non-NULL in objects in sequences. */
if (list->channels == NULL)
return TRUE;
if (stk_tlv_builder_open_container(tlv, cr, tag, TRUE) != TRUE)
return FALSE;
bytes = (list->length * 10 + 7) / 8;
for (i = 0; i < bytes; i++) {
pos = (i * 8 + 7) / 10;
shift = pos * 10 + 10 - i * 8 - 8;
value = 0;
if (pos < list->length)
value |= list->channels[pos] >> shift;
if (shift > 2)
value |= list->channels[pos - 1] << (10 - shift);
if (stk_tlv_builder_append_byte(tlv, value) != TRUE)
return FALSE;
}
return stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.30 */
static gboolean build_dataobj_cc_requested_action(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
@ -3397,6 +3520,195 @@ static gboolean build_dataobj_cc_requested_action(struct stk_tlv_builder *tlv,
stk_tlv_builder_close_container(tlv));
}
/* Described in TS 102.223 Section 8.39 */
static gboolean build_dataobj_datetime_timezone(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct sms_scts *scts = data;
struct sms_scts timestamp;
unsigned char value[7];
int offset = 0;
unsigned char tag = STK_DATA_OBJECT_TYPE_DATETIME_TIMEZONE;
if (scts->month == 0 && scts->day == 0)
return TRUE;
/* Time zone information is optional */
if (scts->timezone == (gint8) 0xff) {
memcpy(&timestamp, scts, sizeof(timestamp));
timestamp.timezone = 0;
if (sms_encode_scts(&timestamp, value, &offset) != TRUE)
return FALSE;
value[6] = 0xff;
} else
if (sms_encode_scts(scts, value, &offset) != TRUE)
return FALSE;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_bytes(tlv, value, 7) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.45 */
static gboolean build_dataobj_language(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
unsigned char tag = STK_DATA_OBJECT_TYPE_LANGUAGE;
if (data == NULL)
return TRUE;
/*
* Coded as two GSM 7-bit characters with eighth bit clear. Since
* ISO 639-2 codes use only english alphabet letters, no conversion
* from UTF-8 to GSM is needed.
*/
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_bytes(tlv, data, 2) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in 3GPP TS 31.111 Section 8.46 */
static gboolean build_dataobj_timing_advance(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct stk_timing_advance *tadv = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_TIMING_ADVANCE;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_byte(tlv, tadv->status) &&
stk_tlv_builder_append_byte(tlv, tadv->advance) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.61 */
static gboolean build_dataobj_access_technologies(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct stk_access_technologies *techs = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_ACCESS_TECHNOLOGY;
int i;
if (stk_tlv_builder_open_container(tlv, cr, tag, FALSE) != TRUE)
return FALSE;
for (i = 0; i < techs->length; i++)
if (stk_tlv_builder_append_byte(tlv, techs->techs[i]) != TRUE)
return FALSE;
return stk_tlv_builder_close_container(tlv);
}
/* Shortcut for a single Access Technology */
static gboolean build_dataobj_access_technology(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
return build_dataobj_access_technologies(tlv,
&(const struct stk_access_technologies) {
.techs = data, .length = 1 }, cr);
}
/* Described in TS 102.223 Section 8.69 */
static gboolean build_dataobj_esn(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const guint32 *esn = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_ESN;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_short(tlv, *esn >> 16) &&
stk_tlv_builder_append_short(tlv, *esn >> 0) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.74
*
* See format note in parse_dataobj_imeisv.
*/
static gboolean build_dataobj_imeisv(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
char byte0[3];
const char *imeisv = data;
unsigned char value[9];
unsigned char tag = STK_DATA_OBJECT_TYPE_IMEISV;
if (imeisv == NULL)
return TRUE;
if (strlen(imeisv) != 16)
return FALSE;
byte0[0] = '3';
byte0[1] = imeisv[0];
byte0[2] = '\0';
sim_encode_bcd_number(byte0, value);
sim_encode_bcd_number(imeisv + 1, value + 1);
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_bytes(tlv, value, 9) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.75 */
static gboolean build_dataobj_network_search_mode(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const enum stk_network_search_mode *mode = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_NETWORK_SEARCH_MODE;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_byte(tlv, *mode) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.76 */
static gboolean build_dataobj_battery_state(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const enum stk_battery_state *state = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_BATTERY_STATE;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_byte(tlv, *state) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.81 */
static gboolean build_dataobj_meid(struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const char *meid = data;
unsigned char value[8];
unsigned char tag = STK_DATA_OBJECT_TYPE_MEID;
if (meid == NULL)
return TRUE;
if (strlen(meid) != 16)
return FALSE;
sim_encode_bcd_number(meid, value);
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_bytes(tlv, value, 8) &&
stk_tlv_builder_close_container(tlv);
}
/* Described in TS 102.223 Section 8.90 */
static gboolean build_dataobj_broadcast_network_information(
struct stk_tlv_builder *tlv,
const void *data, gboolean cr)
{
const struct stk_broadcast_network_information *bni = data;
unsigned char tag = STK_DATA_OBJECT_TYPE_BROADCAST_NETWORK_INFO;
return stk_tlv_builder_open_container(tlv, cr, tag, FALSE) &&
stk_tlv_builder_append_byte(tlv, bni->tech) &&
stk_tlv_builder_append_bytes(tlv, bni->loc_info, bni->len) &&
stk_tlv_builder_close_container(tlv);
}
static gboolean build_dataobj(struct stk_tlv_builder *tlv,
dataobj_writer builder_func, ...)
{
@ -3438,6 +3750,138 @@ static gboolean build_set_up_call(struct stk_tlv_builder *builder,
NULL);
}
static gboolean build_local_info(struct stk_tlv_builder *builder,
const struct stk_response *response)
{
const struct stk_response_local_info *info =
&response->provide_local_info;
int i;
switch (response->qualifier) {
case 0x00: /* Location Information according to current NAA */
return build_dataobj(builder,
build_dataobj_location_info,
DATAOBJ_FLAG_CR, &info->location,
NULL);
case 0x01: /* IMEI of the terminal */
return build_dataobj(builder,
build_dataobj_imei,
DATAOBJ_FLAG_CR, info->imei,
NULL);
case 0x02: /* Network Measurement results according to current NAA */
return build_dataobj(builder,
build_dataobj_network_measurement_results,
DATAOBJ_FLAG_CR, &info->nmr.nmr,
build_dataobj_bcch_channel_list,
DATAOBJ_FLAG_CR, &info->nmr.bcch_ch_list,
NULL);
case 0x03: /* Date, time and time zone */
return build_dataobj(builder,
build_dataobj_datetime_timezone,
DATAOBJ_FLAG_CR, &info->datetime,
NULL);
case 0x04: /* Language setting */
return build_dataobj(builder,
build_dataobj_language,
DATAOBJ_FLAG_CR, info->language,
NULL);
case 0x05: /* Timing Advance */
return build_dataobj(builder,
build_dataobj_timing_advance,
DATAOBJ_FLAG_CR, &info->tadv,
NULL);
case 0x06: /* Access Technology (single access technology) */
return build_dataobj(builder,
build_dataobj_access_technology,
0, &info->access_technology,
NULL);
case 0x07: /* ESN of the terminal */
return build_dataobj(builder,
build_dataobj_esn,
DATAOBJ_FLAG_CR, &info->esn,
NULL);
case 0x08: /* IMEISV of the terminal */
return build_dataobj(builder,
build_dataobj_imeisv,
DATAOBJ_FLAG_CR, info->imeisv,
NULL);
case 0x09: /* Search Mode */
return build_dataobj(builder,
build_dataobj_network_search_mode,
0, &info->search_mode,
NULL);
case 0x0a: /* Charge State of the Battery */
return build_dataobj(builder,
build_dataobj_battery_state,
DATAOBJ_FLAG_CR, &info->battery_charge,
NULL);
case 0x0b: /* MEID of the terminal */
return build_dataobj(builder,
build_dataobj_meid,
0, info->meid,
NULL);
case 0x0d: /* Broadcast Network Information according to current tech */
return build_dataobj(builder,
build_dataobj_broadcast_network_information,
0, &info->broadcast_network_info,
NULL);
case 0x0e: /* Multiple Access Technologies */
return build_dataobj(builder,
build_dataobj_access_technologies,
0, &info->access_technologies,
NULL);
case 0x0f: /* Location Information for multiple NAAs */
if (build_dataobj(builder,
build_dataobj_access_technologies,
0, &info->location_infos.access_techs,
NULL) != TRUE)
return FALSE;
for (i = 0; i < info->location_infos.access_techs.length; i++)
if (build_dataobj(builder,
build_dataobj_location_info,
0, &info->location_infos.locations[i],
NULL) != TRUE)
return FALSE;
return TRUE;
case 0x10: /* Network Measurement results for multiple NAAs */
if (build_dataobj(builder,
build_dataobj_access_technologies,
0, &info->nmrs.access_techs,
NULL) != TRUE)
return FALSE;
for (i = 0; i < info->nmrs.access_techs.length; i++)
if (build_dataobj(builder,
build_dataobj_network_measurement_results,
0, &info->nmrs.nmrs[i].nmr,
build_dataobj_bcch_channel_list,
0, &info->nmrs.nmrs[i].bcch_ch_list,
NULL) != TRUE)
return FALSE;
return TRUE;
}
return FALSE;
}
unsigned int stk_pdu_from_response(const struct stk_response *response,
unsigned char *pdu, unsigned int size)
{
@ -3534,6 +3978,9 @@ unsigned int stk_pdu_from_response(const struct stk_response *response,
break;
case STK_COMMAND_TYPE_POLLING_OFF:
break;
case STK_COMMAND_TYPE_PROVIDE_LOCAL_INFO:
ok = build_local_info(&builder, response);
break;
default:
return 0;
};

View File

@ -110,6 +110,7 @@ enum stk_data_object_type {
STK_DATA_OBJECT_TYPE_CAUSE = 0x1A,
STK_DATA_OBJECT_TYPE_LOCATION_STATUS = 0x1B,
STK_DATA_OBJECT_TYPE_TRANSACTION_ID = 0x1C,
STK_DATA_OBJECT_TYPE_BCCH_CHANNEL_LIST = 0x1D,
STK_DATA_OBJECT_TYPE_ICON_ID = 0x1E,
STK_DATA_OBJECT_TYPE_ITEM_ICON_ID_LIST = 0x1F,
STK_DATA_OBJECT_TYPE_CARD_READER_STATUS = 0x20,
@ -544,6 +545,8 @@ struct stk_location_info {
unsigned short ci;
ofono_bool_t has_ext_ci;
unsigned short ext_ci;
ofono_bool_t has_eutran_ci;
guint32 eutran_ci;
};
/*
@ -1077,6 +1080,55 @@ struct stk_response_set_up_call {
} modified_result;
};
struct stk_response_local_info {
union {
struct stk_location_info location;
const char *imei;
struct stk_network_measurement_results {
struct stk_common_byte_array nmr;
struct stk_bcch_ch_list {
const short *channels;
int length;
} bcch_ch_list;
} nmr;
struct sms_scts datetime;
const char *language;
enum stk_battery_state battery_charge;
enum stk_access_technology_type access_technology;
struct stk_timing_advance {
enum {
STK_TIMING_ADVANCE_ME_IDLE = 0x00,
STK_TIMING_ADVANCE_ME_NOT_IDLE = 0x01,
} status;
/* Contains bit periods number according to 3GPP TS
* 44.118 Section 9.3.106 / 3GPP TS 44.018 Section
* 10.5.2.40.1, not microseconds */
int advance;
} tadv;
/* Bits[31:24]: manufacturer, bits[23:0]: serial number */
guint32 esn;
const char *imeisv;
enum stk_network_search_mode {
STK_NETWORK_SEARCH_MODE_MANUAL = 0x00,
STK_NETWORK_SEARCH_MODE_AUTOMATIC = 0x01,
} search_mode;
const char *meid;
struct stk_broadcast_network_information broadcast_network_info;
struct stk_access_technologies {
const enum stk_access_technology_type *techs;
int length;
} access_technologies;
struct {
struct stk_access_technologies access_techs;
struct stk_location_info *locations;
} location_infos;
struct {
struct stk_access_technologies access_techs;
struct stk_network_measurement_results *nmrs;
} nmrs;
};
};
struct stk_response {
unsigned char number;
unsigned char type;
@ -1097,6 +1149,7 @@ struct stk_response {
struct stk_response_generic send_sms;
struct stk_response_set_up_call set_up_call;
struct stk_response_generic polling_off;
struct stk_response_local_info provide_local_info;
};
void (*destructor)(struct stk_response *response);