~morphis/phablet-extras/ofono-sms-status-report

« back to all changes in this revision

Viewing changes to drivers/isimodem/uicc.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2012-08-22 19:59:08 UTC
  • mfrom: (1.3.3) (6.1.5 experimental)
  • Revision ID: package-import@ubuntu.com-20120822195908-0bmmk1hlh989bgk6
Tags: 1.9-1ubuntu1
* Merge with Debian experimental; remaining changes:
  - debian/control: explicitly Conflicts with modemmanager: having both
    installed / running at the same time causes issues causes issues with
    both claiming modem devices.
  - debian/patches/02-dont-handle-stacktraces.patch: stop catching stacktraces
    and printing the information internally, so apport can catch and report
    the possible bugs.
  - debian/ofono.postinst: on configure, notify the user that a reboot is
    required (so ofono can get started by upstart). (LP: #600501)
  - debian/rules: pass --no-restart-on-upgrade so ofono isn't automatically
    restarted when upgrades.
  - Adding upstart config / Removing standard init script
  - Adding Apport support
  - Patch for recognizing special Huawei devices with weird serial
  - Override lintian to avoid script-in-etc-init.d... warnings.
  - Update debian/compat to 7
* debian/series: add our patches to debian/patches/series now that the package
  uses quilt.
* debian/patches/02-dont-handle-stacktraces.patch: refreshed.
* debian/ofono-dev.install, debian/ofono.install:
  - Install usr/sbin/dundee and ofono.pc to the proper packages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  oFono - Open Source Telephony
 
4
 *
 
5
 *  Copyright (C) 2011  ST-Ericsson AB.
 
6
 *  Copyright (C) 2011  Nokia Corporation and/or its subsidiary(-ies).
 
7
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
20
 *
 
21
 */
 
22
 
 
23
#ifdef HAVE_CONFIG_H
 
24
#include <config.h>
 
25
#endif
 
26
 
 
27
#define _GNU_SOURCE
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <errno.h>
 
32
 
 
33
#include <glib.h>
 
34
 
 
35
#include <gisi/message.h>
 
36
#include <gisi/client.h>
 
37
#include <gisi/iter.h>
 
38
 
 
39
#include <ofono/log.h>
 
40
#include <ofono/modem.h>
 
41
#include <ofono/sim.h>
 
42
 
 
43
#include "simutil.h"
 
44
#include "isimodem.h"
 
45
#include "isiutil.h"
 
46
#include "sim.h"
 
47
#include "uicc.h"
 
48
#include "uicc-util.h"
 
49
#include "debug.h"
 
50
 
 
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
 
64
 
 
65
enum uicc_flag {
 
66
        UICC_FLAG_APP_STARTED =         1 << 0,
 
67
        UICC_FLAG_PIN_STATE_RECEIVED =  1 << 1,
 
68
        UICC_FLAG_PASSWD_REQUIRED =     1 << 2,
 
69
};
 
70
 
 
71
static GHashTable *g_modems;
 
72
 
 
73
struct file_info {
 
74
        int fileid;
 
75
        int length;
 
76
        int structure;
 
77
        int record_length;
 
78
        uint8_t access[3];
 
79
        uint8_t file_status;
 
80
};
 
81
 
 
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 },
 
101
};
 
102
 
 
103
static gboolean check_resp(const GIsiMessage *msg, uint8_t msgid, uint8_t service)
 
104
{
 
105
        uint8_t type;
 
106
        uint8_t cause;
 
107
 
 
108
        if (g_isi_msg_error(msg) < 0) {
 
109
                DBG("Error: %s", g_isi_msg_strerror(msg));
 
110
                return FALSE;
 
111
        }
 
112
 
 
113
        if (g_isi_msg_id(msg) != msgid) {
 
114
                DBG("Unexpected msg: %s",
 
115
                        sim_message_id_name(g_isi_msg_id(msg)));
 
116
                return FALSE;
 
117
        }
 
118
 
 
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));
 
122
                return FALSE;
 
123
        }
 
124
 
 
125
        if (!g_isi_msg_data_get_byte(msg, 0, &type) || type != service) {
 
126
                DBG("Unexpected service: 0x%02X (0x%02X)", type, service);
 
127
                return FALSE;
 
128
        }
 
129
        return TRUE;
 
130
}
 
131
 
 
132
struct uicc_file_info_cb_data {
 
133
        void *cb;
 
134
        void *data;
 
135
        void *user;
 
136
        struct ofono_sim *sim;
 
137
};
 
138
 
 
139
static gboolean decode_uicc_usim_type(GIsiSubBlockIter *iter, uint16_t *length,
 
140
                                        uint16_t *file_id,
 
141
                                        uint16_t *record_length,
 
142
                                        uint8_t *records, uint8_t *structure)
 
143
{
 
144
        uint8_t fcp = 0;
 
145
        uint8_t desc = 0;
 
146
        uint8_t coding = 0;
 
147
        uint8_t fcp_len = 0;
 
148
        uint8_t read = 0;
 
149
        uint8_t item_len = 0;
 
150
 
 
151
        if (!g_isi_sb_iter_get_byte(iter, &fcp, 8))
 
152
                return FALSE;
 
153
 
 
154
        if (fcp != FCP_TEMPLATE)
 
155
                return FALSE;
 
156
 
 
157
        if (!g_isi_sb_iter_get_byte(iter, &fcp_len, 9))
 
158
                return FALSE;
 
159
 
 
160
        for (read = 0; read < fcp_len; read += item_len + 2) {
 
161
 
 
162
                uint8_t id;
 
163
 
 
164
                if (!g_isi_sb_iter_get_byte(iter, &id, read + 10))
 
165
                        return FALSE;
 
166
 
 
167
                if (!g_isi_sb_iter_get_byte(iter, &item_len, read + 11))
 
168
                        return FALSE;
 
169
 
 
170
                switch (id) {
 
171
                case FCP_FILE_SIZE:
 
172
 
 
173
                        if (item_len != 2)
 
174
                                return FALSE;
 
175
 
 
176
                        if (!g_isi_sb_iter_get_word(iter, length, read + 10 + 2))
 
177
                                return FALSE;
 
178
 
 
179
                        break;
 
180
 
 
181
                case FCP_FILE_ID:
 
182
 
 
183
                        if (item_len != 2)
 
184
                                return FALSE;
 
185
 
 
186
                        if (!g_isi_sb_iter_get_word(iter, file_id, read + 10 + 2))
 
187
                                return FALSE;
 
188
 
 
189
                        break;
 
190
 
 
191
                case FCP_FILE_DESC:
 
192
 
 
193
                        if (item_len < 2)
 
194
                                return FALSE;
 
195
 
 
196
                        if (!g_isi_sb_iter_get_byte(iter, &desc, read + 10 + 2))
 
197
                                return FALSE;
 
198
 
 
199
                        if (!g_isi_sb_iter_get_byte(iter, &coding, read + 10 + 3))
 
200
                                return FALSE;
 
201
 
 
202
                        if (item_len < 4)
 
203
                                break;
 
204
 
 
205
                        if (!g_isi_sb_iter_get_word(iter, record_length,
 
206
                                                        read + 10 + 4))
 
207
                                return FALSE;
 
208
 
 
209
                        if (!g_isi_sb_iter_get_byte(iter, records, read + 10 + 6))
 
210
                                return FALSE;
 
211
 
 
212
                        break;
 
213
 
 
214
                /*
 
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
 
218
                 * E, F and G.
 
219
                 */
 
220
                case FCP_FILE_SECURITY_ARR:
 
221
                case FCP_FILE_SECURITY_COMPACT:
 
222
                case FCP_FILE_SECURITY_EXPANDED:
 
223
                case FCP_FILE_LIFECYCLE:
 
224
                default:
 
225
                        DBG("FCP id %02X not supported", id);
 
226
                        break;
 
227
                }
 
228
        }
 
229
 
 
230
        if ((desc & 7) == 1)
 
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;
 
236
 
 
237
        return TRUE;
 
238
}
 
