~rsalveti/phablet-extras/ofono-imei-revision

« back to all changes in this revision

Viewing changes to drivers/qmimodem/sim.c

  • Committer: Stéphane Graber
  • Date: 2013-01-28 16:24:35 UTC
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: stgraber@ubuntu.com-20130128162435-oz7212z6jz68ri1c
Tags: upstream-1.12
Import upstream version 1.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  oFono - Open Source Telephony
 
4
 *
 
5
 *  Copyright (C) 2008-2012  Intel Corporation. All rights reserved.
 
6
 *
 
7
 *  This program is free software; you can redistribute it and/or modify
 
8
 *  it under the terms of the GNU General Public License version 2 as
 
9
 *  published by the Free Software Foundation.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 *
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include <config.h>
 
24
#endif
 
25
 
 
26
#include <string.h>
 
27
 
 
28
#include <ofono/log.h>
 
29
#include <ofono/modem.h>
 
30
#include <ofono/sim.h>
 
31
 
 
32
#include "qmi.h"
 
33
#include "uim.h"
 
34
 
 
35
#include "qmimodem.h"
 
36
#include "simutil.h"
 
37
 
 
38
#define EF_STATUS_INVALIDATED 0
 
39
#define EF_STATUS_VALID 1
 
40
 
 
41
struct sim_data {
 
42
        struct qmi_service *uim;
 
43
        uint32_t event_mask;
 
44
        uint8_t card_state;
 
45
        uint8_t app_type;
 
46
        uint8_t passwd_state;
 
47
        int retries[OFONO_SIM_PASSWORD_INVALID];
 
48
};
 
49
 
 
50
static int create_fileid_data(uint8_t app_type, int fileid,
 
51
                                        const unsigned char *path,
 
52
                                        unsigned int path_len,
 
53
                                        unsigned char *fileid_data)
 
54
{
 
55
        unsigned char db_path[6];
 
56
        unsigned int len;
 
57
 
 
58
        if (path_len > 0) {
 
59
                memcpy(db_path, path, path_len);
 
60
                len = path_len;
 
61
        } else {
 
62
                switch (app_type) {
 
63
                case 0x01:      /* SIM card */
 
64
                        len = sim_ef_db_get_path_2g(fileid, db_path);
 
65
                        break;
 
66
                case 0x02:      /* USIM application */
 
67
                        len = sim_ef_db_get_path_3g(fileid, db_path);
 
68
                        break;
 
69
                default:
 
70
                        len = 0;
 
71
                        break;
 
72
                }
 
73
        }
 
74
 
 
75
        /* Minimum length of path is 2 bytes */
 
76
        if (len < 2)
 
77
                return -1;
 
78
 
 
79
        fileid_data[0] = fileid & 0xff;
 
80
        fileid_data[1] = (fileid & 0xff00) >> 8;
 
81
        fileid_data[2] = len;
 
82
        fileid_data[3] = db_path[1];
 
83
        fileid_data[4] = db_path[0];
 
84
        fileid_data[5] = db_path[3];
 
85
        fileid_data[6] = db_path[2];
 
86
        fileid_data[7] = db_path[5];
 
87
        fileid_data[8] = db_path[4];
 
88
 
 
89
        return len + 3;
 
90
}
 
91
 
 
92
static void get_file_attributes_cb(struct qmi_result *result, void *user_data)
 
