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