239
 
 
240
static void uicc_file_info_resp_cb(const GIsiMessage *msg, void *opaque)
 
241
{
 
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;
 
246
 
 
247
        GIsiSubBlockIter iter;
 
248
 
 
249
        uint16_t length = 0;
 
250
        uint16_t record_length = 0;
 
251
        uint8_t structure = 0xFF;
 
252
        uint8_t records = 0;
 
253
        uint16_t file_id = 0;
 
254
        uint8_t access[3] = {0, 0, 0};
 
255
        uint8_t item_len = 0;
 
256
 
 
257
        uint8_t message_id = 0;
 
258
        uint8_t service_type = 0;
 
259
        uint8_t status = 0;
 
260
        uint8_t details = 0;
 
261
        uint8_t num_subblocks = 0;
 
262
        uint8_t file_status = 1;
 
263
 
 
264
        message_id = g_isi_msg_id(msg);
 
265
 
 
266
        DBG("uicc_file_info_resp_cb: msg_id=%d, msg len=%zu", message_id,
 
267
                g_isi_msg_data_len(msg));
 
268
 
 
269
        if (message_id != UICC_APPL_CMD_RESP)
 
270
                goto error;
 
271
 
 
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))
 
276
                goto error;
 
277
 
 
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),
 
282
                num_subblocks);
 
283
 
 
284
        if (info) {
 
285
                access[0] = info->access[0];
 
286
                access[1] = info->access[1];
 
287
                access[2] = info->access[2];
 
288
                file_status = info->file_status;
 
289
        }
 
290
 
 
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)) {
 
294
 
 
295
                uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
 
296
 
 
297
                DBG("Subblock %s", uicc_subblock_name(sb_id));
 
298
 
 
299
                if (sb_id != UICC_SB_FCI)
 
300
                        continue;
 
301
 
 
302
                DBG("Decoding UICC_SB_FCI");
 
303
 
 
304
                switch (sd->app_type) {
 
305
                case UICC_APPL_TYPE_UICC_USIM:
 
306
                        DBG("UICC_APPL_TYPE_UICC_USIM");
 
307
 
 
308
                        if (!decode_uicc_usim_type(&iter, &length, &file_id,
 
309
                                                        &record_length,
 
310
                                                        &records,
 
311
                                                        &structure))
 
312
                                goto error;
 
313
 
 
314
                        break;
 
315
 
 
316
                case UICC_APPL_TYPE_ICC_SIM:
 
317
                        DBG("UICC_APPL_TYPE_ICC_SIM");
 
318
 
 
319
                        if (!g_isi_sb_iter_get_word(&iter, &length, 10))
 
320
                                goto error;
 
321
 
 
322
                        if (!g_isi_sb_iter_get_word(&iter, &file_id, 12))
 
323
                                goto error;
 
324
 
 
325
                        if (!g_isi_sb_iter_get_byte(&iter, &access[0], 16))
 
326
                                goto error;
 
327
 
 
328
                        if (!g_isi_sb_iter_get_byte(&iter, &access[0], 17))
 
329
                                goto error;
 
330
 
 
331
                        if (!g_isi_sb_iter_get_byte(&iter, &access[0], 18))
 
332
                                goto error;
 
333
 
 
334
                        if (!g_isi_sb_iter_get_byte(&iter, &item_len, 20))
 
335
                                goto error;
 
336
 
 
337
                        if (!g_isi_sb_iter_get_byte(&iter, &structure, 21))
 
338
                                goto error;
 
339
 
 
340
                        if (item_len == 2) {
 
341
                                uint8_t byte;
 
342
 
 
343
                                if (!g_isi_sb_iter_get_byte(&iter, &byte, 22))
 
344
                                        goto error;
 
345
 
 
346
                                record_length = byte;
 
347
                        }
 
348
                        break;
 
349
 
 
350
                default:
 
351
                        DBG("Application type %d not supported", sd->app_type);
 
352
                        break;
 
353
                }
 
354
 
 
355
                DBG("fileid=%04X, filelen=%d, records=%d, reclen=%d, structure=%d",
 
356
                        file_id, length, records, record_length, structure);
 
357
 
 
358
                CALLBACK_WITH_SUCCESS(cb, length, structure, record_length,
 
359
                                        access, file_status, cbd->data);
 
360
                return;
 
361
        }
 
362
 
 
363
error:
 
364
        DBG("Error reading file info");
 
365
        CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, cbd->data);
 
366
}
 
367
 
 
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,
 
371
                                                int df2_path,
 
372
                                                GIsiNotifyFunc notify, void *data,
 
373
                                                GDestroyNotify destroy)
 
374
{
 
375
        const uint8_t msg[] = {
 
376
                UICC_APPL_CMD_REQ,
 
377
                UICC_APPL_FILE_INFO,    /* Service type */
 
378
                app_id,
 
379
                UICC_SESSION_ID_NOT_USED,
 
380
                0, 0,                   /* Filler */
 
381
                1,                      /* Number of subblocks */
 
382
                ISI_16BIT(UICC_SB_APPL_PATH),
 
383
                ISI_16BIT(16),          /* Subblock length */
 
384
                ISI_16BIT(fileid),
 
385
                uicc_get_sfi(fileid),   /* Elementary file short file id */
 
386
                0,                      /* Filler */
 
387
                df_len,
 
388
                0,                      /* Filler */
 
389
                ISI_16BIT(mf_path),
 
390
                ISI_16BIT(df1_path),
 
391
                ISI_16BIT(df2_path),
 
392
        };
 
393
 
 
394
        return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
 
395
}
 
396
 
 
397
static void uicc_read_file_info(struct ofono_sim *sim, int fileid,
 
398
                                ofono_sim_file_info_cb_t cb, void *data)
 
399
{
 
400
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
401
        struct uicc_file_info_cb_data *cbd;
 
402
 
 
403
        /* Prepare for static file info used for access rights */
 
404
        int i;
 
405
        int N = sizeof(static_file_info) / sizeof(static_file_info[0]);
 
406
        int mf_path = 0;
 
407
        int df1_path = 0;
 
408
        int df2_path = 0;
 
409
        uint8_t df_len = 0;
 
410
 
 
411
        cbd = g_try_new0(struct uicc_file_info_cb_data, 1);
 
412
        if (!cbd)
 
413
                goto error;
 
414
 
 
415
        cbd->cb = cb;
 
416
        cbd->data = data;
 
417
        cbd->sim = sim;
 
418
        cbd->user = NULL;
 
419
 
 
420
        DBG("File info for ID=%04X app id %d", fileid, sd->app_id);
 
421
 
 
422
        for (i = 0; i < N; i++) {
 
423
                if (fileid == static_file_info[i].fileid) {
 
424
                        cbd->user = (void *) &static_file_info[i];
 
425
                        break;
 
426
                }
 
427
        }
 
428
 
 
429
        DBG("File info for ID=%04X: %p", fileid, cbd->user);
 
430
 
 
431
        if (!uicc_get_fileid_path(sd, &mf_path, &df1_path, &df2_path,
 
432
                                        &df_len, fileid))
 
433
                goto error;
 
434
 
 
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,
 
438
                                        cbd, g_free))
 