93
{
 
94
        struct cb_data *cbd = user_data;
 
95
        ofono_sim_file_info_cb_t cb = cbd->cb;
 
96
        struct sim_data *data = ofono_sim_get_data(cbd->user);
 
97
        const struct qmi_uim_file_attributes *attr;
 
98
        uint16_t len, raw_len;
 
99
        int flen, rlen, str;
 
100
        unsigned char access[3];
 
101
        unsigned char file_status;
 
102
        gboolean ok;
 
103
 
 
104
        DBG("");
 
105
 
 
106
        if (qmi_result_set_error(result, NULL))
 
107
                goto error;
 
108
 
 
109
        attr = qmi_result_get(result, 0x11, &len);
 
110
        if (!attr)
 
111
                goto error;
 
112
 
 
113
        raw_len = GUINT16_FROM_LE(attr->raw_len);
 
114
 
 
115
        switch (data->app_type) {
 
116
        case 0x01:      /* SIM card */
 
117
                ok = sim_parse_2g_get_response(attr->raw_value, raw_len,
 
118
                                &flen, &rlen, &str, access, &file_status);
 
119
                break;
 
120
        case 0x02:      /* USIM application */
 
121
                ok = sim_parse_3g_get_response(attr->raw_value, raw_len,
 
122
                                         &flen, &rlen, &str, access, NULL);
 
123
                file_status = EF_STATUS_VALID;
 
124
                break;
 
125
        default:
 
126
                ok = FALSE;
 
127
                break;
 
128
        }
 
129
 
 
130
        if (ok) {
 
131
                CALLBACK_WITH_SUCCESS(cb, flen, str, rlen, access,
 
132
                                                file_status, cbd->data);
 
133
                return;
 
134
        }
 
135
 
 
136
error:
 
137
        CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
 
138
                                        EF_STATUS_INVALIDATED, cbd->data);
 
139
}
 
140
 
 
141
static void qmi_read_attributes(struct ofono_sim *sim, int fileid,
 
142
                                const unsigned char *path,
 
143
                                unsigned int path_len,
 
144
                                ofono_sim_file_info_cb_t cb, void *user_data)
 
145
{
 
146
        struct sim_data *data = ofono_sim_get_data(sim);
 
147
        struct cb_data *cbd = cb_data_new(cb, user_data);
 
148
        unsigned char aid_data[2] = { 0x06, 0x00 };
 
149
        unsigned char fileid_data[9];
 
150
        int fileid_len;
 
151
        struct qmi_param *param;
 
152
 
 
153
        DBG("file id 0x%04x path len %d", fileid, path_len);
 
154
 
 
155
        cbd->user = sim;
 
156
 
 
157
        fileid_len = create_fileid_data(data->app_type, fileid,
 
158
                                                path, path_len, fileid_data);
 
159
        if (fileid_len < 0)
 
160
                goto error;
 
161
 
 
162
        param = qmi_param_new();
 
163
        if (!param)
 
164
                goto error;
 
165
 
 
166
        qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
 
167
        qmi_param_append(param, 0x02, fileid_len, fileid_data);
 
168
 
 
169
        if (qmi_service_send(data->uim, QMI_UIM_GET_FILE_ATTRIBUTES, param,
 
170
                                get_file_attributes_cb, cbd, g_free) > 0)
 
171
                return;
 
172
 
 
173
        qmi_param_free(param);
 
174
 
 
175
error:
 
176
        CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
 
177
                                        EF_STATUS_INVALIDATED, cbd->data);
 
178
 
 
179
        g_free(cbd);
 
180
}
 
181
 
 
182
static void read_generic_cb(struct qmi_result *result, void *user_data)
 
183
{
 
184
        struct cb_data *cbd = user_data;
 
185
        ofono_sim_read_cb_t cb = cbd->cb;
 
186
        const unsigned char *content;
 
187
        uint16_t len;
 
188
 
 
189
        DBG("");
 
190
 
 
191
        if (qmi_result_set_error(result, NULL)) {
 
192
                CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
 
193
                return;
 
194
        }
 
195
 
 
196
        content = qmi_result_get(result, 0x11, &len);
 
197
        if (!content) {
 
198
                CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
 
199
                return;
 
200
        }
 
201
 
 
202
        CALLBACK_WITH_SUCCESS(cb, content + 2, len - 2, cbd->data);
 
203
}
 
204
 
 
205
static void qmi_read_transparent(struct ofono_sim *sim,
 
206
                                int fileid, int start, int length,
 
207
                                const unsigned char *path,
 
208
                                unsigned int path_len,
 
209
                                ofono_sim_read_cb_t cb, void *user_data)
 
