atmodem: add ifx support for pin retry count
[platform/upstream/ofono.git] / drivers / atmodem / sim.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2010  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 #define _GNU_SOURCE
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30
31 #include <glib.h>
32
33 #include <ofono/log.h>
34 #include <ofono/modem.h>
35 #include <ofono/sim.h>
36
37 #include "gatchat.h"
38 #include "gatresult.h"
39 #include "simutil.h"
40 #include "vendor.h"
41
42 #include "atmodem.h"
43
44 #define EF_STATUS_INVALIDATED 0
45 #define EF_STATUS_VALID 1
46
47 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
48
49 struct sim_data {
50         GAtChat *chat;
51         unsigned int vendor;
52         guint ready_id;
53 };
54
55 static const char *crsm_prefix[] = { "+CRSM:", NULL };
56 static const char *cpin_prefix[] = { "+CPIN:", NULL };
57 static const char *clck_prefix[] = { "+CLCK:", NULL };
58 static const char *huawei_cpin_prefix[] = { "^CPIN:", NULL };
59 static const char *xpincnt_prefix[] = { "+XPINCNT:", NULL };
60 static const char *none_prefix[] = { NULL };
61
62 static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
63 {
64         struct cb_data *cbd = user_data;
65         GAtResultIter iter;
66         ofono_sim_file_info_cb_t cb = cbd->cb;
67         struct ofono_error error;
68         const guint8 *response;
69         gint sw1, sw2, len;
70         int flen, rlen;
71         int str;
72         unsigned char access[3];
73         unsigned char file_status;
74
75         decode_at_error(&error, g_at_result_final_response(result));
76
77         if (!ok) {
78                 cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
79                 return;
80         }
81
82         g_at_result_iter_init(&iter, result);
83
84         if (!g_at_result_iter_next(&iter, "+CRSM:"))
85                 goto error;
86
87         g_at_result_iter_next_number(&iter, &sw1);
88         g_at_result_iter_next_number(&iter, &sw2);
89
90         if (!g_at_result_iter_next_hexstring(&iter, &response, &len) ||
91                         (sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92) ||
92                         (sw1 == 0x90 && sw2 != 0x00)) {
93                 memset(&error, 0, sizeof(error));
94
95                 error.type = OFONO_ERROR_TYPE_SIM;
96                 error.error = (sw1 << 8) | sw2;
97
98                 cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
99                 return;
100         }
101
102         DBG("crsm_info_cb: %02x, %02x, %i", sw1, sw2, len);
103
104         if (response[0] == 0x62) {
105                 ok = sim_parse_3g_get_response(response, len, &flen, &rlen,
106                                                 &str, access, NULL);
107
108                 file_status = EF_STATUS_VALID;
109         }
110         else
111                 ok = sim_parse_2g_get_response(response, len, &flen, &rlen,
112                                                 &str, access, &file_status);
113
114         if (!ok)
115                 goto error;
116
117         cb(&error, flen, str, rlen, access, file_status, cbd->data);
118
119         return;
120
121 error:
122         CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
123                                 EF_STATUS_INVALIDATED, cbd->data);
124 }
125
126 static void at_sim_read_info(struct ofono_sim *sim, int fileid,
127                                         ofono_sim_file_info_cb_t cb,
128                                         void *data)
129 {
130         struct sim_data *sd = ofono_sim_get_data(sim);
131         struct cb_data *cbd;
132         char buf[64];
133
134         if (sd->vendor == OFONO_VENDOR_OPTION_HSO) {
135                 unsigned char access[3] = { 0x00, 0x00, 0x00 };
136
137                 if (fileid == SIM_EFAD_FILEID) {
138                         CALLBACK_WITH_SUCCESS(cb, 4, 0, 0, access,
139                                                 EF_STATUS_VALID, data);
140                         return;
141                 }
142         }
143
144         cbd = cb_data_new(cb, data);
145         if (cbd == NULL)
146                 goto error;
147
148         snprintf(buf, sizeof(buf), "AT+CRSM=192,%i", fileid);
149
150         switch (sd->vendor) {
151         case OFONO_VENDOR_HUAWEI:
152         case OFONO_VENDOR_QUALCOMM_MSM:
153                 strcat(buf, ",0,0,255"); /* Maximum possible length */
154                 break;
155         }
156
157         if (g_at_chat_send(sd->chat, buf, crsm_prefix,
158                                 at_crsm_info_cb, cbd, g_free) > 0)
159                 return;
160
161 error:
162         CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
163                                 EF_STATUS_INVALIDATED, data);
164 }
165
166 static void at_crsm_read_cb(gboolean ok, GAtResult *result,
167                 gpointer user_data)
168 {
169         struct cb_data *cbd = user_data;
170         GAtResultIter iter;
171         ofono_sim_read_cb_t cb = cbd->cb;
172         struct ofono_error error;
173         const guint8 *response;
174         gint sw1, sw2, len;
175
176         decode_at_error(&error, g_at_result_final_response(result));
177
178         if (!ok) {
179                 cb(&error, NULL, 0, cbd->data);
180                 return;
181         }
182
183         g_at_result_iter_init(&iter, result);
184
185         if (!g_at_result_iter_next(&iter, "+CRSM:")) {
186                 CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
187                 return;
188         }
189
190         g_at_result_iter_next_number(&iter, &sw1);
191         g_at_result_iter_next_number(&iter, &sw2);
192
193         if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
194                         (sw1 == 0x90 && sw2 != 0x00)) {
195                 memset(&error, 0, sizeof(error));
196
197                 error.type = OFONO_ERROR_TYPE_SIM;
198                 error.error = (sw1 << 8) | sw2;
199
200                 cb(&error, NULL, 0, cbd->data);
201                 return;
202         }
203
204         if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
205                 CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
206                 return;
207         }
208
209         DBG("crsm_read_cb: %02x, %02x, %d", sw1, sw2, len);
210
211         cb(&error, response, len, cbd->data);
212 }
213
214 static void at_sim_read_binary(struct ofono_sim *sim, int fileid,
215                                         int start, int length,
216                                         ofono_sim_read_cb_t cb, void *data)
217 {
218         struct sim_data *sd = ofono_sim_get_data(sim);
219         struct cb_data *cbd = cb_data_new(cb, data);
220         char buf[64];
221
222         if (cbd == NULL)
223                 goto error;
224
225         snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
226                         start >> 8, start & 0xff, length);
227
228         if (g_at_chat_send(sd->chat, buf, crsm_prefix,
229                                 at_crsm_read_cb, cbd, g_free) > 0)
230                 return;
231
232 error:
233         g_free(cbd);
234
235         CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
236 }
237
238 static void at_sim_read_record(struct ofono_sim *sim, int fileid,
239                                         int record, int length,
240                                         ofono_sim_read_cb_t cb, void *data)
241 {
242         struct sim_data *sd = ofono_sim_get_data(sim);
243         struct cb_data *cbd = cb_data_new(cb, data);
244         char buf[64];
245
246         if (cbd == NULL)
247                 goto error;
248
249         snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
250                         record, length);
251
252         if (g_at_chat_send(sd->chat, buf, crsm_prefix,
253                                 at_crsm_read_cb, cbd, g_free) > 0)
254                 return;
255
256 error:
257         g_free(cbd);
258
259         CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
260 }
261
262 static void at_crsm_update_cb(gboolean ok, GAtResult *result,
263                 gpointer user_data)
264 {
265         struct cb_data *cbd = user_data;
266         GAtResultIter iter;
267         ofono_sim_write_cb_t cb = cbd->cb;
268         struct ofono_error error;
269         gint sw1, sw2;
270
271         decode_at_error(&error, g_at_result_final_response(result));
272
273         if (!ok) {
274                 cb(&error, cbd->data);
275                 return;
276         }
277
278         g_at_result_iter_init(&iter, result);
279
280         if (!g_at_result_iter_next(&iter, "+CRSM:")) {
281                 CALLBACK_WITH_FAILURE(cb, cbd->data);
282                 return;
283         }
284
285         g_at_result_iter_next_number(&iter, &sw1);
286         g_at_result_iter_next_number(&iter, &sw2);
287
288         if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
289                         (sw1 == 0x90 && sw2 != 0x00)) {
290                 memset(&error, 0, sizeof(error));
291
292                 error.type = OFONO_ERROR_TYPE_SIM;
293                 error.error = (sw1 << 8) | sw2;
294         }
295
296         DBG("crsm_update_cb: %02x, %02x", sw1, sw2);
297
298         cb(&error, cbd->data);
299 }
300
301 static void at_sim_update_binary(struct ofono_sim *sim, int fileid,
302                                         int start, int length,
303                                         const unsigned char *value,
304                                         ofono_sim_write_cb_t cb, void *data)
305 {
306         struct sim_data *sd = ofono_sim_get_data(sim);
307         struct cb_data *cbd = cb_data_new(cb, data);
308         char *buf = g_try_new(char, 36 + length * 2);
309         int len, ret;
310
311         if (cbd == NULL || buf == NULL)
312                 goto error;
313
314         len = sprintf(buf, "AT+CRSM=214,%i,%i,%i,%i,", fileid,
315                         start >> 8, start & 0xff, length);
316
317         for (; length; length--)
318                 len += sprintf(buf + len, "%02hhX", *value++);
319
320         ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
321                                 at_crsm_update_cb, cbd, g_free);
322
323         g_free(buf);
324
325         if (ret > 0)
326                 return;
327
328 error:
329         g_free(cbd);
330
331         CALLBACK_WITH_FAILURE(cb, data);
332 }
333
334 static void at_sim_update_record(struct ofono_sim *sim, int fileid,
335                                         int record, int length,
336                                         const unsigned char *value,
337                                         ofono_sim_write_cb_t cb, void *data)
338 {
339         struct sim_data *sd = ofono_sim_get_data(sim);
340         struct cb_data *cbd = cb_data_new(cb, data);
341         char *buf = g_try_new(char, 36 + length * 2);
342         int len, ret;
343
344         if (cbd == NULL || buf == NULL)
345                 goto error;
346
347         len = sprintf(buf, "AT+CRSM=220,%i,%i,4,%i,", fileid,
348                         record, length);
349
350         for (; length; length--)
351                 len += sprintf(buf + len, "%02hhX", *value++);
352
353         ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
354                                 at_crsm_update_cb, cbd, g_free);
355
356         g_free(buf);
357
358         if (ret > 0)
359                 return;
360
361 error:
362         g_free(cbd);
363
364         CALLBACK_WITH_FAILURE(cb, data);
365 }
366
367 static void at_sim_update_cyclic(struct ofono_sim *sim, int fileid,
368                                         int length, const unsigned char *value,
369                                         ofono_sim_write_cb_t cb, void *data)
370 {
371         struct sim_data *sd = ofono_sim_get_data(sim);
372         struct cb_data *cbd = cb_data_new(cb, data);
373         char *buf = g_try_new(char, 36 + length * 2);
374         int len, ret;
375
376         if (cbd == NULL || buf == NULL)
377                 goto error;
378
379         len = sprintf(buf, "AT+CRSM=220,%i,0,3,%i,", fileid, length);
380
381         for (; length; length--)
382                 len += sprintf(buf + len, "%02hhX", *value++);
383
384         ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
385                                 at_crsm_update_cb, cbd, g_free);
386
387         g_free(buf);
388
389         if (ret > 0)
390                 return;
391
392 error:
393         g_free(cbd);
394
395         CALLBACK_WITH_FAILURE(cb, data);
396 }
397
398 static void at_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data)
399 {
400         struct cb_data *cbd = user_data;
401         GAtResultIter iter;
402         ofono_sim_imsi_cb_t cb = cbd->cb;
403         struct ofono_error error;
404         const char *imsi;
405         int i;
406
407         decode_at_error(&error, g_at_result_final_response(result));
408
409         if (!ok) {
410                 cb(&error, NULL, cbd->data);
411                 return;
412         }
413
414         g_at_result_iter_init(&iter, result);
415
416         for (i = 0; i < g_at_result_num_response_lines(result); i++)
417                 g_at_result_iter_next(&iter, NULL);
418
419         imsi = g_at_result_iter_raw_line(&iter);
420
421         DBG("cimi_cb: %s", imsi);
422
423         cb(&error, imsi, cbd->data);
424 }
425
426 static void at_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
427                         void *data)
428 {
429         struct sim_data *sd = ofono_sim_get_data(sim);
430         struct cb_data *cbd = cb_data_new(cb, data);
431
432         if (cbd == NULL)
433                 goto error;
434
435         if (g_at_chat_send(sd->chat, "AT+CIMI", NULL,
436                                 at_cimi_cb, cbd, g_free) > 0)
437                 return;
438
439 error:
440         g_free(cbd);
441
442         CALLBACK_WITH_FAILURE(cb, NULL, data);
443 }
444
445 static struct {
446         enum ofono_sim_password_type type;
447         const char *name;
448 } const at_sim_name[] = {
449         { OFONO_SIM_PASSWORD_NONE,              "READY"         },
450         { OFONO_SIM_PASSWORD_SIM_PIN,           "SIM PIN"       },
451         { OFONO_SIM_PASSWORD_SIM_PUK,           "SIM PUK"       },
452         { OFONO_SIM_PASSWORD_PHSIM_PIN,         "PH-SIM PIN"    },
453         { OFONO_SIM_PASSWORD_PHFSIM_PIN,        "PH-FSIM PIN"   },
454         { OFONO_SIM_PASSWORD_PHFSIM_PUK,        "PH-FSIM PUK"   },
455         { OFONO_SIM_PASSWORD_SIM_PIN2,          "SIM PIN2"      },
456         { OFONO_SIM_PASSWORD_SIM_PUK2,          "SIM PUK2"      },
457         { OFONO_SIM_PASSWORD_PHNET_PIN,         "PH-NET PIN"    },
458         { OFONO_SIM_PASSWORD_PHNET_PUK,         "PH-NET PUK"    },
459         { OFONO_SIM_PASSWORD_PHNETSUB_PIN,      "PH-NETSUB PIN" },
460         { OFONO_SIM_PASSWORD_PHNETSUB_PUK,      "PH-NETSUB PUK" },
461         { OFONO_SIM_PASSWORD_PHSP_PIN,          "PH-SP PIN"     },
462         { OFONO_SIM_PASSWORD_PHSP_PUK,          "PH-SP PUK"     },
463         { OFONO_SIM_PASSWORD_PHCORP_PIN,        "PH-CORP PIN"   },
464         { OFONO_SIM_PASSWORD_PHCORP_PUK,        "PH-CORP PUK"   },
465 };
466
467 #define BUILD_PIN_RETRIES_ARRAY(passwd_types, passwd_types_cnt, retry)  \
468         for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)                \
469                 retry[i] = -1;                                          \
470                                                                         \
471         for (i = 0; i < passwd_types_cnt; i++) {                        \
472                 int val;                                                \
473                                                                         \
474                 if (!g_at_result_iter_next_number(&iter, &val))         \
475                         goto error;                                     \
476                                                                         \
477                 retry[passwd_types[i]] = val;                           \
478                                                                         \
479                 DBG("retry counter id=%d, val=%d", passwd_types[i],     \
480                                         retry[passwd_types[i]]);        \
481         }                                                               \
482
483 static void huawei_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
484 {
485         struct cb_data *cbd = user_data;
486         ofono_sim_pin_retries_cb_t cb = cbd->cb;
487         const char *final = g_at_result_final_response(result);
488         GAtResultIter iter;
489         struct ofono_error error;
490         int retries[OFONO_SIM_PASSWORD_INVALID];
491         size_t i;
492         static enum ofono_sim_password_type password_types[] = {
493                 OFONO_SIM_PASSWORD_SIM_PUK,
494                 OFONO_SIM_PASSWORD_SIM_PIN,
495                 OFONO_SIM_PASSWORD_SIM_PUK2,
496                 OFONO_SIM_PASSWORD_SIM_PIN2,
497         };
498
499         decode_at_error(&error, final);
500
501         if (!ok) {
502                 cb(&error, NULL, cbd->data);
503                 return;
504         }
505
506         g_at_result_iter_init(&iter, result);
507
508         if (!g_at_result_iter_next(&iter, "^CPIN:"))
509                 goto error;
510
511         /* Skip status since we are not interested in this */
512         if (!g_at_result_iter_skip_next(&iter))
513                 goto error;
514
515         /* Skip "overall counter" since we'll grab each one individually */
516         if (!g_at_result_iter_skip_next(&iter))
517                 goto error;
518
519         BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
520                                 retries);
521
522         cb(&error, retries, cbd->data);
523
524         return;
525
526 error:
527         CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
528 }
529
530 static void xpincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
531 {
532         struct cb_data *cbd = user_data;
533         ofono_sim_pin_retries_cb_t cb = cbd->cb;
534         const char *final = g_at_result_final_response(result);
535         GAtResultIter iter;
536         struct ofono_error error;
537         int retries[OFONO_SIM_PASSWORD_INVALID];
538         size_t i;
539         static enum ofono_sim_password_type password_types[] = {
540                 OFONO_SIM_PASSWORD_SIM_PIN,
541                 OFONO_SIM_PASSWORD_SIM_PIN2,
542                 OFONO_SIM_PASSWORD_SIM_PUK,
543                 OFONO_SIM_PASSWORD_SIM_PUK2,
544         };
545
546         decode_at_error(&error, final);
547
548         if (!ok) {
549                 cb(&error, NULL, cbd->data);
550                 return;
551         }
552
553         g_at_result_iter_init(&iter, result);
554
555         if (!g_at_result_iter_next(&iter, "+XPINCNT:"))
556                 goto error;
557
558         BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
559                                 retries);
560
561         cb(&error, retries, cbd->data);
562
563         return;
564
565 error:
566         CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
567 }
568
569 static void at_pin_retries_query(struct ofono_sim *sim,
570                                         ofono_sim_pin_retries_cb_t cb,
571                                         void *data)
572 {
573         struct sim_data *sd = ofono_sim_get_data(sim);
574         struct cb_data *cbd = cb_data_new(cb, data);
575
576         DBG("");
577
578         if (cbd == NULL)
579                 goto error;
580
581         switch (sd->vendor) {
582         case OFONO_VENDOR_IFX:
583                 if (g_at_chat_send(sd->chat, "AT+XPINCNT", xpincnt_prefix,
584                                         xpincnt_cb, cbd, g_free) > 0)
585                         return;
586
587                 break;
588         case OFONO_VENDOR_HUAWEI:
589                 if (g_at_chat_send(sd->chat, "AT^CPIN?", huawei_cpin_prefix,
590                                         huawei_cpin_cb, cbd, g_free) > 0)
591                         return;
592
593         default:
594                 break;
595         }
596
597 error:
598         g_free(cbd);
599
600         CALLBACK_WITH_FAILURE(cb, NULL, data);
601 }
602
603 static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
604 {
605         struct cb_data *cbd = user_data;
606         struct sim_data *sd = ofono_sim_get_data(cbd->user);
607         GAtResultIter iter;
608         ofono_sim_passwd_cb_t cb = cbd->cb;
609         struct ofono_error error;
610         const char *pin_required;
611         int pin_type = OFONO_SIM_PASSWORD_INVALID;
612         int i;
613         int len = sizeof(at_sim_name) / sizeof(*at_sim_name);
614         const char *final = g_at_result_final_response(result);
615
616         if (sd->vendor == OFONO_VENDOR_WAVECOM && ok && strlen(final) > 7)
617                 decode_at_error(&error, "OK");
618         else
619                 decode_at_error(&error, final);
620
621         if (!ok) {
622                 cb(&error, -1, cbd->data);
623                 return;
624         }
625
626         if (sd->vendor == OFONO_VENDOR_WAVECOM) {
627                 /* +CPIN: <pin> */
628                 pin_required = final + 7;
629         } else {
630                 g_at_result_iter_init(&iter, result);
631
632                 if (!g_at_result_iter_next(&iter, "+CPIN:")) {
633                         CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
634                         return;
635                 }
636
637                 g_at_result_iter_next_unquoted_string(&iter, &pin_required);
638         }
639
640         for (i = 0; i < len; i++) {
641                 if (strcmp(pin_required, at_sim_name[i].name))
642                         continue;
643
644                 pin_type = at_sim_name[i].type;
645                 break;
646         }
647
648         if (pin_type == OFONO_SIM_PASSWORD_INVALID) {
649                 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
650                 return;
651         }
652
653         DBG("crsm_pin_cb: %s", pin_required);
654
655         cb(&error, pin_type, cbd->data);
656 }
657
658 static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
659                         void *data)
660 {
661         struct sim_data *sd = ofono_sim_get_data(sim);
662         struct cb_data *cbd = cb_data_new(cb, data);
663
664         if (cbd == NULL)
665                 goto error;
666
667         cbd->user = sim;
668
669         if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
670                                 at_cpin_cb, cbd, g_free) > 0)
671                 return;
672
673 error:
674         g_free(cbd);
675
676         CALLBACK_WITH_FAILURE(cb, -1, data);
677 }
678
679 static void at_xsim_notify(GAtResult *result, gpointer user_data)
680 {
681         struct cb_data *cbd = user_data;
682         struct sim_data *sd = cbd->user;
683         ofono_sim_lock_unlock_cb_t cb = cbd->cb;
684         struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
685         GAtResultIter iter;
686         int state;
687
688         g_at_result_iter_init(&iter, result);
689
690         if (!g_at_result_iter_next(&iter, "+XSIM:"))
691                 return;
692
693         if (!g_at_result_iter_next_number(&iter, &state))
694                 return;
695
696         switch (state) {
697         case 3: /* PIN verified â€“ Ready */
698         case 7: /* ready for attach (+COPS) */
699                 break;
700         default:
701                 return;
702         }
703
704         cb(&error, cbd->data);
705
706         g_at_chat_unregister(sd->chat, sd->ready_id);
707         sd->ready_id = 0;
708 }
709
710 static void at_epev_notify(GAtResult *result, gpointer user_data)
711 {
712         struct cb_data *cbd = user_data;
713         struct sim_data *sd = cbd->user;
714         ofono_sim_lock_unlock_cb_t cb = cbd->cb;
715         struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
716
717         cb(&error, cbd->data);
718
719         g_at_chat_unregister(sd->chat, sd->ready_id);
720         sd->ready_id = 0;
721 }
722
723 static void at_pin_send_cb(gboolean ok, GAtResult *result,
724                                 gpointer user_data)
725 {
726         struct cb_data *cbd = user_data;
727         struct sim_data *sd = cbd->user;
728         ofono_sim_lock_unlock_cb_t cb = cbd->cb;
729         struct ofono_error error;
730
731         decode_at_error(&error, g_at_result_final_response(result));
732
733         if (!ok)
734                 goto done;
735
736         switch (sd->vendor) {
737         case OFONO_VENDOR_IFX:
738                 /*
739                  * On the IFX modem, AT+CPIN? can return READY too
740                  * early and so use +XSIM notification to detect
741                  * the ready state of the SIM.
742                  */
743                 sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
744                                                         at_xsim_notify,
745                                                         FALSE, cbd, g_free);
746                 return;
747         case OFONO_VENDOR_MBM:
748                 /*
749                  * On the MBM modem, AT+CPIN? keeps returning SIM PIN
750                  * for a moment after successful AT+CPIN="..", but then
751                  * sends *EPEV when that changes.
752                  */
753                 sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
754                                                         at_epev_notify,
755                                                         FALSE, cbd, g_free);
756                 return;
757         }
758
759 done:
760         cb(&error, cbd->data);
761
762         g_free(cbd);
763 }
764
765 static void at_pin_send(struct ofono_sim *sim, const char *passwd,
766                         ofono_sim_lock_unlock_cb_t cb, void *data)
767 {
768         struct sim_data *sd = ofono_sim_get_data(sim);
769         struct cb_data *cbd = cb_data_new(cb, data);
770         char buf[64];
771         int ret;
772
773         if (cbd == NULL)
774                 goto error;
775
776         cbd->user = sd;
777
778         snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
779
780         ret = g_at_chat_send(sd->chat, buf, none_prefix,
781                                 at_pin_send_cb, cbd, NULL);
782
783         memset(buf, 0, sizeof(buf));
784
785         if (ret > 0)
786                 return;
787
788 error:
789         g_free(cbd);
790
791         CALLBACK_WITH_FAILURE(cb, data);
792 }
793
794 static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
795                                 const char *passwd,
796                                 ofono_sim_lock_unlock_cb_t cb, void *data)
797 {
798         struct sim_data *sd = ofono_sim_get_data(sim);
799         struct cb_data *cbd = cb_data_new(cb, data);
800         char buf[64];
801         int ret;
802
803         if (cbd == NULL)
804                 goto error;
805
806         cbd->user = sd;
807
808         snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
809
810         ret = g_at_chat_send(sd->chat, buf, none_prefix,
811                                 at_pin_send_cb, cbd, NULL);
812
813         memset(buf, 0, sizeof(buf));
814
815         if (ret > 0)
816                 return;
817
818 error:
819         g_free(cbd);
820
821         CALLBACK_WITH_FAILURE(cb, data);
822 }
823
824 static void at_lock_unlock_cb(gboolean ok, GAtResult *result,
825                                 gpointer user_data)
826 {
827         struct cb_data *cbd = user_data;
828         ofono_sim_lock_unlock_cb_t cb = cbd->cb;
829         struct ofono_error error;
830
831         decode_at_error(&error, g_at_result_final_response(result));
832
833         cb(&error, cbd->data);
834 }
835
836 static const char *const at_clck_cpwd_fac[] = {
837         [OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
838         [OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
839         [OFONO_SIM_PASSWORD_PHSIM_PIN] = "PS",
840         [OFONO_SIM_PASSWORD_PHFSIM_PIN] = "PF",
841         [OFONO_SIM_PASSWORD_PHNET_PIN] = "PN",
842         [OFONO_SIM_PASSWORD_PHNETSUB_PIN] = "PU",
843         [OFONO_SIM_PASSWORD_PHSP_PIN] = "PP",
844         [OFONO_SIM_PASSWORD_PHCORP_PIN] = "PC",
845 };
846
847 static void at_pin_enable(struct ofono_sim *sim,
848                                 enum ofono_sim_password_type passwd_type,
849                                 int enable, const char *passwd,
850                                 ofono_sim_lock_unlock_cb_t cb, void *data)
851 {
852         struct sim_data *sd = ofono_sim_get_data(sim);
853         struct cb_data *cbd = cb_data_new(cb, data);
854         char buf[64];
855         int ret;
856         unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
857
858         if (cbd == NULL)
859                 goto error;
860
861         if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
862                 goto error;
863
864         snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
865                         at_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd);
866
867         ret = g_at_chat_send(sd->chat, buf, none_prefix,
868                                 at_lock_unlock_cb, cbd, g_free);
869
870         memset(buf, 0, sizeof(buf));
871
872         if (ret > 0)
873                 return;
874
875 error:
876         g_free(cbd);
877
878         CALLBACK_WITH_FAILURE(cb, data);
879 }
880
881 static void at_change_passwd(struct ofono_sim *sim,
882                         enum ofono_sim_password_type passwd_type,
883                         const char *old, const char *new,
884                         ofono_sim_lock_unlock_cb_t cb, void *data)
885 {
886         struct sim_data *sd = ofono_sim_get_data(sim);
887         struct cb_data *cbd = cb_data_new(cb, data);
888         char buf[64];
889         int ret;
890         unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
891
892         if (cbd == NULL)
893                 goto error;
894
895         if (passwd_type >= len ||
896                         at_clck_cpwd_fac[passwd_type] == NULL)
897                 goto error;
898
899         snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
900                         at_clck_cpwd_fac[passwd_type], old, new);
901
902         ret = g_at_chat_send(sd->chat, buf, none_prefix,
903                                 at_lock_unlock_cb, cbd, g_free);
904
905         memset(buf, 0, sizeof(buf));
906
907         if (ret > 0)
908                 return;
909
910 error:
911         g_free(cbd);
912
913         CALLBACK_WITH_FAILURE(cb, data);
914 }
915
916 static void at_lock_status_cb(gboolean ok, GAtResult *result,
917                 gpointer user_data)
918 {
919         struct cb_data *cbd = user_data;
920         GAtResultIter iter;
921         ofono_sim_locked_cb_t cb = cbd->cb;
922         struct ofono_error error;
923         int locked;
924
925         decode_at_error(&error, g_at_result_final_response(result));
926
927         if (!ok) {
928                 cb(&error, -1, cbd->data);
929                 return;
930         }
931
932         g_at_result_iter_init(&iter, result);
933
934         if (!g_at_result_iter_next(&iter, "+CLCK:")) {
935                 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
936                 return;
937         }
938
939         g_at_result_iter_next_number(&iter, &locked);
940
941         DBG("lock_status_cb: %i", locked);
942
943         cb(&error, locked, cbd->data);
944 }
945
946 static void at_pin_query_enabled(struct ofono_sim *sim,
947                                 enum ofono_sim_password_type passwd_type,
948                                 ofono_sim_locked_cb_t cb, void *data)
949 {
950         struct sim_data *sd = ofono_sim_get_data(sim);
951         struct cb_data *cbd = cb_data_new(cb, data);
952         char buf[64];
953         unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
954
955         if (cbd == NULL)
956                 goto error;
957
958         if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
959                 goto error;
960
961         snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
962                         at_clck_cpwd_fac[passwd_type]);
963
964         if (g_at_chat_send(sd->chat, buf, clck_prefix,
965                                 at_lock_status_cb, cbd, g_free) > 0)
966                 return;
967
968 error:
969         g_free(cbd);
970
971         CALLBACK_WITH_FAILURE(cb, -1, data);
972 }
973
974 static gboolean at_sim_register(gpointer user)
975 {
976         struct ofono_sim *sim = user;
977
978         ofono_sim_register(sim);
979
980         return FALSE;
981 }
982
983 static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
984                                 void *data)
985 {
986         GAtChat *chat = data;
987         struct sim_data *sd;
988
989         sd = g_new0(struct sim_data, 1);
990         sd->chat = g_at_chat_clone(chat);
991         sd->vendor = vendor;
992
993         switch (sd->vendor) {
994         case OFONO_VENDOR_WAVECOM:
995                 g_at_chat_add_terminator(sd->chat, "+CPIN:", 6, TRUE);
996                 break;
997         case OFONO_VENDOR_MBM:
998                 g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
999                 break;
1000         default:
1001                 break;
1002         }
1003
1004         ofono_sim_set_data(sim, sd);
1005         g_idle_add(at_sim_register, sim);
1006
1007         return 0;
1008 }
1009
1010 static void at_sim_remove(struct ofono_sim *sim)
1011 {
1012         struct sim_data *sd = ofono_sim_get_data(sim);
1013
1014         ofono_sim_set_data(sim, NULL);
1015
1016         g_at_chat_unref(sd->chat);
1017         g_free(sd);
1018 }
1019
1020 static struct ofono_sim_driver driver = {
1021         .name                   = "atmodem",
1022         .probe                  = at_sim_probe,
1023         .remove                 = at_sim_remove,
1024         .read_file_info         = at_sim_read_info,
1025         .read_file_transparent  = at_sim_read_binary,
1026         .read_file_linear       = at_sim_read_record,
1027         .read_file_cyclic       = at_sim_read_record,
1028         .write_file_transparent = at_sim_update_binary,
1029         .write_file_linear      = at_sim_update_record,
1030         .write_file_cyclic      = at_sim_update_cyclic,
1031         .read_imsi              = at_read_imsi,
1032         .query_passwd_state     = at_pin_query,
1033         .query_pin_retries      = at_pin_retries_query,
1034         .send_passwd            = at_pin_send,
1035         .reset_passwd           = at_pin_send_puk,
1036         .lock                   = at_pin_enable,
1037         .change_passwd          = at_change_passwd,
1038         .query_locked           = at_pin_query_enabled,
1039 };
1040
1041 void at_sim_init(void)
1042 {
1043         ofono_sim_driver_register(&driver);
1044 }
1045
1046 void at_sim_exit(void)
1047 {
1048         ofono_sim_driver_unregister(&driver);
1049 }