439
                return;
 
440
 
 
441
error:
 
442
        CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, 0, data);
 
443
        g_free(cbd);
 
444
}
 
445
 
 
446
static void uicc_read_file_transp_resp_cb(const GIsiMessage *msg, void *opaque)
 
447
{
 
448
        struct isi_cb_data *cbd = opaque;
 
449
        ofono_sim_read_cb_t cb = cbd->cb;
 
450
        GIsiSubBlockIter iter;
 
451
 
 
452
        uint32_t filelen = 0;
 
453
        uint8_t *filedata = NULL;
 
454
        uint8_t num_sb = 0;
 
455
 
 
456
        DBG("");
 
457
 
 
458
        if (!check_resp(msg, UICC_APPL_CMD_RESP, UICC_APPL_READ_TRANSPARENT))
 
459
                goto error;
 
460
 
 
461
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
462
                goto error;
 
463
 
 
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)) {
 
467
 
 
468
                int sb_id = g_isi_sb_iter_get_id(&iter);
 
469
 
 
470
                DBG("Subblock %s", uicc_subblock_name(sb_id));
 
471
 
 
472
                if (sb_id != UICC_SB_FILE_DATA)
 
473
                        continue;
 
474
 
 
475
                if (!g_isi_sb_iter_get_dword(&iter, &filelen, 4))
 
476
                        goto error;
 
477
 
 
478
                if (!g_isi_sb_iter_get_struct(&iter, (void **) &filedata,
 
479
                                                filelen, 8))
 
480
                        goto error;
 
481
 
 
482
                DBG("Transparent EF read: 1st byte %02x, len %d",
 
483
                        filedata[0], filelen);
 
484
                CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
 
485
                return;
 
486
        }
 
487
 
 
488
error:
 
489
        DBG("Error reading transparent EF");
 
490
        CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
 
491
}
 
492
 
 
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,
 
497
                                                int df2_path,
 
498
                                                GIsiNotifyFunc notify,
 
499
                                                void *data,
 
500
                                                GDestroyNotify destroy)
 
501
{
 
502
        const uint8_t msg[] = {
 
503
                UICC_APPL_CMD_REQ,
 
504
                UICC_APPL_READ_TRANSPARENT,
 
505
                app_id,
 
506
                UICC_SESSION_ID_NOT_USED,
 
507
                0, 0,           /* Filler */
 
508
                3,              /* Number of subblocks */
 
509
                ISI_16BIT(UICC_SB_CLIENT),
 
510
                ISI_16BIT(8),   /* Subblock length*/
 
511
                0, 0, 0,        /* Filler */
 
512
                client_id,
 
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 */
 
519
                ISI_16BIT(fileid),
 
520
                uicc_get_sfi(fileid),   /* Elementary file short file id */
 
521
                0,      /* Filler */
 
522
                df_len,
 
523
                0,
 
524
                ISI_16BIT(mf_path),
 
525
                ISI_16BIT(df1_path),
 
526
                ISI_16BIT(df2_path),
 
527
        };
 
528
 
 
529
        return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
 
530
}
 
531
 
 
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)
 
535
{
 
536
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
537
        struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
 
538
        int mf_path = 0;
 
539
        int df1_path = 0;
 
540
        int df2_path = 0;
 
541
        uint8_t df_len = 0;
 
542
 
 
543
        if (!cbd || !sd)
 
544
                goto error;
 
545
 
 
546
        DBG("File ID=%04X, client %d, AID %d", fileid, sd->client_id,
 
547
                sd->app_id);
 
548
 
 
549
        if (!uicc_get_fileid_path(sd, &mf_path, &df1_path,
 
550
                                        &df2_path, &df_len, fileid))
 
551
                goto error;
 
552
 
 
553
        if (send_uicc_read_file_transparent(sd->client, sd->app_id, sd->client_id,
 
554
                                                fileid, df_len, mf_path,
 
555
                                                df1_path, df2_path,
 
556
                                                uicc_read_file_transp_resp_cb,
 
557
                                                cbd, g_free))
 
558
                return;
 
559
 
 
560
error:
 
561
        DBG("Read file transparent failed");
 
562
        CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
 
563
        g_free(cbd);
 
564
}
 
565
 
 
566
static void read_file_linear_resp(const GIsiMessage *msg, void *opaque)
 
567
{
 
568
        struct isi_cb_data *cbd = opaque;
 
569
        ofono_sim_read_cb_t cb = cbd->cb;
 
570
        GIsiSubBlockIter iter;
 
571
        uint8_t num_sb = 0;
 
572
        uint8_t *filedata = NULL;
 
573
        uint32_t filelen = 0;
 
574
 
 
575
        DBG("");
 
576
 
 
577
        if (!check_resp(msg, UICC_APPL_CMD_RESP, UICC_APPL_READ_LINEAR_FIXED))
 
578
                goto error;
 
579
 
 
580
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
581
                goto error;
 
582
 
 
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)) {
 
586
 
 
587
                uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
 
588
 
 
589
                DBG("Subblock %s", uicc_subblock_name(sb_id));
 
590
 
 
591
                if (sb_id != UICC_SB_FILE_DATA)
 
592
                        continue;
 
593
 
 
594
                if (!g_isi_sb_iter_get_dword(&iter, &filelen, 4))
 
595
                        goto error;
 
596
 
 
597
                if (!g_isi_sb_iter_get_struct(&iter, (void **) &filedata,
 
598
                                                filelen, 8))
 
599
                        goto error;
 
600
 
 
601
                DBG("Linear fixed EF read: 1st byte %02x, len %d", filedata[0],
 
602
                        filelen);
 
603
 
 
604
                CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
 
605
                return;
 
606
        }
 
607
 
 
608
error:
 
609
        CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
 
610
}
 
611
 
 
612
static gboolean send_uicc_read_file_linear(GIsiClient *client, uint8_t app_id,
 
613
                                                uint8_t client_id,
 
614
                                                int fileid, int record,
 
615
                                                int rec_length,
 
616
                                                unsigned char df_len,
 
617
                                                int mf_path, int df1_path,
 
618
                                                int df2_path,
 
619
                                                GIsiNotifyFunc notify,
 
620
                                                void *data,
 
621
                                                GDestroyNotify destroy)
 
622
{
 
623
        const uint8_t msg[] = {
 
624
                UICC_APPL_CMD_REQ,
 
625
                UICC_APPL_READ_LINEAR_FIXED,
 
626
                app_id,
 
627
                UICC_SESSION_ID_NOT_USED,
 
628
                0, 0,           /* Filler */
 
629
                3,              /* Number of subblocks */
 
630
                ISI_16BIT(UICC_SB_CLIENT),
 
631
                ISI_16BIT(8),   /*Subblock length */
 
632
                0, 0, 0,        /* Filler */
 
633
                client_id,
 
634
                ISI_16BIT(UICC_SB_LINEAR_FIXED),
 
635
                ISI_16BIT(8),   /*Subblock length */
 
636
                record,
 
637
                0,              /* Record offset */
 
638
                rec_length & 0xff,      /*Data amount (0=all)*/
 
639
                0,
 
640
                ISI_16BIT(UICC_SB_APPL_PATH),
 
641
                ISI_16BIT(16),  /* Subblock length */
 
642
                ISI_16BIT(fileid),
 
643
                uicc_get_sfi(fileid),   /* Elementary file short file id */
 
644
                0,              /* Filler */
 
645
                df_len,
 
646
                0,
 
647
                ISI_16BIT(mf_path),
 
648
                ISI_16BIT(df1_path),
 
649
                ISI_16BIT(df2_path),
 
650
        };
 
651
 
 
652
        return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
 
653
}
 