210
{
 
211
        struct sim_data *data = ofono_sim_get_data(sim);
 
212
        struct cb_data *cbd = cb_data_new(cb, user_data);
 
213
        unsigned char aid_data[2] = { 0x06, 0x00 };
 
214
        unsigned char read_data[4];
 
215
        unsigned char fileid_data[9];
 
216
        int fileid_len;
 
217
        struct qmi_param *param;
 
218
 
 
219
        DBG("file id 0x%04x path len %d", fileid, path_len);
 
220
 
 
221
        fileid_len = create_fileid_data(data->app_type, fileid,
 
222
                                                path, path_len, fileid_data);
 
223
        if (fileid_len < 0)
 
224
                goto error;
 
225
 
 
226
        read_data[0] = start & 0xff;
 
227
        read_data[1] = (start & 0xff00) >> 8;
 
228
        read_data[2] = length & 0xff;
 
229
        read_data[3] = (length & 0xff00) >> 8;
 
230
 
 
231
        param = qmi_param_new();
 
232
        if (!param)
 
233
                goto error;
 
234
 
 
235
        qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
 
236
        qmi_param_append(param, 0x02, fileid_len, fileid_data);
 
237
        qmi_param_append(param, 0x03, sizeof(read_data), read_data);
 
238
 
 
239
        if (qmi_service_send(data->uim, QMI_UIM_READ_TRANSPARENT, param,
 
240
                                        read_generic_cb, cbd, g_free) > 0)
 
241
                return;
 
242
 
 
243
        qmi_param_free(param);
 
244
 
 
245
error:
 
246
        CALLBACK_WITH_FAILURE(cb, NULL, 0, user_data);
 
247
 
 
248
        g_free(cbd);
 
249
}
 
250
 
 
251
static void qmi_read_record(struct ofono_sim *sim,
 
252
                                int fileid, int record, int length,
 
253
                                const unsigned char *path,
 
254
                                unsigned int path_len,
 
255
                                ofono_sim_read_cb_t cb, void *user_data)
 
256
{
 
257
        struct sim_data *data = ofono_sim_get_data(sim);
 
258
        struct cb_data *cbd = cb_data_new(cb, user_data);
 
259
        unsigned char aid_data[2] = { 0x06, 0x00 };
 
260
        unsigned char read_data[4];
 
261
        unsigned char fileid_data[9];
 
262
        int fileid_len;
 
263
        struct qmi_param *param;
 
264
 
 
265
        DBG("file id 0x%04x path len %d", fileid, path_len);
 
266
 
 
267
        fileid_len = create_fileid_data(data->app_type, fileid,
 
268
                                                path, path_len, fileid_data);
 
269
        if (fileid_len < 0)
 
270
                goto error;
 
271
 
 
272
        read_data[0] = record & 0xff;
 
273
        read_data[1] = (record & 0xff00) >> 8;
 
274
        read_data[2] = length & 0xff;
 
275
        read_data[3] = (length & 0xff00) >> 8;
 
276
 
 
277
        param = qmi_param_new();
 
278
        if (!param)
 
279
                goto error;
 
280
 
 
281
        qmi_param_append(param, 0x01, sizeof(aid_data), aid_data);
 
282
        qmi_param_append(param, 0x02, fileid_len, fileid_data);
 
283
        qmi_param_append(param, 0x03, sizeof(read_data), read_data);
 
284
 
 
285
        if (qmi_service_send(data->uim, QMI_UIM_READ_RECORD, param,
 
286
                                        read_generic_cb, cbd, g_free) > 0)
 
287
                return;
 
288
 
 
289
        qmi_param_free(param);
 
290
 
 
291
error:
 
292
        CALLBACK_WITH_FAILURE(cb, NULL, 0, user_data);
 
293
 
 
294
        g_free(cbd);
 
295
}
 
296
 
 
297
static void qmi_query_passwd_state(struct ofono_sim *sim,
 
298
                                ofono_sim_passwd_cb_t cb, void *user_data)
 
299
{
 
300
        struct sim_data *data = ofono_sim_get_data(sim);
 
301
 
 
302
        DBG("passwd state %d", data->passwd_state);
 
303
 
 
304
        if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
 
305
                CALLBACK_WITH_FAILURE(cb, -1, user_data);
 
306
                return;
 
307
        }
 
308
 
 
309
        CALLBACK_WITH_SUCCESS(cb, data->passwd_state, user_data);
 
310
}
 
311
 
 
312
static void qmi_query_pin_retries(struct ofono_sim *sim,
 
313
                                ofono_sim_pin_retries_cb_t cb, void *user_data)
 
