3
* oFono - Open Source Telephony
5
* Copyright (C) 2011 ST-Ericsson AB.
6
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2 as
10
* published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35
#include <gisi/message.h>
36
#include <gisi/client.h>
37
#include <gisi/iter.h>
39
#include <ofono/log.h>
40
#include <ofono/modem.h>
41
#include <ofono/sim.h>
48
#include "uicc-util.h"
51
/* File info parameters */
52
#define FCP_TEMPLATE 0x62
53
#define FCP_FILE_SIZE 0x80
54
#define FCP_FILE_DESC 0x82
55
#define FCP_FILE_ID 0x83
56
#define FCP_FILE_LIFECYCLE 0x8A
57
#define FCP_FILE_SECURITY_ARR 0x8B
58
#define FCP_FILE_SECURITY_COMPACT 0x8C
59
#define FCP_FILE_SECURITY_EXPANDED 0xAB
60
#define FCP_PIN_STATUS 0xC6
61
#define SIM_EFARR_FILEID 0x6f06
62
#define MAX_SIM_APPS 10
63
#define MAX_IMSI_LENGTH 15
66
UICC_FLAG_APP_STARTED = 1 << 0,
67
UICC_FLAG_PIN_STATE_RECEIVED = 1 << 1,
68
UICC_FLAG_PASSWD_REQUIRED = 1 << 2,
71
static GHashTable *g_modems;
82
static const struct file_info static_file_info[] = {
83
{ SIM_EFSPN_FILEID, 17, 0, 0, { 0x0e, 0xff, 0xee }, 1 },
84
{ SIM_EF_ICCID_FILEID, 10, 0, 10, { 0x0f, 0xff, 0xee }, 1 },
85
{ SIM_EFPL_FILEID, 1, 0, 1, { 0x0f, 0xff, 0xff }, 1 },
86
{ SIM_EFLI_FILEID, 1, 0, 1, { 0x0f, 0xff, 0xff }, 1 },
87
{ SIM_EFMSISDN_FILEID, 28, 1, 28, { 0x01, 0xff, 0xee }, 1 },
88
{ SIM_EFAD_FILEID, 20, 0, 20, { 0x0e, 0xff, 0xee }, 1 },
89
{ SIM_EFPHASE_FILEID, 1, 0, 1, { 0x0e, 0xff, 0xee }, 1 },
90
{ SIM_EFPNN_FILEID, 4 * 18, 1, 18, { 0x0e, 0xff, 0xee }, 1 },
91
{ SIM_EFOPL_FILEID, 4 * 24, 1, 24, { 0x0e, 0xff, 0xee }, 1 },
92
{ SIM_EFMBI_FILEID, 5, 1, 5, { 0x0e, 0xff, 0xee }, 1 },
93
{ SIM_EFMWIS_FILEID, 6, 1, 6, { 0x01, 0xff, 0xee }, 1 },
94
{ SIM_EFSPDI_FILEID, 64, 0, 64, { 0x0e, 0xff, 0xee }, 1 },
95
{ SIM_EFECC_FILEID, 5 * 3, 0, 3, { 0x0e, 0xff, 0xee }, 1 },
96
{ SIM_EFCBMIR_FILEID, 8 * 4, 0, 4, { 0x01, 0xff, 0xee }, 1 },
97
{ SIM_EFCBMI_FILEID, 8 * 2, 0, 2, { 0x01, 0xff, 0xee }, 1 },
98
{ SIM_EFCBMID_FILEID, 8 * 2, 0, 2, { 0x01, 0xff, 0x11 }, 1 },
99
{ SIM_EFSMSP_FILEID, 56, 1, 56, { 0x01, 0xff, 0xee }, 1 },
100
{ SIM_EFIMSI_FILEID, 9, 0, 9, { 0x0e, 0xff, 0xee }, 1 },
103
static gboolean check_resp(const GIsiMessage *msg, uint8_t msgid, uint8_t service)
108
if (g_isi_msg_error(msg) < 0) {
109
DBG("Error: %s", g_isi_msg_strerror(msg));
113
if (g_isi_msg_id(msg) != msgid) {
114
DBG("Unexpected msg: %s",
115
sim_message_id_name(g_isi_msg_id(msg)));
119
if (!g_isi_msg_data_get_byte(msg, 1, &cause) ||
120
cause != UICC_STATUS_OK) {
121
DBG("Request failed: %s", uicc_status_name(cause));
125
if (!g_isi_msg_data_get_byte(msg, 0, &type) || type != service) {
126
DBG("Unexpected service: 0x%02X (0x%02X)", type, service);
132
struct uicc_file_info_cb_data {
136
struct ofono_sim *sim;
139
static gboolean decode_uicc_usim_type(GIsiSubBlockIter *iter, uint16_t *length,
141
uint16_t *record_length,
142
uint8_t *records, uint8_t *structure)
149
uint8_t item_len = 0;
151
if (!g_isi_sb_iter_get_byte(iter, &fcp, 8))
154
if (fcp != FCP_TEMPLATE)
157
if (!g_isi_sb_iter_get_byte(iter, &fcp_len, 9))
160
for (read = 0; read < fcp_len; read += item_len + 2) {
164
if (!g_isi_sb_iter_get_byte(iter, &id, read + 10))
167
if (!g_isi_sb_iter_get_byte(iter, &item_len, read + 11))
176
if (!g_isi_sb_iter_get_word(iter, length, read + 10 + 2))
186
if (!g_isi_sb_iter_get_word(iter, file_id, read + 10 + 2))
196
if (!g_isi_sb_iter_get_byte(iter, &desc, read + 10 + 2))
199
if (!g_isi_sb_iter_get_byte(iter, &coding, read + 10 + 3))
205
if (!g_isi_sb_iter_get_word(iter, record_length,
209
if (!g_isi_sb_iter_get_byte(iter, records, read + 10 + 6))
215
* Not implemented, using static access rules
216
* as these are used only for cacheing See
217
* ETSI TS 102 221, ch 11.1.1.4.7 and Annexes
220
case FCP_FILE_SECURITY_ARR:
221
case FCP_FILE_SECURITY_COMPACT:
222
case FCP_FILE_SECURITY_EXPANDED:
223
case FCP_FILE_LIFECYCLE:
225
DBG("FCP id %02X not supported", id);
231
*structure = OFONO_SIM_FILE_STRUCTURE_TRANSPARENT;
232
else if ((desc & 7) == 2)
233
*structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
234
else if ((desc & 7) == 6)
235
*structure = OFONO_SIM_FILE_STRUCTURE_CYCLIC;
240
static void uicc_file_info_resp_cb(const GIsiMessage *msg, void *opaque)
242
struct uicc_file_info_cb_data *cbd = opaque;
243
struct uicc_sim_data *sd = ofono_sim_get_data(cbd->sim);
244
struct file_info const *info = cbd->user;
245
ofono_sim_file_info_cb_t cb = cbd->cb;
247
GIsiSubBlockIter iter;
250
uint16_t record_length = 0;
251
uint8_t structure = 0xFF;
253
uint16_t file_id = 0;
254
uint8_t access[3] = {0, 0, 0};
255
uint8_t item_len = 0;
257
uint8_t message_id = 0;
258
uint8_t service_type = 0;
261
uint8_t num_subblocks = 0;
262
uint8_t file_status = 1;
264
message_id = g_isi_msg_id(msg);
266
DBG("uicc_file_info_resp_cb: msg_id=%d, msg len=%zu", message_id,
267
g_isi_msg_data_len(msg));
269
if (message_id != UICC_APPL_CMD_RESP)
272
if (!g_isi_msg_data_get_byte(msg, 0, &service_type) ||
273
!g_isi_msg_data_get_byte(msg, 1, &status) ||
274
!g_isi_msg_data_get_byte(msg, 2, &details) ||
275
!g_isi_msg_data_get_byte(msg, 5, &num_subblocks))
278
DBG("%s, service %s, status %s, details %s, nm_sb %d",
279
uicc_message_id_name(message_id),
280
uicc_service_type_name(service_type),
281
uicc_status_name(status), uicc_details_name(details),
285
access[0] = info->access[0];
286
access[1] = info->access[1];
287
access[2] = info->access[2];
288
file_status = info->file_status;
291
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_subblocks);
292
g_isi_sb_iter_is_valid(&iter);
293
g_isi_sb_iter_next(&iter)) {
295
uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
297
DBG("Subblock %s", uicc_subblock_name(sb_id));
299
if (sb_id != UICC_SB_FCI)
302
DBG("Decoding UICC_SB_FCI");
304
switch (sd->app_type) {
305
case UICC_APPL_TYPE_UICC_USIM:
306
DBG("UICC_APPL_TYPE_UICC_USIM");
308
if (!decode_uicc_usim_type(&iter, &length, &file_id,
316
case UICC_APPL_TYPE_ICC_SIM:
317
DBG("UICC_APPL_TYPE_ICC_SIM");
319
if (!g_isi_sb_iter_get_word(&iter, &length, 10))
322
if (!g_isi_sb_iter_get_word(&iter, &file_id, 12))
325
if (!g_isi_sb_iter_get_byte(&iter, &access[0], 16))
328
if (!g_isi_sb_iter_get_byte(&iter, &access[0], 17))
331
if (!g_isi_sb_iter_get_byte(&iter, &access[0], 18))
334
if (!g_isi_sb_iter_get_byte(&iter, &item_len, 20))
337
if (!g_isi_sb_iter_get_byte(&iter, &structure, 21))
343
if (!g_isi_sb_iter_get_byte(&iter, &byte, 22))
346
record_length = byte;
351
DBG("Application type %d not supported", sd->app_type);
355
DBG("fileid=%04X, filelen=%d, records=%d, reclen=%d, structure=%d",
356
file_id, length, records, record_length, structure);
358
CALLBACK_WITH_SUCCESS(cb, length, structure, record_length,
359
access, file_status, cbd->data);
364
DBG("Error reading file info");
365
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, cbd->data);
368
static gboolean send_uicc_read_file_info(GIsiClient *client, uint8_t app_id,
369
int fileid, uint8_t df_len,
370
int mf_path, int df1_path,
372
GIsiNotifyFunc notify, void *data,
373
GDestroyNotify destroy)
375
const uint8_t msg[] = {
377
UICC_APPL_FILE_INFO, /* Service type */
379
UICC_SESSION_ID_NOT_USED,
381
1, /* Number of subblocks */
382
ISI_16BIT(UICC_SB_APPL_PATH),
383
ISI_16BIT(16), /* Subblock length */
385
uicc_get_sfi(fileid), /* Elementary file short file id */
394
return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
397
static void uicc_read_file_info(struct ofono_sim *sim, int fileid,
398
ofono_sim_file_info_cb_t cb, void *data)
400
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
401
struct uicc_file_info_cb_data *cbd;
403
/* Prepare for static file info used for access rights */
405
int N = sizeof(static_file_info) / sizeof(static_file_info[0]);
411
cbd = g_try_new0(struct uicc_file_info_cb_data, 1);
420
DBG("File info for ID=%04X app id %d", fileid, sd->app_id);
422
for (i = 0; i < N; i++) {
423
if (fileid == static_file_info[i].fileid) {
424
cbd->user = (void *) &static_file_info[i];
429
DBG("File info for ID=%04X: %p", fileid, cbd->user);
431
if (!uicc_get_fileid_path(sd, &mf_path, &df1_path, &df2_path,
435
if (send_uicc_read_file_info(sd->client, sd->app_id, fileid, df_len,
436
mf_path, df1_path, df2_path,
437
uicc_file_info_resp_cb,
442
CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
446
static void uicc_read_file_transp_resp_cb(const GIsiMessage *msg, void *opaque)
448
struct isi_cb_data *cbd = opaque;
449
ofono_sim_read_cb_t cb = cbd->cb;
450
GIsiSubBlockIter iter;
452
uint32_t filelen = 0;
453
uint8_t *filedata = NULL;
458
if (!check_resp(msg, UICC_APPL_CMD_RESP, UICC_APPL_READ_TRANSPARENT))
461
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
464
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
465
g_isi_sb_iter_is_valid(&iter);
466
g_isi_sb_iter_next(&iter)) {
468
int sb_id = g_isi_sb_iter_get_id(&iter);
470
DBG("Subblock %s", uicc_subblock_name(sb_id));
472
if (sb_id != UICC_SB_FILE_DATA)
475
if (!g_isi_sb_iter_get_dword(&iter, &filelen, 4))
478
if (!g_isi_sb_iter_get_struct(&iter, (void **) &filedata,
482
DBG("Transparent EF read: 1st byte %02x, len %d",
483
filedata[0], filelen);
484
CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
489
DBG("Error reading transparent EF");
490
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
493
static gboolean send_uicc_read_file_transparent(GIsiClient *client,
494
uint8_t app_id, uint8_t client_id,
495
int fileid, uint8_t df_len,
496
int mf_path, int df1_path,
498
GIsiNotifyFunc notify,
500
GDestroyNotify destroy)
502
const uint8_t msg[] = {
504
UICC_APPL_READ_TRANSPARENT,
506
UICC_SESSION_ID_NOT_USED,
508
3, /* Number of subblocks */
509
ISI_16BIT(UICC_SB_CLIENT),
510
ISI_16BIT(8), /* Subblock length*/
511
0, 0, 0, /* Filler */
513
ISI_16BIT(UICC_SB_TRANSPARENT),
514
ISI_16BIT(8), /* Subblock length */
515
ISI_16BIT(0), /* File offset */
516
ISI_16BIT(0), /* Data amount (0=all) */
517
ISI_16BIT(UICC_SB_APPL_PATH),
518
ISI_16BIT(16), /* Subblock length */
520
uicc_get_sfi(fileid), /* Elementary file short file id */
529
return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
532
static void uicc_read_file_transparent(struct ofono_sim *sim, int fileid,
533
int start, int length,
534
ofono_sim_read_cb_t cb, void *data)
536
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
537
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
546
DBG("File ID=%04X, client %d, AID %d", fileid, sd->client_id,
549
if (!uicc_get_fileid_path(sd, &mf_path, &df1_path,
550
&df2_path, &df_len, fileid))
553
if (send_uicc_read_file_transparent(sd->client, sd->app_id, sd->client_id,
554
fileid, df_len, mf_path,
556
uicc_read_file_transp_resp_cb,
561
DBG("Read file transparent failed");
562
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
566
static void read_file_linear_resp(const GIsiMessage *msg, void *opaque)
568
struct isi_cb_data *cbd = opaque;
569
ofono_sim_read_cb_t cb = cbd->cb;
570
GIsiSubBlockIter iter;
572
uint8_t *filedata = NULL;
573
uint32_t filelen = 0;
577
if (!check_resp(msg, UICC_APPL_CMD_RESP, UICC_APPL_READ_LINEAR_FIXED))
580
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
583
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
584
g_isi_sb_iter_is_valid(&iter);
585
g_isi_sb_iter_next(&iter)) {
587
uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
589
DBG("Subblock %s", uicc_subblock_name(sb_id));
591
if (sb_id != UICC_SB_FILE_DATA)
594
if (!g_isi_sb_iter_get_dword(&iter, &filelen, 4))
597
if (!g_isi_sb_iter_get_struct(&iter, (void **) &filedata,
601
DBG("Linear fixed EF read: 1st byte %02x, len %d", filedata[0],
604
CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
609
CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
612
static gboolean send_uicc_read_file_linear(GIsiClient *client, uint8_t app_id,
614
int fileid, int record,
616
unsigned char df_len,
617
int mf_path, int df1_path,
619
GIsiNotifyFunc notify,
621
GDestroyNotify destroy)
623
const uint8_t msg[] = {
625
UICC_APPL_READ_LINEAR_FIXED,
627
UICC_SESSION_ID_NOT_USED,
629
3, /* Number of subblocks */
630
ISI_16BIT(UICC_SB_CLIENT),
631
ISI_16BIT(8), /*Subblock length */
632
0, 0, 0, /* Filler */
634
ISI_16BIT(UICC_SB_LINEAR_FIXED),
635
ISI_16BIT(8), /*Subblock length */
637
0, /* Record offset */
638
rec_length & 0xff, /*Data amount (0=all)*/
640
ISI_16BIT(UICC_SB_APPL_PATH),
641
ISI_16BIT(16), /* Subblock length */
643
uicc_get_sfi(fileid), /* Elementary file short file id */
652
return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
655
static void uicc_read_file_linear(struct ofono_sim *sim, int fileid, int record,
656
int rec_length, ofono_sim_read_cb_t cb,
659
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
660
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
669
DBG("File ID=%04X, record %d, client %d AID %d", fileid, record,
670
sd->client_id, sd->app_id);
672
if (!uicc_get_fileid_path(sd, &mf_path, &df1_path, &df2_path,
676
if (send_uicc_read_file_linear(sd->client, sd->app_id, sd->client_id,
677
fileid, record, rec_length, df_len,
678
mf_path, df1_path, df2_path,
679
read_file_linear_resp, cbd, g_free))
683
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
687
static void uicc_read_file_cyclic(struct ofono_sim *sim, int fileid,
688
int record, int length,
689
ofono_sim_read_cb_t cb, void *data)
691
DBG("Not implemented");
692
CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
695
static void uicc_write_file_transparent(struct ofono_sim *sim, int fileid,
696
int start, int length,
697
const unsigned char *value,
698
ofono_sim_write_cb_t cb, void *data)
700
DBG("Not implemented");
701
CALLBACK_WITH_FAILURE(cb, data);
704
static void uicc_write_file_linear(struct ofono_sim *sim, int fileid, int record,
705
int length, const unsigned char *value,
706
ofono_sim_write_cb_t cb, void *data)
708
DBG("Not implemented");
709
CALLBACK_WITH_FAILURE(cb, data);
712
static void uicc_write_file_cyclic(struct ofono_sim *sim, int fileid, int length,
713
const unsigned char *value,
714
ofono_sim_write_cb_t cb, void *data)
716
DBG("Not implemented");
717
CALLBACK_WITH_FAILURE(cb, data);
720
static gboolean decode_imsi(uint8_t *data, int len, char *imsi)
722
int i = 1; /* Skip first byte, the length field */
725
if (data == NULL || len == 0)
728
if (data[0] != 8 || data[0] > len)
731
/* Ignore low-order semi-octet of the first byte */
732
imsi[j] = ((data[i] & 0xF0) >> 4) + '0';
734
for (i++, j++; i - 1 < data[0] && j < MAX_IMSI_LENGTH; i++) {
737
imsi[j++] = (data[i] & 0x0F) + '0';
738
nibble = (data[i] & 0xF0) >> 4;
741
imsi[j++] = nibble + '0';
748
static void uicc_read_imsi_resp(const GIsiMessage *msg, void *opaque)
750
struct isi_cb_data *cbd = opaque;
751
ofono_sim_imsi_cb_t cb = cbd->cb;
752
GIsiSubBlockIter iter;
754
uint32_t filelen = 0;
755
uint8_t *filedata = NULL;
758
char imsi[MAX_IMSI_LENGTH + 1] = { 0 };
762
if (!check_resp(msg, UICC_APPL_CMD_RESP, UICC_APPL_READ_TRANSPARENT))
765
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
768
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
769
g_isi_sb_iter_is_valid(&iter);
770
g_isi_sb_iter_next(&iter)) {
772
int sb_id = g_isi_sb_iter_get_id(&iter);
774
DBG("Subblock %s", uicc_subblock_name(sb_id));
776
if (sb_id != UICC_SB_FILE_DATA)
779
if (!g_isi_sb_iter_get_dword(&iter, &filelen, 4))
782
if (!g_isi_sb_iter_get_struct(&iter, (void **) &filedata,
786
DBG("Transparent EF read: 1st byte %02x, len %d",
787
filedata[0], filelen);
789
if (!decode_imsi(filedata, filelen, imsi))
792
DBG("IMSI %s", imsi);
793
CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
798
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
801
static void uicc_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
804
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
805
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
815
DBG("Client %d, AID %d", sd->client_id, sd->app_id);
817
if (!uicc_get_fileid_path(sd, &mf_path, &df1_path, &df2_path, &df_len,
821
if (send_uicc_read_file_transparent(sd->client, sd->app_id, sd->client_id,
822
SIM_EFIMSI_FILEID, df_len,
823
mf_path, df1_path, df2_path,
829
CALLBACK_WITH_FAILURE(cb, NULL, data);
833
static void uicc_query_passwd_state_resp(const GIsiMessage *msg, void *opaque)
835
struct isi_cb_data *cbd = opaque;
836
ofono_sim_passwd_cb_t cb = cbd->cb;
842
if (g_isi_msg_error(msg) < 0) {
843
DBG("Error: %s", g_isi_msg_strerror(msg));
847
if (g_isi_msg_id(msg) != UICC_PIN_RESP) {
848
DBG("Unexpected msg: %s", sim_message_id_name(g_isi_msg_id(msg)));
852
if (!g_isi_msg_data_get_byte(msg, 0, &type) ||
853
type != UICC_PIN_PROMPT_VERIFY) {
854
DBG("Unexpected service: 0x%02X (0x%02X)", type,
855
UICC_PIN_PROMPT_VERIFY);
859
if (!g_isi_msg_data_get_byte(msg, 1, &cause))
862
DBG("Status: %d %s", cause, uicc_status_name(cause));
864
if (cause == UICC_STATUS_PIN_DISABLED) {
865
CALLBACK_WITH_SUCCESS(cb, OFONO_SIM_PASSWORD_NONE, cbd->data);
869
DBG("Request failed or not implemented: %s", uicc_status_name(cause));
872
CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
875
static void uicc_query_passwd_state(struct ofono_sim *sim,
876
ofono_sim_passwd_cb_t cb, void *data)
878
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
879
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
881
const uint8_t req[] = {
883
UICC_PIN_PROMPT_VERIFY,
885
0, 0, 0, /* Filler */
886
1, /* Number of subblocks */
887
ISI_16BIT(UICC_SB_PIN_REF),
888
ISI_16BIT(8), /*Sub block length*/
889
sd->pin1_id, /* Pin ID */
890
0, 0, 0, /* Filler */
895
if (g_isi_client_send(sd->client, req, sizeof(req),
896
uicc_query_passwd_state_resp, cbd, g_free))
899
CALLBACK_WITH_FAILURE(cb, -1, data);
903
static void uicc_send_passwd(struct ofono_sim *sim, const char *passwd,
904
ofono_sim_lock_unlock_cb_t cb, void *data)
906
DBG("Not implemented");
907
CALLBACK_WITH_FAILURE(cb, data);
910
static void uicc_query_pin_retries_resp(const GIsiMessage *msg, void *opaque)
912
struct isi_cb_data *cbd = opaque;
913
ofono_sim_pin_retries_cb_t cb = cbd->cb;
914
int retries[OFONO_SIM_PASSWORD_INVALID];
915
GIsiSubBlockIter iter;
924
if (!check_resp(msg, UICC_PIN_RESP, UICC_PIN_INFO))
927
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
930
DBG("Subblock count %d", num_sb);
932
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
933
g_isi_sb_iter_is_valid(&iter);
934
g_isi_sb_iter_next(&iter)) {
936
uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
938
DBG("Sub-block %s", uicc_subblock_name(sb_id));
940
if (sb_id != UICC_SB_PIN_INFO)
943
if (!g_isi_sb_iter_get_byte(&iter, &pins, 4))
946
if (!g_isi_sb_iter_get_byte(&iter, &pina, 5))
949
if (!g_isi_sb_iter_get_byte(&iter, &puka, 6))
952
DBG("PIN status %X PIN Attrib %d PUK attrib %d", pins,
955
retries[OFONO_SIM_PASSWORD_SIM_PIN] = pina;
956
retries[OFONO_SIM_PASSWORD_SIM_PUK] = puka;
958
CALLBACK_WITH_SUCCESS(cb, retries, cbd->data);
963
CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
966
static void uicc_query_pin_retries(struct ofono_sim *sim,
967
ofono_sim_pin_retries_cb_t cb,
970
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
971
struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
973
const uint8_t req[] = {
977
0, 0, 0, /* Filler */
978
1, /* Number of subblocks */
979
ISI_16BIT(UICC_SB_PIN_REF),
980
ISI_16BIT(8), /* Subblock length */
981
sd->pin1_id, /* Pin ID */
982
0, 0, 0, /* Filler */
987
if (g_isi_client_send(sd->client, req, sizeof(req),
988
uicc_query_pin_retries_resp, cbd, g_free))
991
CALLBACK_WITH_FAILURE(cb, NULL, data);
995
static void uicc_reset_passwd(struct ofono_sim *sim, const char *puk,
996
const char *passwd, ofono_sim_lock_unlock_cb_t cb,
999
DBG("Not implemented");
1000
CALLBACK_WITH_FAILURE(cb, data);
1003
static void uicc_change_passwd(struct ofono_sim *sim,
1004
enum ofono_sim_password_type passwd_type,
1005
const char *old, const char *new,
1006
ofono_sim_lock_unlock_cb_t cb, void *data)
1008
DBG("Not implemented");
1009
CALLBACK_WITH_FAILURE(cb, data);
1012
static void uicc_lock(struct ofono_sim *sim, enum ofono_sim_password_type type,
1013
int enable, const char *passwd,
1014
ofono_sim_lock_unlock_cb_t cb, void *data)
1016
DBG("Not implemented");
1017
CALLBACK_WITH_FAILURE(cb, data);
1020
static void uicc_query_locked(struct ofono_sim *sim,
1021
enum ofono_sim_password_type type,
1022
ofono_sim_locked_cb_t cb, void *data)
1024
DBG("Not implemented");
1025
CALLBACK_WITH_FAILURE(cb, -1, data);
1028
static gboolean decode_fcp_pin_status(const GIsiSubBlockIter *iter, uint8_t read,
1029
uint8_t *pin1, uint8_t *pin2)
1037
DBG("Decoding PIN status");
1039
if (!g_isi_sb_iter_get_byte(iter, &do_len, read))
1042
tag_pos = read + 1 + do_len;
1044
if (!g_isi_sb_iter_get_byte(iter, &tag, tag_pos))
1047
while (tag == 0x83) {
1049
if (!g_isi_sb_iter_get_byte(iter, &len, tag_pos + 1))
1052
if (!g_isi_sb_iter_get_byte(iter, &id, tag_pos + 2))
1057
if (!g_isi_sb_iter_get_byte(iter, &tag, tag_pos))
1060
DBG("PIN_len %d, PIN id %02x, PIN tag %02x", len, id, tag);
1062
if (id >= 0x01 && id <= 0x08)
1064
else if (id >= 0x81 && id <= 0x88)
1070
static gboolean decode_fci_sb(const GIsiSubBlockIter *iter, int app_type,
1071
uint8_t *pin1, uint8_t *pin2)
1074
uint8_t fcp_len = 0;
1076
uint8_t item_len = 0;
1078
DBG("Decoding UICC_SB_FCI");
1080
if (app_type != UICC_APPL_TYPE_UICC_USIM)
1083
if (!g_isi_sb_iter_get_byte(iter, &fcp, 8))
1086
if (fcp != FCP_TEMPLATE)
1089
if (!g_isi_sb_iter_get_byte(iter, &fcp_len, 9))
1092
for (read = 0; read < fcp_len; read += item_len + 2) {
1095
if (!g_isi_sb_iter_get_byte(iter, &id, read + 10))
1098
if (!g_isi_sb_iter_get_byte(iter, &item_len, read + 11))
1101
if (id != FCP_PIN_STATUS)
1104
if (!decode_fcp_pin_status(iter, read + 13, pin1, pin2))
1110
static gboolean decode_chv_sb(const GIsiSubBlockIter *iter, int app_type,
1111
uint8_t *pin1, uint8_t *pin2)
1116
DBG("Decoding UICC_SB_CHV");
1118
if (app_type != UICC_APPL_TYPE_ICC_SIM)
1121
if (!g_isi_sb_iter_get_byte(iter, &chv_id, 4))
1124
if (!g_isi_sb_iter_get_byte(iter, &pin_id, 5))
1140
DBG("CHV=%d, pin_id=%2x, PIN1 %02x, PIN2 %02x", chv_id, pin_id, *pin1,
1146
static void uicc_application_activate_resp(const GIsiMessage *msg, void *opaque)
1148
struct ofono_sim *sim = opaque;
1149
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1150
GIsiSubBlockIter iter;
1151
uint8_t cause, num_sb;
1155
if (g_isi_msg_error(msg) < 0) {
1156
DBG("Error: %s", g_isi_msg_strerror(msg));
1160
if (g_isi_msg_id(msg) != UICC_APPLICATION_RESP) {
1161
DBG("Unexpected msg: %s",
1162
sim_message_id_name(g_isi_msg_id(msg)));
1166
if (!g_isi_msg_data_get_byte(msg, 1, &cause))
1169
if (cause != UICC_STATUS_OK && cause != UICC_STATUS_APPL_ACTIVE) {
1170
DBG("TODO: handle application activation");
1174
if (!sd->uicc_app_started) {
1175
sd->app_id = sd->trying_app_id;
1176
sd->app_type = sd->trying_app_type;
1177
sd->uicc_app_started = TRUE;
1179
DBG("UICC application activated");
1181
ofono_sim_inserted_notify(sim, TRUE);
1182
ofono_sim_register(sim);
1184
g_hash_table_remove_all(sd->app_table);
1187
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
1190
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
1191
g_isi_sb_iter_is_valid(&iter);
1192
g_isi_sb_iter_next(&iter)) {
1194
uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
1196
DBG("Subblock %s", uicc_subblock_name(sb_id));
1199
case UICC_SB_CLIENT:
1201
if (!g_isi_sb_iter_get_byte(&iter, &sd->client_id, 7))
1204
DBG("Client id %d", sd->client_id);
1209
if (!decode_fci_sb(&iter, sd->app_type, &sd->pin1_id,
1213
DBG("PIN1 %02x, PIN2 %02x", sd->pin1_id, sd->pin2_id);
1218
if (!decode_chv_sb(&iter, sd->app_type, &sd->pin1_id,
1222
DBG("PIN1 %02x, PIN2 %02x", sd->pin1_id, sd->pin2_id);
1226
DBG("Skipping sub-block: %s (%zu bytes)",
1227
uicc_subblock_name(g_isi_sb_iter_get_id(&iter)),
1228
g_isi_sb_iter_get_len(&iter));
1234
static gboolean send_application_activate_req(GIsiClient *client,
1237
GIsiNotifyFunc notify,
1239
GDestroyNotify destroy)
1241
const uint8_t msg[] = {
1242
UICC_APPLICATION_REQ,
1243
UICC_APPL_HOST_ACTIVATE,
1244
2, /* Number of subblocks */
1245
ISI_16BIT(UICC_SB_APPLICATION),
1246
ISI_16BIT(8), /* Subblock length */
1250
ISI_16BIT(UICC_SB_APPL_INFO),
1251
ISI_16BIT(8), /* Subblock length */
1252
0, 0, 0, /* Filler */
1254
* Next field indicates whether the application
1255
* initialization procedure will follow the activation
1258
UICC_APPL_START_UP_INIT_PROC,
1261
DBG("App type %d, AID %d", app_type, app_id);
1263
return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
1266
static void uicc_application_list_resp(const GIsiMessage *msg, void *data)
1268
struct ofono_sim *sim = data;
1269
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1270
GIsiSubBlockIter iter;
1272
struct uicc_sim_application *sim_app;
1274
/* Throw away old app table */
1275
g_hash_table_remove_all(sd->app_table);
1277
if (!check_resp(msg, UICC_APPLICATION_RESP, UICC_APPL_LIST))
1280
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
1283
/* Iterate through the application list */
1284
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
1285
g_isi_sb_iter_is_valid(&iter);
1286
g_isi_sb_iter_next(&iter)) {
1292
if (g_isi_sb_iter_get_id(&iter) != UICC_SB_APPL_DATA_OBJECT)
1295
if (!g_isi_sb_iter_get_byte(&iter, &app_type, 6))
1298
if (!g_isi_sb_iter_get_byte(&iter, &app_id, 7))
1301
if (!g_isi_sb_iter_get_byte(&iter, &app_status, 8))
1304
if (!g_isi_sb_iter_get_byte(&iter, &app_len, 9))
1307
if (app_type != UICC_APPL_TYPE_ICC_SIM &&
1308
app_type != UICC_APPL_TYPE_UICC_USIM)
1311
sim_app = g_try_new0(struct uicc_sim_application, 1);
1313
DBG("out of memory!");
1317
sim_app->type = app_type;
1318
sim_app->id = app_id;
1319
sim_app->status = app_status;
1320
sim_app->length = app_len;
1323
g_hash_table_replace(sd->app_table, &sim_app->id, sim_app);
1326
if (!sd->uicc_app_started) {
1327
GHashTableIter app_iter;
1328
struct uicc_sim_application *app;
1333
g_hash_table_iter_init(&app_iter, sd->app_table);
1335
if (!g_hash_table_iter_next(&app_iter, &key, &value))
1339
sd->trying_app_type = app->type;
1340
sd->trying_app_id = app->id;
1342
g_hash_table_remove(sd->app_table, &app->id);
1344
if (!send_application_activate_req(sd->client, app->type, app->id,
1345
uicc_application_activate_resp,
1347
DBG("Failed to activate: 0x%02X (type=0x%02X)",
1348
app->id, app->type);
1355
DBG("Decoding application list failed");
1357
g_isi_client_destroy(sd->client);
1360
ofono_sim_remove(sim);
1363
static void uicc_card_status_resp(const GIsiMessage *msg, void *data)
1365
struct ofono_sim *sim = data;
1366
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1367
GIsiSubBlockIter iter;
1368
uint8_t card_status = 0;
1373
if (!sd->server_running)
1376
if (!check_resp(msg, UICC_CARD_RESP, UICC_CARD_STATUS_GET))
1379
if (!g_isi_msg_data_get_byte(msg, 1, &card_status))
1382
if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
1385
DBG("Subblock count %d", num_sb);
1387
for (g_isi_sb_iter_init_full(&iter, msg, 6, TRUE, num_sb);
1388
g_isi_sb_iter_is_valid(&iter);
1389
g_isi_sb_iter_next(&iter)) {
1391
if (g_isi_sb_iter_get_id(&iter) != UICC_SB_CARD_STATUS)
1394
if (!g_isi_sb_iter_get_byte(&iter, &card_status, 7))
1397
DBG("card_status = 0x%X", card_status);
1399
/* Check if card is ready */
1400
if (card_status == 0x21) {
1401
const uint8_t req[] = {
1402
UICC_APPLICATION_REQ,
1404
0, /* Number of subblocks */
1407
DBG("card is ready");
1408
ofono_sim_inserted_notify(sim, TRUE);
1410
if (g_isi_client_send(sd->client, req, sizeof(req),
1411
uicc_application_list_resp,
1415
DBG("Failed to query application list");
1419
DBG("card not ready");
1420
ofono_sim_inserted_notify(sim, FALSE);
1426
g_isi_client_destroy(sd->client);
1429
ofono_sim_remove(sim);
1432
static void uicc_card_status_req(struct ofono_sim *sim,
1433
struct uicc_sim_data *sd)
1435
const uint8_t req[] = {
1437
UICC_CARD_STATUS_GET,
1443
if (g_isi_client_send(sd->client, req, sizeof(req),
1444
uicc_card_status_resp, sim, NULL))
1447
g_isi_client_destroy(sd->client);
1450
ofono_sim_remove(sim);
1453
static void uicc_card_ind_cb(const GIsiMessage *msg, void *data)
1455
struct ofono_sim *sim = data;
1456
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1460
if (g_isi_msg_id(msg) != UICC_CARD_IND)
1463
/* We're not interested in card indications if server isn't running */
1464
if (!sd->server_running)
1467
/* Request card status */
1468
uicc_card_status_req(sim, sd);
1471
static void uicc_status_resp(const GIsiMessage *msg, void *data)
1473
struct ofono_sim *sim = data;
1474
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1475
uint8_t status = 0, server_status = 0;
1476
gboolean server_running = FALSE;
1478
if (!check_resp(msg, UICC_RESP, UICC_STATUS_GET))
1481
if (g_isi_msg_error(msg) < 0)
1484
if (!g_isi_msg_data_get_byte(msg, 1, &status) ||
1485
!g_isi_msg_data_get_byte(msg, 3, &server_status))
1488
DBG("status=0x%X, server_status=0x%X", status, server_status);
1490
if (status == UICC_STATUS_OK &&
1491
server_status == UICC_STATUS_START_UP_COMPLETED) {
1492
DBG("server is up!");
1493
server_running = TRUE;
1497
if (!server_running) {
1498
sd->server_running = FALSE;
1500
/* TODO: Remove SIM etc... */
1504
if (sd->server_running && server_running) {
1505
DBG("Server status didn't change...");
1509
/* Server is running */
1510
sd->server_running = TRUE;
1512
/* Request card status */
1513
uicc_card_status_req(sim, sd);
1517
g_isi_client_destroy(sd->client);
1520
ofono_sim_remove(sim);
1523
static void uicc_ind_cb(const GIsiMessage *msg, void *data)
1525
struct ofono_sim *sim = data;
1526
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1527
const uint8_t req[] = { UICC_REQ, UICC_STATUS_GET, 0 };
1529
int msg_id = g_isi_msg_id(msg);
1530
DBG("%s", uicc_message_id_name(msg_id));
1532
if (msg_id != UICC_IND)
1535
/* Request status */
1536
if (g_isi_client_send(sd->client, req, sizeof(req), uicc_status_resp,
1540
DBG("status request failed!");
1542
g_isi_client_destroy(sd->client);
1544
ofono_sim_remove(sim);
1547
static void uicc_reachable_cb(const GIsiMessage *msg, void *data)
1549
struct ofono_sim *sim = data;
1550
struct uicc_sim_data *sd = ofono_sim_get_data(sim);
1552
const uint8_t req[] = {
1555
0, /* Number of Sub Blocks (only from version 4.0) */
1558
ISI_RESOURCE_DBG(msg);
1560
if (g_isi_msg_error(msg) < 0)
1563
sd->version.major = g_isi_msg_version_major(msg);
1564
sd->version.minor = g_isi_msg_version_minor(msg);
1566
/* UICC server is reachable: request indications */
1567
g_isi_client_ind_subscribe(sd->client, UICC_IND, uicc_ind_cb, sim);
1568
g_isi_client_ind_subscribe(sd->client, UICC_CARD_IND, uicc_card_ind_cb,
1572
if (g_isi_client_send(sd->client, req,
1573
sizeof(req) - ((sd->version.major < 4) ? 1 : 0),
1574
uicc_status_resp, data, NULL))
1578
g_isi_client_destroy(sd->client);
1581
ofono_sim_remove(sim);
1584
static void sim_app_destroy(gpointer p)
1586
struct uicc_sim_application *app = p;
1593
static int uicc_sim_probe(struct ofono_sim *sim, unsigned int vendor,
1596
GIsiModem *modem = user;
1597
struct uicc_sim_data *sd;
1599
sd = g_try_new0(struct uicc_sim_data, 1);
1603
/* Create hash table for the UICC applications */
1604
sd->app_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
1606
if (sd->app_table == NULL) {
1611
sd->client = g_isi_client_create(modem, PN_UICC);
1612
if (sd->client == NULL) {
1613
g_hash_table_destroy(sd->app_table);
1618
g_hash_table_insert(g_modems, g_isi_client_modem(sd->client), sim);
1620
sd->server_running = FALSE;
1621
sd->uicc_app_started = FALSE;
1622
sd->pin_state_received = FALSE;
1623
sd->passwd_required = TRUE;
1624
ofono_sim_set_data(sim, sd);
1626
g_isi_client_verify(sd->client, uicc_reachable_cb, sim, NULL);
1631
static void uicc_sim_remove(struct ofono_sim *sim)
1633
struct uicc_sim_data *data = ofono_sim_get_data(sim);
1635
ofono_sim_set_data(sim, NULL);
1640
g_hash_table_remove(g_modems, g_isi_client_modem(data->client));
1642
g_hash_table_destroy(data->app_table);
1643
g_isi_client_destroy(data->client);
1647
static struct ofono_sim_driver driver = {
1648
.name = "wgmodem2.5",
1649
.probe = uicc_sim_probe,
1650
.remove = uicc_sim_remove,
1651
.read_file_info = uicc_read_file_info,
1652
.read_file_transparent = uicc_read_file_transparent,
1653
.read_file_linear = uicc_read_file_linear,
1654
.read_file_cyclic = uicc_read_file_cyclic,
1655
.write_file_transparent = uicc_write_file_transparent,
1656
.write_file_linear = uicc_write_file_linear,
1657
.write_file_cyclic = uicc_write_file_cyclic,
1658
.read_imsi = uicc_read_imsi,
1659
.query_passwd_state = uicc_query_passwd_state,
1660
.send_passwd = uicc_send_passwd,
1661
.query_pin_retries = uicc_query_pin_retries,
1662
.reset_passwd = uicc_reset_passwd,
1663
.change_passwd = uicc_change_passwd,
1665
.query_locked = uicc_query_locked,
1668
void isi_uicc_init(void)
1670
g_modems = g_hash_table_new(g_direct_hash, g_direct_equal);
1671
ofono_sim_driver_register(&driver);
1674
void isi_uicc_exit(void)
1676
g_hash_table_destroy(g_modems);
1677
ofono_sim_driver_unregister(&driver);
1680
gboolean isi_uicc_properties(GIsiModem *modem, int *app_id, int *app_type,
1683
struct ofono_sim *sim;
1684
struct uicc_sim_data *sd;
1686
sim = g_hash_table_lookup(g_modems, modem);
1690
sd = ofono_sim_get_data(sim);
1695
*app_id = sd->app_id;
1697
if (app_type != NULL)
1698
*app_type = sd->app_type;
1700
if (client_id != NULL)
1701
*client_id = sd->client_id;