654
 
 
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,
 
657
                                        void *data)
 
658
{
 
659
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
660
        struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
 
661
        int mf_path = 0;
 
662
        int df1_path = 0;
 
663
        int df2_path = 0;
 
664
        uint8_t df_len = 0;
 
665
 
 
666
        if (!sd || !cbd)
 
667
                goto error;
 
668
 
 
669
        DBG("File ID=%04X, record %d, client %d AID %d", fileid, record,
 
670
                sd->client_id, sd->app_id);
 
671
 
 
672
        if (!uicc_get_fileid_path(sd, &mf_path, &df1_path, &df2_path,
 
673
                                        &df_len, fileid))
 
674
                goto error;
 
675
 
 
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))
 
680
                return;
 
681
 
 
682
error:
 
683
        CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
 
684
        g_free(cbd);
 
685
}
 
686
 
 
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)
 
690
{
 
691
        DBG("Not implemented");
 
692
        CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
 
693
}
 
694
 
 
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)
 
699
{
 
700
        DBG("Not implemented");
 
701
        CALLBACK_WITH_FAILURE(cb, data);
 
702
}
 
703
 
 
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)
 
707
{
 
708
        DBG("Not implemented");
 
709
        CALLBACK_WITH_FAILURE(cb, data);
 
710
}
 
711
 
 
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)
 
715
{
 
716
        DBG("Not implemented");
 
717
        CALLBACK_WITH_FAILURE(cb, data);
 
718
}
 
719
 
 
720
static gboolean decode_imsi(uint8_t *data, int len, char *imsi)
 
721
{
 
722
        int i = 1; /* Skip first byte, the length field */
 
723
        int j = 0;
 
724
 
 
725
        if (data == NULL || len == 0)
 
726
                return FALSE;
 
727
 
 
728
        if (data[0] != 8 || data[0] > len)
 
729
                return FALSE;
 
730
 
 
731
        /* Ignore low-order semi-octet of the first byte */
 
732
        imsi[j] = ((data[i] & 0xF0) >> 4) + '0';
 
733
 
 
734
        for (i++, j++; i - 1 < data[0] && j < MAX_IMSI_LENGTH; i++) {
 
735
                char nibble;
 
736
 
 
737
                imsi[j++] = (data[i] & 0x0F) + '0';
 
738
                nibble = (data[i] & 0xF0) >> 4;
 
739
 
 
740
                if (nibble != 0x0F)
 
741
                        imsi[j++] = nibble + '0';
 
742
        }
 
743
 
 
744
        imsi[j] = '\0';
 
745
        return TRUE;
 
746
}
 
747
 
 
748
static void uicc_read_imsi_resp(const GIsiMessage *msg, void *opaque)
 
749
{
 
750
        struct isi_cb_data *cbd = opaque;
 
751
        ofono_sim_imsi_cb_t cb = cbd->cb;
 
752
        GIsiSubBlockIter iter;
 
753
 
 
754
        uint32_t filelen = 0;
 
755
        uint8_t *filedata = NULL;
 
756
        uint8_t num_sb = 0;
 
757
 
 
758
        char imsi[MAX_IMSI_LENGTH + 1] = { 0 };
 
759
 
 
760
        DBG("");
 
761
 
 
762
        if (!check_resp(msg, UICC_APPL_CMD_RESP, UICC_APPL_READ_TRANSPARENT))
 
763
                goto error;
 
764
 
 
765
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
766
                goto error;
 
767
 
 
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)) {
 
771
 
 
772
                int sb_id = g_isi_sb_iter_get_id(&iter);
 
773
 
 
774
                DBG("Subblock %s", uicc_subblock_name(sb_id));
 
775
 
 
776
                if (sb_id != UICC_SB_FILE_DATA)
 
777
                        continue;
 
778
 
 
779
                if (!g_isi_sb_iter_get_dword(&iter, &filelen, 4))
 
780
                        goto error;
 
781
 
 
782
                if (!g_isi_sb_iter_get_struct(&iter, (void **) &filedata,
 
783
                                                filelen, 8))
 
784
                        goto error;
 
785
 
 
786
                DBG("Transparent EF read: 1st byte %02x, len %d",
 
787
                        filedata[0], filelen);
 
788
 
 
789
                if (!decode_imsi(filedata, filelen, imsi))
 
790
                        goto error;
 
791
 
 
792
                DBG("IMSI %s", imsi);
 
793
                CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
 
794
                return;
 
795
        }
 
796
 
 
797
error:
 
798
        CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
 
799
}
 
800
 
 
801
static void uicc_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
 
802
                                void *data)
 
803
{
 
804
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
805
        struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
 
806
 
 
807
        int mf_path = 0;
 
808
        int df1_path = 0;
 
809
        int df2_path = 0;
 
810
        uint8_t df_len = 0;
 
811
 
 
812
        if (!cbd)
 
813
                goto error;
 
814
 
 
815
        DBG("Client %d, AID %d", sd->client_id, sd->app_id);
 
816
 
 
817
        if (!uicc_get_fileid_path(sd, &mf_path, &df1_path, &df2_path, &df_len,
 
818
                                        SIM_EFIMSI_FILEID))
 
819
                goto error;
 
820
 
 
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,
 
824
                                                uicc_read_imsi_resp,
 
825
                                                cbd, g_free))
 
826
                return;
 
827
 
 
828
error:
 
829
        CALLBACK_WITH_FAILURE(cb, NULL, data);
 
830
        g_free(cbd);
 
831
}
 
832
 
 
833
static void uicc_query_passwd_state_resp(const GIsiMessage *msg, void *opaque)
 
834
{
 
835
        struct isi_cb_data *cbd = opaque;
 
836
        ofono_sim_passwd_cb_t cb = cbd->cb;
 
837
        uint8_t type;
 
838
        uint8_t cause;
 
839
 
 
840
        DBG("");
 
841
 
 
842
        if (g_isi_msg_error(msg) < 0) {
 
843
                DBG("Error: %s", g_isi_msg_strerror(msg));
 
844
                goto error;
 
845
        }
 
846
 
 
847
        if (g_isi_msg_id(msg) != UICC_PIN_RESP) {
 
848
                DBG("Unexpected msg: %s", sim_message_id_name(g_isi_msg_id(msg)));
 
849
                goto error;
 
850
        }
 
851
 
 
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);
 
856
                goto error;
 
857
        }
 
858
 
 
859
        if (!g_isi_msg_data_get_byte(msg, 1, &cause))
 
860
                goto error;
 
861
 
 
862
        DBG("Status: %d %s", cause, uicc_status_name(cause));
 
863
 
 
864
        if (cause == UICC_STATUS_PIN_DISABLED) {
 
865
                CALLBACK_WITH_SUCCESS(cb, OFONO_SIM_PASSWORD_NONE, cbd->data);
 
866
                return;
 
867
        }
 