314
{
 
315
        struct sim_data *data = ofono_sim_get_data(sim);
 
316
 
 
317
        DBG("passwd state %d", data->passwd_state);
 
318
 
 
319
        if (data->passwd_state == OFONO_SIM_PASSWORD_INVALID) {
 
320
                CALLBACK_WITH_FAILURE(cb, NULL, user_data);
 
321
                return;
 
322
        }
 
323
 
 
324
        CALLBACK_WITH_SUCCESS(cb, data->retries, user_data);
 
325
}
 
326
 
 
327
static void card_setup(const struct qmi_uim_slot_info *slot,
 
328
                                        const struct qmi_uim_app_info1 *info1,
 
329
                                        const struct qmi_uim_app_info2 *info2,
 
330
                                                        struct sim_data *data)
 
331
{
 
332
        data->card_state = slot->card_state;
 
333
        data->app_type = info1->app_type;
 
334
 
 
335
        switch (info1->app_state) {
 
336
        case 0x02:      /* PIN1 or UPIN is required */
 
337
                data->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
 
338
                break;
 
339
        case 0x03:      /* PUK1 or PUK for UPIN is required */
 
340
                data->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
 
341
                break;
 
342
        case 0x07:      /* Ready */
 
343
                data->passwd_state = OFONO_SIM_PASSWORD_NONE;
 
344
                break;
 
345
        default:
 
346
                data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
 
347
                break;
 
348
        }
 
349
 
 
350
        data->retries[OFONO_SIM_PASSWORD_SIM_PIN] = info2->pin1_retries;
 
351
        data->retries[OFONO_SIM_PASSWORD_SIM_PUK] = info2->puk1_retries;
 
352
 
 
353
        data->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = info2->pin2_retries;
 
354
        data->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = info2->puk2_retries;
 
355
}
 
356
 
 
357
static void get_card_status_cb(struct qmi_result *result, void *user_data)
 
358
{
 
359
        struct ofono_sim *sim = user_data;
 
360
        struct sim_data *data = ofono_sim_get_data(sim);
 
361
        const void *ptr;
 
362
        const struct qmi_uim_card_status *status;
 
363
        uint16_t len, offset;
 
364
        uint8_t i;
 
365
 
 
366
        DBG("");
 
367
 
 
368
        if (qmi_result_set_error(result, NULL))
 
369
                goto done;
 
370
 
 
371
        ptr = qmi_result_get(result, QMI_UIM_RESULT_CARD_STATUS, &len);
 
372
        if (!ptr)
 
373
                goto done;
 
374
 
 
375
        status = ptr;
 
376
        offset = sizeof(struct qmi_uim_card_status);
 
377
 
 
378
        for (i = 0; i < status->num_slot; i++) {
 
379
                const struct qmi_uim_slot_info *slot;
 
380
                uint8_t n;
 
381
 
 
382
                slot = ptr + offset;
 
383
                offset += sizeof(struct qmi_uim_slot_info);
 
384
 
 
385
                for (n = 0; n < slot->num_app; n++) {
 
386
                        const struct qmi_uim_app_info1 *info1;
 
387
                        const struct qmi_uim_app_info2 *info2;
 
388
                        uint16_t index;
 
389
 
 
390
                        info1 = ptr + offset;
 
391
                        offset += sizeof(struct qmi_uim_app_info1);
 
392
                        offset += info1->aid_len;
 
393
 
 
394
                        info2 = ptr + offset;
 
395
                        offset += sizeof(struct qmi_uim_app_info2);
 
396
 
 
397
                        index = GUINT16_FROM_LE(status->index_gw_pri);
 
398
 
 
399
                        if ((index & 0xff) == i && (index >> 8) == n)
 
400
                                card_setup(slot, info1, info2, data);
 
401
                }
 
402
        }
 
403
 
 
404
done:
 
405
        ofono_sim_register(sim);
 
406
 
 
407
        switch (data->card_state) {
 
408
        case 0x00:      /* Absent */
 
409
        case 0x02:      /* Error */
 
410
                break;
 
411
        case 0x01:      /* Present */
 
412
                ofono_sim_inserted_notify(sim, TRUE);
 
413
                break;
 
414
        }
 
415
}
 
416
 
 
417
static void event_registration_cb(struct qmi_result *result, void *user_data)
 