868
 
 
869
        DBG("Request failed or not implemented: %s", uicc_status_name(cause));
 
870
 
 
871
error:
 
872
        CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
 
873
}
 
874
 
 
875
static void uicc_query_passwd_state(struct ofono_sim *sim,
 
876
                                        ofono_sim_passwd_cb_t cb, void *data)
 
877
{
 
878
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
879
        struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
 
880
 
 
881
        const uint8_t req[] = {
 
882
                UICC_PIN_REQ,
 
883
                UICC_PIN_PROMPT_VERIFY,
 
884
                sd->app_id,
 
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 */
 
891
        };
 
892
 
 
893
        DBG("");
 
894
 
 
895
        if (g_isi_client_send(sd->client, req, sizeof(req),
 
896
                                uicc_query_passwd_state_resp, cbd, g_free))
 
897
                return;
 
898
 
 
899
        CALLBACK_WITH_FAILURE(cb, -1, data);
 
900
        g_free(cbd);
 
901
}
 
902
 
 
903
static void uicc_send_passwd(struct ofono_sim *sim, const char *passwd,
 
904
                                ofono_sim_lock_unlock_cb_t cb, void *data)
 
905
{
 
906
        DBG("Not implemented");
 
907
        CALLBACK_WITH_FAILURE(cb, data);
 
908
}
 
909
 
 
910
static void uicc_query_pin_retries_resp(const GIsiMessage *msg, void *opaque)
 
911
{
 
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;
 
916
 
 
917
        uint8_t num_sb = 0;
 
918
        uint8_t pins = 0;
 
919
        uint8_t pina = 0;
 
920
        uint8_t puka = 0;
 
921
 
 
922
        DBG("");
 
923
 
 
924
        if (!check_resp(msg, UICC_PIN_RESP, UICC_PIN_INFO))
 
925
                goto error;
 
926
 
 
927
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
928
                goto error;
 
929
 
 
930
        DBG("Subblock count %d", num_sb);
 
931
 
 
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)) {
 
935
 
 
936
                uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
 
937
 
 
938
                DBG("Sub-block %s", uicc_subblock_name(sb_id));
 
939
 
 
940
                if (sb_id != UICC_SB_PIN_INFO)
 
941
                        continue;
 
942
 
 
943
                if (!g_isi_sb_iter_get_byte(&iter, &pins, 4))
 
944
                        goto error;
 
945
 
 
946
                if (!g_isi_sb_iter_get_byte(&iter, &pina, 5))
 
947
                        goto error;
 
948
 
 
949
                if (!g_isi_sb_iter_get_byte(&iter, &puka, 6))
 
950
                        goto error;
 
951
 
 
952
                DBG("PIN status %X PIN Attrib %d PUK attrib %d", pins,
 
953
                        pina, puka);
 
954
 
 
955
                retries[OFONO_SIM_PASSWORD_SIM_PIN] = pina;
 
956
                retries[OFONO_SIM_PASSWORD_SIM_PUK] = puka;
 
957
 
 
958
                CALLBACK_WITH_SUCCESS(cb, retries, cbd->data);
 
959
                return;
 
960
        }
 
961
 
 
962
error:
 
963
        CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
 
964
}
 
965
 
 
966
static void uicc_query_pin_retries(struct ofono_sim *sim,
 
967
                                        ofono_sim_pin_retries_cb_t cb,
 
968
                                        void *data)
 
969
{
 
970
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
971
        struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
 
972
 
 
973
        const uint8_t req[] = {
 
974
                UICC_PIN_REQ,
 
975
                UICC_PIN_INFO,
 
976
                sd->app_id,
 
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 */
 
983
        };
 
984
 
 
985
        DBG("");
 
986
 
 
987
        if (g_isi_client_send(sd->client, req, sizeof(req),
 
988
                                uicc_query_pin_retries_resp, cbd, g_free))
 
989
                return;
 
990
 
 
991
        CALLBACK_WITH_FAILURE(cb, NULL, data);
 
992
        g_free(cbd);
 
993
}
 
994
 
 
995
static void uicc_reset_passwd(struct ofono_sim *sim, const char *puk,
 
996
                                const char *passwd, ofono_sim_lock_unlock_cb_t cb,
 
997
                                void *data)
 
998
{
 
999
        DBG("Not implemented");
 
1000
        CALLBACK_WITH_FAILURE(cb, data);
 
1001
}
 
1002
 
 
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)
 
1007
{
 
1008
        DBG("Not implemented");
 
1009
        CALLBACK_WITH_FAILURE(cb, data);
 
1010
}
 
1011
 
 
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)
 
1015
{
 
1016
        DBG("Not implemented");
 
1017
        CALLBACK_WITH_FAILURE(cb, data);
 
1018
}
 
1019
 
 
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)
 
1023
{
 
1024
        DBG("Not implemented");
 
1025
        CALLBACK_WITH_FAILURE(cb, -1, data);
 
1026
}
 
1027
 
 
1028
static gboolean decode_fcp_pin_status(const GIsiSubBlockIter *iter, uint8_t read,
 
1029
                                        uint8_t *pin1, uint8_t *pin2)
 
1030
{
 
1031
        uint8_t do_len;
 
1032
        uint8_t len;
 
1033
        uint8_t tag;
 
1034
        uint8_t id;
 
1035
        uint8_t tag_pos;
 
1036
 
 
1037
        DBG("Decoding PIN status");
 
1038
 
 
1039
        if (!g_isi_sb_iter_get_byte(iter, &do_len, read))
 
1040
                return FALSE;
 
1041
 
 
1042
        tag_pos = read + 1 + do_len;
 
1043
 
 
1044
        if (!g_isi_sb_iter_get_byte(iter, &tag, tag_pos))
 
1045
                return FALSE;
 
1046
 
 
1047
        while (tag == 0x83) {
 
1048
 
 
1049
                if (!g_isi_sb_iter_get_byte(iter, &len, tag_pos + 1))
 
1050
                        return FALSE;
 
1051
 
 
1052
                if (!g_isi_sb_iter_get_byte(iter, &id, tag_pos + 2))
 
1053
                        return FALSE;
 
1054
 
 
1055
                tag_pos += 2 + len;
 
1056
 
 
1057
                if (!g_isi_sb_iter_get_byte(iter, &tag, tag_pos))
 
1058
                        return FALSE;
 
1059
 
 
1060
                DBG("PIN_len %d, PIN id %02x, PIN tag %02x", len, id, tag);
 
1061
 
 
1062
                if (id >= 0x01 && id <= 0x08)
 
1063
                        *pin1 = id;
 
1064
                else if (id >= 0x81 && id <= 0x88)
 
1065
                        *pin2 = id;
 
1066
        }
 
1067
        return TRUE;
 
1068
}
 
1069
 
 
1070
static gboolean decode_fci_sb(const GIsiSubBlockIter *iter, int app_type,
 
1071
                                uint8_t *pin1, uint8_t *pin2)
 