418
{
 
419
        struct ofono_sim *sim = user_data;
 
420
        struct sim_data *data = ofono_sim_get_data(sim);
 
421
 
 
422
        DBG("");
 
423
 
 
424
        if (qmi_result_set_error(result, NULL))
 
425
                goto error;
 
426
 
 
427
        if (!qmi_result_get_uint32(result, QMI_UIM_RESULT_EVENT_MASK,
 
428
                                                        &data->event_mask))
 
429
                goto error;
 
430
 
 
431
        DBG("event mask 0x%04x", data->event_mask);
 
432
 
 
433
        if (qmi_service_send(data->uim, QMI_UIM_GET_CARD_STATUS, NULL,
 
434
                                        get_card_status_cb, sim, NULL) > 0)
 
435
                return;
 
436
 
 
437
error:
 
438
        ofono_sim_remove(sim);
 
439
}
 
440
 
 
441
 
 
442
static void create_uim_cb(struct qmi_service *service, void *user_data)
 
443
{
 
444
        struct ofono_sim *sim = user_data;
 
445
        struct sim_data *data = ofono_sim_get_data(sim);
 
446
        struct qmi_param *param;
 
447
        uint32_t mask = 0x0003;
 
448
 
 
449
        DBG("");
 
450
 
 
451
        if (!service) {
 
452
                ofono_error("Failed to request UIM service");
 
453
                goto error;
 
454
        }
 
455
 
 
456
        data->uim = qmi_service_ref(service);
 
457
 
 
458
        param = qmi_param_new_uint32(QMI_UIM_PARAM_EVENT_MASK, mask);
 
459
        if (!param)
 
460
                goto error;
 
461
 
 
462
        if (qmi_service_send(data->uim, QMI_UIM_EVENT_REGISTRATION, param,
 
463
                                        event_registration_cb, sim, NULL) > 0)
 
464
                return;
 
465
 
 
466
error:
 
467
        qmi_service_unref(data->uim);
 
468
 
 
469
        ofono_sim_remove(sim);
 
470
}
 
471
 
 
472
static int qmi_sim_probe(struct ofono_sim *sim,
 
473
                                unsigned int vendor, void *user_data)
 
474
{
 
475
        struct qmi_device *device = user_data;
 
476
        struct sim_data *data;
 
477
        int i;
 
478
 
 
479
        DBG("");
 
480
 
 
481
        data = g_new0(struct sim_data, 1);
 
482
 
 
483
        data->passwd_state = OFONO_SIM_PASSWORD_INVALID;
 
484
 
 
485
        for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
 
486
                data->retries[i] = -1;
 
487
 
 
488
        ofono_sim_set_data(sim, data);
 
489
 
 
490
        qmi_service_create(device, QMI_SERVICE_UIM, create_uim_cb, sim, NULL);
 
491
 
 
492
        return 0;
 
493
}
 
494
 
 
495
static void qmi_sim_remove(struct ofono_sim *sim)
 
496
{
 
497
        struct sim_data *data = ofono_sim_get_data(sim);
 
498
 
 
499
        DBG("");
 
500
 
 
501
        ofono_sim_set_data(sim, NULL);
 
502
 
 
503
        qmi_service_unregister_all(data->uim);
 
504
 
 
505
        qmi_service_unref(data->uim);
 
506
 
 
507
        g_free(data);
 
508
}
 
509
 
 
510
static struct ofono_sim_driver driver = {
 
511
        .name                   = "qmimodem",
 
512
        .probe                  = qmi_sim_probe,
 
513
        .remove                 = qmi_sim_remove,
 
514
        .read_file_info         = qmi_read_attributes,
 
515
        .read_file_transparent  = qmi_read_transparent,
 
516
        .read_file_linear       = qmi_read_record,
 
517
        .read_file_cyclic       = qmi_read_record,
 
518
        .query_passwd_state     = qmi_query_passwd_state,
 
519
        .query_pin_retries      = qmi_query_pin_retries,
 
520
};
 
521
 
 
522
void qmi_sim_init(void)
 
523
{
 
524
        ofono_sim_driver_register(&driver);
 
525
}
 
526
 
 
527
void qmi_sim_exit(void)
 
528
{
 
529
        ofono_sim_driver_unregister(&driver);
 
530
}