1072
{
 
1073
        uint8_t fcp = 0;
 
1074
        uint8_t fcp_len = 0;
 
1075
        uint8_t read = 0;
 
1076
        uint8_t item_len = 0;
 
1077
 
 
1078
        DBG("Decoding UICC_SB_FCI");
 
1079
 
 
1080
        if (app_type != UICC_APPL_TYPE_UICC_USIM)
 
1081
                return FALSE;
 
1082
 
 
1083
        if (!g_isi_sb_iter_get_byte(iter, &fcp, 8))
 
1084
                return FALSE;
 
1085
 
 
1086
        if (fcp != FCP_TEMPLATE)
 
1087
                return FALSE;
 
1088
 
 
1089
        if (!g_isi_sb_iter_get_byte(iter, &fcp_len, 9))
 
1090
                return FALSE;
 
1091
 
 
1092
        for (read = 0; read < fcp_len; read += item_len + 2) {
 
1093
                uint8_t id;
 
1094
 
 
1095
                if (!g_isi_sb_iter_get_byte(iter, &id, read + 10))
 
1096
                        return FALSE;
 
1097
 
 
1098
                if (!g_isi_sb_iter_get_byte(iter, &item_len, read + 11))
 
1099
                        return FALSE;
 
1100
 
 
1101
                if (id != FCP_PIN_STATUS)
 
1102
                        continue;
 
1103
 
 
1104
                if (!decode_fcp_pin_status(iter, read + 13, pin1, pin2))
 
1105
                        return FALSE;
 
1106
        }
 
1107
        return TRUE;
 
1108
}
 
1109
 
 
1110
static gboolean decode_chv_sb(const GIsiSubBlockIter *iter, int app_type,
 
1111
                                uint8_t *pin1, uint8_t *pin2)
 
1112
{
 
1113
        uint8_t chv_id = 0;
 
1114
        uint8_t pin_id = 0;
 
1115
 
 
1116
        DBG("Decoding UICC_SB_CHV");
 
1117
 
 
1118
        if (app_type != UICC_APPL_TYPE_ICC_SIM)
 
1119
                return FALSE;
 
1120
 
 
1121
        if (!g_isi_sb_iter_get_byte(iter, &chv_id, 4))
 
1122
                return FALSE;
 
1123
 
 
1124
        if (!g_isi_sb_iter_get_byte(iter, &pin_id, 5))
 
1125
                return FALSE;
 
1126
 
 
1127
        switch (chv_id) {
 
1128
        case 1:
 
1129
                *pin1 = pin_id;
 
1130
                break;
 
1131
 
 
1132
        case 2:
 
1133
                *pin2 = pin_id;
 
1134
                break;
 
1135
 
 
1136
        default:
 
1137
                return FALSE;
 
1138
        }
 
1139
 
 
1140
        DBG("CHV=%d, pin_id=%2x, PIN1 %02x, PIN2 %02x", chv_id, pin_id, *pin1,
 
1141
                *pin2);
 
1142
 
 
1143
        return TRUE;
 
1144
}
 
1145
 
 
1146
static void uicc_application_activate_resp(const GIsiMessage *msg, void *opaque)
 
1147
{
 
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;
 
1152
 
 
1153
        DBG("");
 
1154
 
 
1155
        if (g_isi_msg_error(msg) < 0) {
 
1156
                DBG("Error: %s", g_isi_msg_strerror(msg));
 
1157
                return;
 
1158
        }
 
1159
 
 
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)));
 
1163
                return;
 
1164
        }
 
1165
 
 
1166
        if (!g_isi_msg_data_get_byte(msg, 1, &cause))
 
1167
                return;
 
1168
 
 
1169
        if (cause != UICC_STATUS_OK && cause != UICC_STATUS_APPL_ACTIVE) {
 
1170
                DBG("TODO: handle application activation");
 
1171
                return;
 
1172
        }
 
1173
 
 
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;
 
1178
 
 
1179
                DBG("UICC application activated");
 
1180
 
 
1181
                ofono_sim_inserted_notify(sim, TRUE);
 
1182
                ofono_sim_register(sim);
 
1183
 
 
1184
                g_hash_table_remove_all(sd->app_table);
 
1185
        }
 
1186
 
 
1187
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
1188
                return;
 
1189
 
 
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)) {
 
1193
 
 
1194
                uint8_t sb_id = g_isi_sb_iter_get_id(&iter);
 
1195
 
 
1196
                DBG("Subblock %s", uicc_subblock_name(sb_id));
 
1197
 
 
1198
                switch (sb_id) {
 
1199
                case UICC_SB_CLIENT:
 
1200
 
 
1201
                        if (!g_isi_sb_iter_get_byte(&iter, &sd->client_id, 7))
 
1202
                                return;
 
1203
 
 
1204
                        DBG("Client id %d", sd->client_id);
 
1205
                        break;
 
1206
 
 
1207
                case UICC_SB_FCI:
 
1208
 
 
1209
                        if (!decode_fci_sb(&iter, sd->app_type, &sd->pin1_id,
 
1210
                                                &sd->pin2_id))
 
1211
                                return;
 
1212
 
 
1213
                        DBG("PIN1 %02x, PIN2 %02x", sd->pin1_id, sd->pin2_id);
 
1214
                        break;
 
1215
 
 
1216
                case UICC_SB_CHV:
 
1217
 
 
1218
                        if (!decode_chv_sb(&iter, sd->app_type, &sd->pin1_id,
 
1219
                                                &sd->pin2_id))
 
1220
                                return;
 
1221
 
 
1222
                        DBG("PIN1 %02x, PIN2 %02x", sd->pin1_id, sd->pin2_id);
 
1223
                        break;
 
1224
 
 
1225
                default:
 
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));
 
1229
                        break;
 
1230
                }
 
1231
        }
 
1232
}
 
1233
 
 
1234
static gboolean send_application_activate_req(GIsiClient *client,
 
1235
                                                uint8_t app_type,
 
1236
                                                uint8_t app_id,
 
1237
                                                GIsiNotifyFunc notify,
 
1238
                                                void *data,
 
1239
                                                GDestroyNotify destroy)
 
1240
{
 
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 */
 
1247
                0, 0,           /* Filler */
 
1248
                app_type,
 
1249
                app_id,
 
1250
                ISI_16BIT(UICC_SB_APPL_INFO),
 
1251
                ISI_16BIT(8),   /* Subblock length */
 
1252
                0, 0, 0,        /* Filler */
 
1253
                /*
 
1254
                 * Next field indicates whether the application
 
1255
                 * initialization procedure will follow the activation
 
1256
                 * or not
 
1257
                 */
 
1258
                UICC_APPL_START_UP_INIT_PROC,
 
1259
        };
 
1260
 
 
1261
        DBG("App type %d, AID %d", app_type, app_id);
 
1262
 
 
1263
        return g_isi_client_send(client, msg, sizeof(msg), notify, data, destroy);
 
1264
}
 
1265
 
 
1266
static void uicc_application_list_resp(const GIsiMessage *msg, void *data)
 
1267
{
 
1268
        struct ofono_sim *sim = data;
 
1269
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
1270
        GIsiSubBlockIter iter;
 
1271
        uint8_t num_sb;
 
1272
        struct uicc_sim_application *sim_app;
 
1273
 
 
1274
        /* Throw away old app table */
 
1275
        g_hash_table_remove_all(sd->app_table);
 
1276
 
 
1277
        if (!check_resp(msg, UICC_APPLICATION_RESP, UICC_APPL_LIST))
 
1278
                goto error;
 
1279
 
 
1280
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
1281
                goto error;
 
1282
 
 
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)) {
 
1287
                uint8_t app_type;
 
1288
                uint8_t app_id;
 
1289
                uint8_t app_status;
 
1290
                uint8_t app_len;
 
1291
 
 
1292
                if (g_isi_sb_iter_get_id(&iter) != UICC_SB_APPL_DATA_OBJECT)
 
1293
                        continue;
 
1294
 
 
1295
                if (!g_isi_sb_iter_get_byte(&iter, &app_type, 6))
 
1296
                        goto error;
 
1297
 
 
1298
                if (!g_isi_sb_iter_get_byte(&iter, &app_id, 7))
 
1299
                        goto error;
 
1300
 
 
1301
                if (!g_isi_sb_iter_get_byte(&iter, &app_status, 8))
 
1302
                        goto error;
 
1303
 
 
1304
                if (!g_isi_sb_iter_get_byte(&iter, &app_len, 9))
 
1305
                        goto error;
 
1306
 
 
1307
                if (app_type != UICC_APPL_TYPE_ICC_SIM &&
 
1308
                                app_type != UICC_APPL_TYPE_UICC_USIM)
 
1309
                        continue;
 
1310
 
 
1311
                sim_app = g_try_new0(struct uicc_sim_application, 1);
 
1312
                if (!sim_app) {
 
1313
                        DBG("out of memory!");
 
1314
                        goto error;
 
1315
                }
 
1316
 
 
1317
                sim_app->type = app_type;
 
1318
                sim_app->id = app_id;
 
1319
                sim_app->status = app_status;
 
1320
                sim_app->length = app_len;
 
1321
                sim_app->sim = sd;
 
1322
 
 
1323
                g_hash_table_replace(sd->app_table, &sim_app->id, sim_app);
 
1324
        }
 
1325
 
 
1326
        if (!sd->uicc_app_started) {
 
1327
                GHashTableIter app_iter;
 
1328
                struct uicc_sim_application *app;
 
1329
 
 
1330
                gpointer key;
 
1331
                gpointer value;
 
1332
 
 
1333
                g_hash_table_iter_init(&app_iter, sd->app_table);
 
1334
 
 
1335
                if (!g_hash_table_iter_next(&app_iter, &key, &value))
 
1336
                        return;
 
1337
 
 
1338
                app = value;
 
1339
                sd->trying_app_type = app->type;
 
1340
                sd->trying_app_id = app->id;
 
1341
 
 
1342
                g_hash_table_remove(sd->app_table, &app->id);
 
1343
 
 
1344
                if (!send_application_activate_req(sd->client, app->type, app->id,
 
1345
                                                uicc_application_activate_resp,
 
1346
                                                data, NULL)) {
 
1347
                        DBG("Failed to activate: 0x%02X (type=0x%02X)",
 
1348
                                app->id, app->type);
 
1349
                        return;
 
1350
                }
 
1351
        }
 
1352
        return;
 
1353
 
 
1354
error:
 
1355
        DBG("Decoding application list failed");
 
1356
 
 
1357
        g_isi_client_destroy(sd->client);
 
1358
        sd->client = NULL;
 
1359
 
 
1360
        ofono_sim_remove(sim);
 
1361
}
 
1362
 
 
1363
static void uicc_card_status_resp(const GIsiMessage *msg, void *data)
 
1364
{
 
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;
 
1369
        uint8_t num_sb = 0;
 
1370
 
 
1371
        DBG("");
 
1372
 
 
1373
        if (!sd->server_running)
 
1374
                return;
 
1375
 
 
1376
        if (!check_resp(msg, UICC_CARD_RESP, UICC_CARD_STATUS_GET))
 
1377
                goto error;
 
1378
 
 
1379
        if (!g_isi_msg_data_get_byte(msg, 1, &card_status))
 
1380
                goto error;
 
1381
 
 
1382
        if (!g_isi_msg_data_get_byte(msg, 5, &num_sb))
 
1383
                goto error;
 
1384
 
 
1385
        DBG("Subblock count %d", num_sb);
 
1386
 
 
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)) {
 
1390
 
 
1391
                if (g_isi_sb_iter_get_id(&iter) != UICC_SB_CARD_STATUS)
 
1392
                        continue;
 
1393
 
 
1394
                if (!g_isi_sb_iter_get_byte(&iter, &card_status, 7))
 
1395
                        goto error;
 
1396
 
 
1397
                DBG("card_status = 0x%X", card_status);
 
1398
 
 
1399
                /* Check if card is ready */
 
1400
                if (card_status == 0x21) {
 
1401
                        const uint8_t req[] = {
 
1402
                                UICC_APPLICATION_REQ,
 
1403
                                UICC_APPL_LIST,
 
1404
                                0,      /* Number of subblocks */
 
1405
                        };
 
1406
 
 
1407
                        DBG("card is ready");
 
1408
                        ofono_sim_inserted_notify(sim, TRUE);
 
1409
 
 
1410
                        if (g_isi_client_send(sd->client, req, sizeof(req),
 
1411
                                                uicc_application_list_resp,
 
1412
                                                data, NULL))
 
1413
                                return;
 
1414
 
 
1415
                        DBG("Failed to query application list");
 
1416
                        goto error;
 
1417
 
 
1418
                } else {
 
1419
                        DBG("card not ready");
 
1420
                        ofono_sim_inserted_notify(sim, FALSE);
 
1421
                        return;
 
1422
                }
 
1423
        }
 
1424
 
 
1425
error:
 
1426
        g_isi_client_destroy(sd->client);
 
1427
        sd->client = NULL;
 
1428
 
 
1429
        ofono_sim_remove(sim);
 
1430
}
 
1431
 
 
1432
static void uicc_card_status_req(struct ofono_sim *sim,
 
1433
                                        struct uicc_sim_data *sd)
 
1434
{
 
1435
        const uint8_t req[] = {
 
1436
                UICC_CARD_REQ,
 
1437
                UICC_CARD_STATUS_GET,
 
1438
                0,
 
1439
        };
 
1440
 
 
1441
        DBG("");
 
1442
 
 
1443
        if (g_isi_client_send(sd->client, req, sizeof(req),
 
1444
                                    uicc_card_status_resp, sim, NULL))
 
1445
                return;
 
1446
 
 
1447
        g_isi_client_destroy(sd->client);
 
1448
        sd->client = NULL;
 
1449
 
 
1450
        ofono_sim_remove(sim);
 
1451
}
 
1452
 
 
1453
static void uicc_card_ind_cb(const GIsiMessage *msg, void *data)
 
1454
{
 
1455
        struct ofono_sim *sim = data;
 
1456
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
1457
 
 
1458
        DBG("");
 
1459
 
 
1460
        if (g_isi_msg_id(msg) != UICC_CARD_IND)
 
1461
                return;
 
1462
 
 
1463
        /* We're not interested in card indications if server isn't running */
 
1464
        if (!sd->server_running)
 
1465
                return;
 
1466
 
 
1467
        /* Request card status */
 
1468
        uicc_card_status_req(sim, sd);
 
1469
}
 
1470
 
 
1471
static void uicc_status_resp(const GIsiMessage *msg, void *data)
 
1472
{
 
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;
 
1477
 
 
1478
        if (!check_resp(msg, UICC_RESP, UICC_STATUS_GET))
 
1479
                goto error;
 
1480
 
 
1481
        if (g_isi_msg_error(msg) < 0)
 
1482
                goto error;
 
1483
 
 
1484
        if (!g_isi_msg_data_get_byte(msg, 1, &status) ||
 
1485
                        !g_isi_msg_data_get_byte(msg, 3, &server_status))
 
1486
                goto error;
 
1487
 
 
1488
        DBG("status=0x%X, server_status=0x%X", status, server_status);
 
1489
 
 
1490
        if (status == UICC_STATUS_OK &&
 
1491
                        server_status == UICC_STATUS_START_UP_COMPLETED) {
 
1492
                DBG("server is up!");
 
1493
                server_running = TRUE;
 
1494
        }
 
1495
 
 
1496
 
 
1497
        if (!server_running) {
 
1498
                sd->server_running = FALSE;
 
1499
 
 
1500
                /* TODO: Remove SIM etc... */
 
1501
                return;
 
1502
        }
 
1503
 
 
1504
        if (sd->server_running && server_running) {
 
1505
                DBG("Server status didn't change...");
 
1506
                return;
 
1507
        }
 
1508
 
 
1509
        /* Server is running */
 
1510
        sd->server_running = TRUE;
 
1511
 
 
1512
        /* Request card status */
 
1513
        uicc_card_status_req(sim, sd);
 
1514
        return;
 
1515
 
 
1516
error:
 
1517
        g_isi_client_destroy(sd->client);
 
1518
        sd->client = NULL;
 
1519
 
 
1520
        ofono_sim_remove(sim);
 
1521
}
 
1522
 
 
1523
static void uicc_ind_cb(const GIsiMessage *msg, void *data)
 
1524
{
 
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 };
 
1528
 
 
1529
        int msg_id = g_isi_msg_id(msg);
 
1530
        DBG("%s", uicc_message_id_name(msg_id));
 
1531
 
 
1532
        if (msg_id != UICC_IND)
 
1533
                return;
 
1534
 
 
1535
        /* Request status */
 
1536
        if (g_isi_client_send(sd->client, req, sizeof(req), uicc_status_resp,
 
1537
                                data, NULL))
 
1538
                return;
 
1539
 
 
1540
        DBG("status request failed!");
 
1541
 
 
1542
        g_isi_client_destroy(sd->client);
 
1543
        sd->client = NULL;
 
1544
        ofono_sim_remove(sim);
 
1545
}
 
1546
 
 
1547
static void uicc_reachable_cb(const GIsiMessage *msg, void *data)
 
1548
{
 
1549
        struct ofono_sim *sim = data;
 
1550
        struct uicc_sim_data *sd = ofono_sim_get_data(sim);
 
1551
 
 
1552
        const uint8_t req[] = {
 
1553
                UICC_REQ,
 
1554
                UICC_STATUS_GET,
 
1555
                0,      /* Number of Sub Blocks (only from version 4.0) */
 
1556
        };
 
1557
 
 
1558
        ISI_RESOURCE_DBG(msg);
 
1559
 
 
1560
        if (g_isi_msg_error(msg) < 0)
 
1561
                goto error;
 
1562
 
 
1563
        sd->version.major = g_isi_msg_version_major(msg);
 
1564
        sd->version.minor = g_isi_msg_version_minor(msg);
 
1565
 
 
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,
 
1569
                                        sim);
 
1570
 
 
1571
        /* Update status */
 
1572
        if (g_isi_client_send(sd->client, req,
 
1573
                                sizeof(req) - ((sd->version.major < 4) ? 1 : 0),
 
1574
                                uicc_status_resp, data, NULL))
 
1575
                return;
 
1576
 
 
1577
error:
 
1578
        g_isi_client_destroy(sd->client);
 
1579
        sd->client = NULL;
 
1580
 
 
1581
        ofono_sim_remove(sim);
 
1582
}
 
1583
 
 
1584
static void sim_app_destroy(gpointer p)
 
1585
{
 
1586
        struct uicc_sim_application *app = p;
 
1587
        if (!app)
 
1588
                return;
 
1589
 
 
1590
        g_free(app);
 
1591
}
 
1592
 
 
1593
static int uicc_sim_probe(struct ofono_sim *sim, unsigned int vendor,
 
1594
                                        void *user)
 
1595
{
 
1596
        GIsiModem *modem = user;
 
1597
        struct uicc_sim_data *sd;
 
1598
 
 
1599
        sd = g_try_new0(struct uicc_sim_data, 1);
 
1600
        if (sd == NULL)
 
1601
                return -ENOMEM;
 
1602
 
 
1603
        /* Create hash table for the UICC applications */
 
1604
        sd->app_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
 
1605
                                                sim_app_destroy);
 
1606
        if (sd->app_table == NULL) {
 
1607
                g_free(sd);
 
1608
                return -ENOMEM;
 
1609
        }
 
1610
 
 
1611
        sd->client = g_isi_client_create(modem, PN_UICC);
 
1612
        if (sd->client == NULL) {
 
1613
                g_hash_table_destroy(sd->app_table);
 
1614
                g_free(sd);
 
1615
                return -ENOMEM;
 
1616
        }
 
1617
 
 
1618
        g_hash_table_insert(g_modems, g_isi_client_modem(sd->client), sim);
 
1619
 
 
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);
 
1625
 
 
1626
        g_isi_client_verify(sd->client, uicc_reachable_cb, sim, NULL);
 
1627
 
 
1628
        return 0;
 
1629
}
 
1630
 
 
1631
static void uicc_sim_remove(struct ofono_sim *sim)
 
1632
{
 
1633
        struct uicc_sim_data *data = ofono_sim_get_data(sim);
 
1634
 
 
1635
        ofono_sim_set_data(sim, NULL);
 
1636
 
 
1637
        if (data == NULL)
 
1638
                return;
 
1639
 
 
1640
        g_hash_table_remove(g_modems, g_isi_client_modem(data->client));
 
1641
 
 
1642
        g_hash_table_destroy(data->app_table);
 
1643
        g_isi_client_destroy(data->client);
 
1644
        g_free(data);
 
1645
}
 
1646
 
 
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,
 
1664
        .lock                   = uicc_lock,
 
1665
        .query_locked           = uicc_query_locked,
 
1666
};
 
1667
 
 
1668
void isi_uicc_init(void)
 
1669
{
 
1670
        g_modems = g_hash_table_new(g_direct_hash, g_direct_equal);
 
1671
        ofono_sim_driver_register(&driver);
 
1672
}
 
1673
 
 
1674
void isi_uicc_exit(void)
 
1675
{
 
1676
        g_hash_table_destroy(g_modems);
 
1677
        ofono_sim_driver_unregister(&driver);
 
1678
}
 
1679
 
 
1680
gboolean isi_uicc_properties(GIsiModem *modem, int *app_id, int *app_type,
 
1681
                                int *client_id)
 
1682
{
 
1683
        struct ofono_sim *sim;
 
1684
        struct uicc_sim_data *sd;
 
1685
 
 
1686
        sim = g_hash_table_lookup(g_modems, modem);
 
1687
        if (sim == NULL)
 
1688
                return FALSE;
 
1689
 
 
1690
        sd = ofono_sim_get_data(sim);
 
1691
        if (sd == NULL)
 
1692
                return FALSE;
 
1693
 
 
1694
        if (app_id != NULL)
 
1695
                *app_id = sd->app_id;
 
1696
 
 
1697
        if (app_type != NULL)
 
1698
                *app_type = sd->app_type;
 
1699
 
 
1700
        if (client_id != NULL)
 
1701
                *client_id = sd->client_id;
 
1702
 
 
1703
        return TRUE;
 
1704
}