3ef3cf84bb795e86a95de4f122504192a8e390d0
[osmocom-bb.git] / src / host / layer23 / src / common / sim.c
1 /*
2  * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
3  *
4  * All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
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 along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  */
21
22 #include <stdint.h>
23 #include <errno.h>
24 #include <arpa/inet.h>
25 #include <osmocore/talloc.h>
26 #include <osmocore/utils.h>
27
28 #include <osmocom/bb/common/logging.h>
29 #include <osmocom/bb/common/osmocom_data.h>
30 #include <osmocom/bb/common/l1ctl.h>
31
32 extern void *l23_ctx;
33 static int sim_process_job(struct osmocom_ms *ms);
34
35 /*
36  * support
37  */
38
39 uint32_t new_handle = 1;
40
41 static struct gsm1111_df_name {
42         uint16_t file;
43         const char *name;
44 } gsm1111_df_name[] = {
45         { 0x3f00, "MF" },
46         { 0x7f20, "DFgsm" },
47         { 0x7f10, "DFtelecom" },
48         { 0x7f22, "DFis-41" },
49         { 0x7f23, "DFfp-cts" },
50         { 0x5f50, "DFgraphics" },
51         { 0x5f30, "DFiridium" },
52         { 0x5f31, "DFglobst" },
53         { 0x5f32, "DFico" },
54         { 0x5f33, "DFaces" },
55         { 0x5f40, "DFeia/tia-553" },
56         { 0x5f60, "DFcts" },
57         { 0x5f70, "DFsolsa" },
58         { 0x5f3c, "DFmexe" },
59         { 0, NULL }
60 };
61
62 static const char *get_df_name(uint16_t fid)
63 {
64         int i;
65         static char text[7];
66
67         for (i = 0; gsm1111_df_name[i].file; i++)
68                 if (gsm1111_df_name[i].file == fid)
69                         break;
70         if (gsm1111_df_name[i].file)
71                 return gsm1111_df_name[i].name;
72
73         sprintf(text, "0x%04x", fid);
74         return text;
75 }
76
77 static struct gsm_sim_handler *sim_get_handler(struct gsm_sim *sim,
78         uint32_t handle)
79 {
80         struct gsm_sim_handler *handler;
81
82         llist_for_each_entry(handler, &sim->handlers, entry)
83                 if (handler->handle == handle)
84                         return handler;
85
86         return NULL;
87 }
88
89 /*
90  * messages
91  */
92
93 static const struct value_string sim_job_names[] = {
94         { SIM_JOB_READ_BINARY,          "SIM_JOB_READ_BINARY" },
95         { SIM_JOB_UPDATE_BINARY,        "SIM_JOB_UPDATE_BINARY" },
96         { SIM_JOB_READ_RECORD,          "SIM_JOB_READ_RECORD" },
97         { SIM_JOB_UPDATE_RECORD,        "SIM_JOB_UPDATE_RECORD" },
98         { SIM_JOB_SEEK_RECORD,          "SIM_JOB_SEEK_RECORD" },
99         { SIM_JOB_INCREASE,             "SIM_JOB_INCREASE" },
100         { SIM_JOB_INVALIDATE,           "SIM_JOB_INVALIDATE" },
101         { SIM_JOB_REHABILITATE,         "SIM_JOB_REHABILITATE" },
102         { SIM_JOB_RUN_GSM_ALGO,         "SIM_JOB_RUN_GSM_ALGO" },
103         { SIM_JOB_PIN1_UNLOCK,          "SIM_JOB_PIN1_UNLOCK" },
104         { SIM_JOB_PIN1_CHANGE,          "SIM_JOB_PIN1_CHANGE" },
105         { SIM_JOB_PIN1_DISABLE,         "SIM_JOB_PIN1_DISABLE" },
106         { SIM_JOB_PIN1_ENABLE,          "SIM_JOB_PIN1_ENABLE" },
107         { SIM_JOB_PIN1_UNBLOCK,         "SIM_JOB_PIN1_UNBLOCK" },
108         { SIM_JOB_PIN2_UNLOCK,          "SIM_JOB_PIN2_UNLOCK" },
109         { SIM_JOB_PIN2_CHANGE,          "SIM_JOB_PIN2_CHANGE" },
110         { SIM_JOB_PIN2_UNBLOCK,         "SIM_JOB_PIN2_UNBLOCK" },
111         { SIM_JOB_OK,                   "SIM_JOB_OK" },
112         { SIM_JOB_ERROR,                "SIM_JOB_ERROR" },
113         { 0,                            NULL }
114 };
115
116 static const char *get_job_name(int value)
117 {
118         return get_value_string(sim_job_names, value);
119 }
120
121 /* allocate sim client message (upper layer) */
122 struct msgb *gsm_sim_msgb_alloc(uint32_t handle, uint8_t job_type)
123 {
124         struct msgb *msg;
125         struct sim_hdr *nsh;
126
127         msg = msgb_alloc_headroom(SIM_ALLOC_SIZE+SIM_ALLOC_HEADROOM,
128                 SIM_ALLOC_HEADROOM, "SIM");
129         if (!msg)
130                 return NULL;
131
132         nsh = (struct sim_hdr *) msgb_put(msg, sizeof(*nsh));
133         nsh->handle = handle;
134         nsh->job_type = job_type;
135
136         return msg;
137 }
138
139 /* reply to job, after it is done. reuse the msgb in the job */
140 void gsm_sim_reply(struct osmocom_ms *ms, uint8_t result_type, uint8_t *result,
141         uint16_t result_len)
142 {
143         struct gsm_sim *sim = &ms->sim;
144         struct msgb *msg = sim->job_msg;
145         struct sim_hdr *sh;
146         uint8_t *payload;
147         uint16_t payload_len;
148         struct gsm_sim_handler *handler;
149
150         LOGP(DSIM, LOGL_INFO, "sending result to callback function "
151                 "(type=%d)\n", result_type);
152
153         /* if no handler, or no callback, just free the job */
154         sh = (struct sim_hdr *)msg->data;
155         handler = sim_get_handler(sim, sh->handle);
156         if (!handler || !handler->cb) {
157                 LOGP(DSIM, LOGL_INFO, "no callback or no handler, "
158                         "dropping result\n");
159                 msgb_free(sim->job_msg);
160                 sim->job_msg = NULL;
161                 sim->job_state = SIM_JST_IDLE;
162                 return;
163         }
164
165         payload = msg->data + sizeof(*sh);
166         payload_len = msg->len - sizeof(*sh);
167
168         /* remove data */
169         msg->tail -= payload_len;
170         msg->len -= payload_len;
171
172         /* add reply data */
173         sh->job_type = result_type;
174         if (result_len)
175                 memcpy(msgb_put(msg, result_len), result, result_len);
176
177         /* callback */
178         sim->job_state = SIM_JST_IDLE;
179         sim->job_msg = NULL;
180         handler->cb(ms, msg);
181 }
182
183 /* send APDU to card reader */
184 static int sim_apdu_send(struct osmocom_ms *ms, uint8_t *data, uint16_t length)
185 {
186         LOGP(DSIM, LOGL_INFO, "sending APDU (class 0x%02x, ins 0x%02x)\n",
187                 data[0], data[1]);
188         l1ctl_tx_sim_req(ms, data, length);
189         return 0;
190 }
191
192 /* dequeue messages (RSL-SAP) */
193 int gsm_sim_job_dequeue(struct osmocom_ms *ms)
194 {
195         struct gsm_sim *sim = &ms->sim;
196         struct sim_hdr *sh;
197         struct msgb *msg;
198         struct gsm_sim_handler *handler;
199
200         /* already have a job */
201         if (sim->job_msg)
202                 return 0;
203
204         /* get next job */
205         while ((msg = msgb_dequeue(&sim->jobs))) {
206                 /* resolve handler */
207                 sh = (struct sim_hdr *) msg->data;
208                 LOGP(DSIM, LOGL_INFO, "got new job: %s (handle=%08x)\n",
209                         get_job_name(sh->job_type), sh->handle);
210                 handler = sim_get_handler(sim, sh->handle);
211                 if (!handler) {
212                         LOGP(DSIM, LOGL_INFO, "no handler, ignoring job\n");
213                         /* does not exist anymore */
214                         msgb_free(msg);
215                         continue;
216                 }
217
218                 /* init job */
219                 sim->job_state = SIM_JST_IDLE;
220                 sim->job_msg = msg;
221                 sim->job_handle = sh->handle;
222
223                 /* process current job, message is freed there */
224                 sim_process_job(ms);
225                 return 1; /* work done */
226         }
227         
228         return 0;
229 }
230
231
232 /*
233  * SIM commands
234  */
235
236 /* 9.2.1 */
237 static int gsm1111_tx_select(struct osmocom_ms *ms, uint16_t fid)
238 {
239         uint8_t buffer[5 + 2];
240
241         LOGP(DSIM, LOGL_INFO, "SELECT (file=0x%04x)\n", fid);
242         buffer[0] = GSM1111_CLASS_GSM;
243         buffer[1] = GSM1111_INST_SELECT;
244         buffer[2] = 0x00;
245         buffer[3] = 0x00;
246         buffer[4] = 2;
247         buffer[5] = fid >> 8;
248         buffer[6] = fid;
249
250         return sim_apdu_send(ms, buffer, 5 + 2);
251 }
252
253 #if 0
254 /* 9.2.2 */
255 static int gsm1111_tx_status(struct osmocom_ms *ms)
256 {
257         uint8_t buffer[5];
258
259         LOGP(DSIM, LOGL_INFO, "STATUS\n");
260         buffer[0] = GSM1111_CLASS_GSM;
261         buffer[1] = GSM1111_INST_STATUS;
262         buffer[2] = 0x00;
263         buffer[3] = 0x00;
264         buffer[4] = 0;
265
266         return sim_apdu_send(ms, buffer, 5);
267 }
268 #endif
269
270 /* 9.2.3 */
271 static int gsm1111_tx_read_binary(struct osmocom_ms *ms, uint16_t offset,
272         uint8_t length)
273 {
274         uint8_t buffer[5];
275
276         LOGP(DSIM, LOGL_INFO, "READ BINARY (offset=%d len=%d)\n", offset,
277                 length);
278         buffer[0] = GSM1111_CLASS_GSM;
279         buffer[1] = GSM1111_INST_READ_BINARY;
280         buffer[2] = offset >> 8;
281         buffer[3] = offset;
282         buffer[4] = length;
283
284         return sim_apdu_send(ms, buffer, 5);
285 }
286
287 /* 9.2.4 */
288 static int gsm1111_tx_update_binary(struct osmocom_ms *ms, uint16_t offset,
289         uint8_t *data, uint8_t length)
290 {
291         uint8_t buffer[5 + length];
292
293         LOGP(DSIM, LOGL_INFO, "UPDATE BINARY (offset=%d len=%d)\n", offset,
294                 length);
295         buffer[0] = GSM1111_CLASS_GSM;
296         buffer[1] = GSM1111_INST_UPDATE_BINARY;
297         buffer[2] = offset >> 8;
298         buffer[3] = offset;
299         buffer[4] = length;
300         memcpy(buffer + 5, data, length);
301
302         return sim_apdu_send(ms, buffer, 5 + length);
303 }
304
305 /* 9.2.5 */
306 static int gsm1111_tx_read_record(struct osmocom_ms *ms, uint8_t rec_no,
307         uint8_t mode, uint8_t length)
308 {
309         uint8_t buffer[5];
310
311         LOGP(DSIM, LOGL_INFO, "READ RECORD (rec_no=%d mode=%d len=%d)\n",
312                 rec_no, mode, length);
313         buffer[0] = GSM1111_CLASS_GSM;
314         buffer[1] = GSM1111_INST_READ_RECORD;
315         buffer[2] = rec_no;
316         buffer[3] = mode;
317         buffer[4] = length;
318
319         return sim_apdu_send(ms, buffer, 5);
320 }
321
322 /* 9.2.6 */
323 static int gsm1111_tx_update_record(struct osmocom_ms *ms, uint8_t rec_no,
324         uint8_t mode, uint8_t *data, uint8_t length)
325 {
326         uint8_t buffer[5 + length];
327
328         LOGP(DSIM, LOGL_INFO, "UPDATE RECORD (rec_no=%d mode=%d len=%d)\n",
329                 rec_no, mode, length);
330         buffer[0] = GSM1111_CLASS_GSM;
331         buffer[1] = GSM1111_INST_UPDATE_RECORD;
332         buffer[2] = rec_no;
333         buffer[3] = mode;
334         buffer[4] = length;
335         memcpy(buffer + 5, data, length);
336
337         return sim_apdu_send(ms, buffer, 5 + length);
338 }
339
340 /* 9.2.7 */
341 static int gsm1111_tx_seek(struct osmocom_ms *ms, uint8_t type_mode,
342         uint8_t *pattern, uint8_t length)
343 {
344         uint8_t buffer[5 + length];
345         uint8_t type = type_mode >> 4;
346         uint8_t mode = type_mode & 0x0f;
347
348         LOGP(DSIM, LOGL_INFO, "SEEK (type=%d mode=%d len=%d)\n", type, mode,
349                 length);
350         buffer[0] = GSM1111_CLASS_GSM;
351         buffer[1] = GSM1111_INST_SEEK;
352         buffer[2] = 0x00;
353         buffer[3] = type_mode;
354         buffer[4] = length;
355         memcpy(buffer + 5, pattern, length);
356
357         return sim_apdu_send(ms, buffer, 5 + length);
358 }
359
360 /* 9.2.8 */
361 static int gsm1111_tx_increase(struct osmocom_ms *ms, uint32_t value)
362 {
363         uint8_t buffer[5 + 3];
364
365         LOGP(DSIM, LOGL_INFO, "INCREASE (value=%d)\n", value);
366         buffer[0] = GSM1111_CLASS_GSM;
367         buffer[1] = GSM1111_INST_INCREASE;
368         buffer[2] = 0x00;
369         buffer[3] = 0x00;
370         buffer[4] = 3;
371         buffer[5] = value >> 16;
372         buffer[6] = value >> 8;
373         buffer[7] = value;
374
375         return sim_apdu_send(ms, buffer, 5 + 3);
376 }
377
378 /* 9.2.9 */
379 static int gsm1111_tx_verify_chv(struct osmocom_ms *ms, uint8_t chv_no,
380         uint8_t *chv, uint8_t length)
381 {
382         uint8_t buffer[5 + 8];
383         int i;
384
385         LOGP(DSIM, LOGL_INFO, "VERIFY CHV (CHV%d)\n", chv_no);
386         buffer[0] = GSM1111_CLASS_GSM;
387         buffer[1] = GSM1111_INST_VERIFY_CHV;
388         buffer[2] = 0x00;
389         buffer[3] = chv_no;
390         buffer[4] = 8;
391         for (i = 0; i < 8; i++) {
392                 if (i < length)
393                         buffer[5 + i] = chv[i];
394                 else
395                         buffer[5 + i] = 0xff;
396         }
397
398         return sim_apdu_send(ms, buffer, 5 + 8);
399 }
400
401 /* 9.2.10 */
402 static int gsm1111_tx_change_chv(struct osmocom_ms *ms, uint8_t chv_no,
403         uint8_t *chv_old, uint8_t length_old, uint8_t *chv_new,
404         uint8_t length_new)
405 {
406         uint8_t buffer[5 + 16];
407         int i;
408
409         LOGP(DSIM, LOGL_INFO, "CHANGE CHV (CHV%d)\n", chv_no);
410         buffer[0] = GSM1111_CLASS_GSM;
411         buffer[1] = GSM1111_INST_CHANGE_CHV;
412         buffer[2] = 0x00;
413         buffer[3] = chv_no;
414         buffer[4] = 16;
415         for (i = 0; i < 8; i++) {
416                 if (i < length_old)
417                         buffer[5 + i] = chv_old[i];
418                 else
419                         buffer[5 + i] = 0xff;
420                 if (i < length_new)
421                         buffer[13 + i] = chv_new[i];
422                 else
423                         buffer[13 + i] = 0xff;
424         }
425
426         return sim_apdu_send(ms, buffer, 5 + 16);
427 }
428
429 /* 9.2.11 */
430 static int gsm1111_tx_disable_chv(struct osmocom_ms *ms, uint8_t *chv,
431         uint8_t length)
432 {
433         uint8_t buffer[5 + 8];
434         int i;
435
436         LOGP(DSIM, LOGL_INFO, "DISABLE CHV (CHV1)\n");
437         buffer[0] = GSM1111_CLASS_GSM;
438         buffer[1] = GSM1111_INST_DISABLE_CHV;
439         buffer[2] = 0x00;
440         buffer[3] = 0x01;
441         buffer[4] = 8;
442         for (i = 0; i < 8; i++) {
443                 if (i < length)
444                         buffer[5 + i] = chv[i];
445                 else
446                         buffer[5 + i] = 0xff;
447         }
448
449         return sim_apdu_send(ms, buffer, 5 + 8);
450 }
451
452 /* 9.2.12 */
453 static int gsm1111_tx_enable_chv(struct osmocom_ms *ms, uint8_t *chv,
454         uint8_t length)
455 {
456         uint8_t buffer[5 + 8];
457         int i;
458
459         LOGP(DSIM, LOGL_INFO, "ENABLE CHV (CHV1)\n");
460         buffer[0] = GSM1111_CLASS_GSM;
461         buffer[1] = GSM1111_INST_ENABLE_CHV;
462         buffer[2] = 0x00;
463         buffer[3] = 0x01;
464         buffer[4] = 8;
465         for (i = 0; i < 8; i++) {
466                 if (i < length)
467                         buffer[5 + i] = chv[i];
468                 else
469                         buffer[5 + i] = 0xff;
470         }
471
472         return sim_apdu_send(ms, buffer, 5 + 8);
473 }
474
475 /* 9.2.13 */
476 static int gsm1111_tx_unblock_chv(struct osmocom_ms *ms, uint8_t chv_no,
477         uint8_t *chv_unblk, uint8_t length_unblk, uint8_t *chv_new,
478         uint8_t length_new)
479 {
480         uint8_t buffer[5 + 16];
481         int i;
482
483         LOGP(DSIM, LOGL_INFO, "UNBLOCK CHV (CHV%d)\n", (chv_no == 2) ? 2 : 1);
484         buffer[0] = GSM1111_CLASS_GSM;
485         buffer[1] = GSM1111_INST_UNBLOCK_CHV;
486         buffer[2] = 0x00;
487         buffer[3] = (chv_no == 1) ? 0 : chv_no;
488         buffer[4] = 16;
489         for (i = 0; i < 8; i++) {
490                 if (i < length_unblk)
491                         buffer[5 + i] = chv_unblk[i];
492                 else
493                         buffer[5 + i] = 0xff;
494                 if (i < length_new)
495                         buffer[13 + i] = chv_new[i];
496                 else
497                         buffer[13 + i] = 0xff;
498         }
499
500         return sim_apdu_send(ms, buffer, 5 + 16);
501 }
502
503 /* 9.2.14 */
504 static int gsm1111_tx_invalidate(struct osmocom_ms *ms)
505 {
506         uint8_t buffer[5];
507
508         LOGP(DSIM, LOGL_INFO, "INVALIDATE\n");
509         buffer[0] = GSM1111_CLASS_GSM;
510         buffer[1] = GSM1111_INST_INVALIDATE;
511         buffer[2] = 0x00;
512         buffer[3] = 0x00;
513         buffer[4] = 0;
514
515         return sim_apdu_send(ms, buffer, 5);
516 }
517
518 /* 9.2.15 */
519 static int gsm1111_tx_rehabilitate(struct osmocom_ms *ms)
520 {
521         uint8_t buffer[5];
522
523         LOGP(DSIM, LOGL_INFO, "REHABILITATE\n");
524         buffer[0] = GSM1111_CLASS_GSM;
525         buffer[1] = GSM1111_INST_REHABLILITATE;
526         buffer[2] = 0x00;
527         buffer[3] = 0x00;
528         buffer[4] = 0;
529
530         return sim_apdu_send(ms, buffer, 5);
531 }
532
533 /* 9.2.16 */
534 static int gsm1111_tx_run_gsm_algo(struct osmocom_ms *ms, uint8_t *rand)
535 {
536         uint8_t buffer[5 + 16];
537
538         LOGP(DSIM, LOGL_INFO, "RUN GSM ALGORITHM\n");
539         buffer[0] = GSM1111_CLASS_GSM;
540         buffer[1] = GSM1111_INST_RUN_GSM_ALGO;
541         buffer[2] = 0x00;
542         buffer[3] = 0x00;
543         buffer[4] = 16;
544         memcpy(buffer + 5, rand, 16);
545
546         return sim_apdu_send(ms, buffer, 5 + 16);
547 }
548
549 #if 0
550 /* 9.2.17 */
551 static int gsm1111_tx_sleep(struct osmocom_ms *ms)
552 {
553         uint8_t buffer[5];
554
555         LOGP(DSIM, LOGL_INFO, "\n");
556         buffer[0] = GSM1111_CLASS_GSM;
557         buffer[1] = GSM1111_INST_SLEEP;
558         buffer[2] = 0x00;
559         buffer[3] = 0x00;
560         buffer[4] = 0;
561
562         return sim_apdu_send(ms, buffer, 5);
563 }
564 #endif
565
566 /* 9.2.18 */
567 static int gsm1111_tx_get_response(struct osmocom_ms *ms, uint8_t length)
568 {
569         uint8_t buffer[5];
570
571         LOGP(DSIM, LOGL_INFO, "GET RESPONSE (len=%d)\n", length);
572         buffer[0] = GSM1111_CLASS_GSM;
573         buffer[1] = GSM1111_INST_GET_RESPONSE;
574         buffer[2] = 0x00;
575         buffer[3] = 0x00;
576         buffer[4] = length;
577
578         return sim_apdu_send(ms, buffer, 5);
579 }
580
581 #if 0
582 /* 9.2.19 */
583 static int gsm1111_tx_terminal_profile(struct osmocom_ms *ms, uint8_t *data,
584         uint8_t length)
585 {
586         uint8_t buffer[5 + length];
587
588         LOGP(DSIM, LOGL_INFO, "TERMINAL PROFILE (len=%d)\n", length);
589         buffer[0] = GSM1111_CLASS_GSM;
590         buffer[1] = GSM1111_INST_TERMINAL_PROFILE;
591         buffer[2] = 0x00;
592         buffer[3] = 0x00;
593         buffer[4] = length;
594         memcpy(buffer + 5, data, length);
595
596         return sim_apdu_send(ms, buffer, 5 + length);
597 }
598
599 /* 9.2.20 */
600 static int gsm1111_tx_envelope(struct osmocom_ms *ms, uint8_t *data,
601         uint8_t length)
602 {
603         uint8_t buffer[5 + length];
604
605         LOGP(DSIM, LOGL_INFO, "ENVELOPE (len=%d)\n", length);
606         buffer[0] = GSM1111_CLASS_GSM;
607         buffer[1] = GSM1111_INST_ENVELOPE;
608         buffer[2] = 0x00;
609         buffer[3] = 0x00;
610         buffer[4] = length;
611         memcpy(buffer + 5, data, length);
612
613         return sim_apdu_send(ms, buffer, 5 + length);
614 }
615
616 /* 9.2.21 */
617 static int gsm1111_tx_fetch(struct osmocom_ms *ms, uint8_t length)
618 {
619         uint8_t buffer[5];
620
621         LOGP(DSIM, LOGL_INFO, "FETCH (len=%d)\n", length);
622         buffer[0] = GSM1111_CLASS_GSM;
623         buffer[1] = GSM1111_INST_FETCH;
624         buffer[2] = 0x00;
625         buffer[3] = 0x00;
626         buffer[4] = length;
627
628         return sim_apdu_send(ms, buffer, 5);
629 }
630
631 /* 9.2.22 */
632 static int gsm1111_tx_terminal_response(struct osmocom_ms *ms, uint8_t *data,
633         uint8_t length)
634 {
635         uint8_t buffer[5 + length];
636
637         LOGP(DSIM, LOGL_INFO, "TERMINAL RESPONSE (len=%d)\n", length);
638         buffer[0] = GSM1111_CLASS_GSM;
639         buffer[1] = GSM1111_INST_TERMINAL_RESPONSE;
640         buffer[2] = 0x00;
641         buffer[3] = 0x00;
642         buffer[4] = length;
643         memcpy(buffer + 5, data, length);
644
645         return sim_apdu_send(ms, buffer, 5 + length);
646 }
647 #endif
648
649 /*
650  * SIM state machine
651  */
652
653 /* process job */
654 static int sim_process_job(struct osmocom_ms *ms)
655 {
656         struct gsm_sim *sim = &ms->sim;
657         uint8_t *payload, *payload2;
658         uint16_t payload_len, payload_len2;
659         struct sim_hdr *sh;
660         uint8_t cause;
661         int i;
662
663         /* no current */
664         if (!sim->job_msg)
665                 return 0;
666
667         sh = (struct sim_hdr *)sim->job_msg->data;
668         payload = sim->job_msg->data + sizeof(*sh);
669         payload_len = sim->job_msg->len - sizeof(*sh);
670
671         /* do reset before sim reading */
672         if (!sim->reset) {
673                 sim->reset = 1;
674                 // FIXME: send reset command to L1
675         }
676
677         /* navigate to right DF */
678         switch (sh->job_type) {
679         case SIM_JOB_READ_BINARY:
680         case SIM_JOB_UPDATE_BINARY:
681         case SIM_JOB_READ_RECORD:
682         case SIM_JOB_UPDATE_RECORD:
683         case SIM_JOB_SEEK_RECORD:
684         case SIM_JOB_INCREASE:
685         case SIM_JOB_INVALIDATE:
686         case SIM_JOB_REHABILITATE:
687         case SIM_JOB_RUN_GSM_ALGO:
688                 /* check MF / DF */
689                 i = 0;
690                 while (sh->path[i] && sim->path[i]) {
691                         if (sh->path[i] != sh->path[i])
692                                 break;
693                         i++;
694                 }
695                 /* if path in message is shorter or if paths are different */
696                 if (sim->path[i]) {
697                         LOGP(DSIM, LOGL_INFO, "go MF\n");
698                         sim->job_state = SIM_JST_SELECT_MFDF;
699                         /* go MF */
700                         sim->path[0] = 0;
701                         return gsm1111_tx_select(ms, 0x3f00);
702                 }
703                 /* if path in message is longer */
704                 if (sh->path[i]) {
705                         LOGP(DSIM, LOGL_INFO, "requested path is longer, go "
706                                 "child %s\n", get_df_name(sh->path[i]));
707                         sim->job_state = SIM_JST_SELECT_MFDF;
708                         /* select child */
709                         sim->path[i] = sh->path[i];
710                         sim->path[i + 1] = 0;
711                         return gsm1111_tx_select(ms, sh->path[i]);
712                 }
713                 /* if paths are equal, continue */
714         }
715
716         /* set state and trigger SIM process */
717         switch (sh->job_type) {
718         case SIM_JOB_READ_BINARY:
719         case SIM_JOB_UPDATE_BINARY:
720         case SIM_JOB_READ_RECORD:
721         case SIM_JOB_UPDATE_RECORD:
722         case SIM_JOB_SEEK_RECORD:
723         case SIM_JOB_INCREASE:
724         case SIM_JOB_INVALIDATE:
725         case SIM_JOB_REHABILITATE:
726                 sim->job_state = SIM_JST_SELECT_EF;
727                 sim->file = sh->file;
728                 return gsm1111_tx_select(ms, sh->file);
729         case SIM_JOB_RUN_GSM_ALGO:
730                 if (payload_len != 16) {
731                         LOGP(DSIM, LOGL_ERROR, "random not 16 bytes\n");
732                         break;
733                 }
734                 sim->job_state = SIM_JST_RUN_GSM_ALGO;
735                 return gsm1111_tx_run_gsm_algo(ms, payload);
736         case SIM_JOB_PIN1_UNLOCK:
737                 payload_len = strlen((char *)payload);
738                 if (payload_len < 4 || payload_len > 8) {
739                         LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
740                         break;
741                 }
742                 sim->job_state = SIM_JST_PIN1_UNLOCK;
743                 return gsm1111_tx_verify_chv(ms, 0x01, payload, payload_len);
744         case SIM_JOB_PIN2_UNLOCK:
745                 payload_len = strlen((char *)payload);
746                 if (payload_len < 4 || payload_len > 8) {
747                         LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
748                         break;
749                 }
750                 sim->job_state = SIM_JST_PIN2_UNLOCK;
751                 return gsm1111_tx_verify_chv(ms, 0x02, payload, payload_len);
752         case SIM_JOB_PIN1_CHANGE:
753                 payload_len = strlen((char *)payload);
754                 payload2 = payload + payload_len + 1;
755                 payload_len2 = strlen((char *)payload2);
756                 if (payload_len < 4 || payload_len > 8) {
757                         LOGP(DSIM, LOGL_ERROR, "key1 not in range 4..8\n");
758                         break;
759                 }
760                 if (payload_len2 < 4 || payload_len2 > 8) {
761                         LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
762                         break;
763                 }
764                 sim->job_state = SIM_JST_PIN1_CHANGE;
765                 return gsm1111_tx_change_chv(ms, 0x01, payload, payload_len,
766                         payload2, payload_len2);
767         case SIM_JOB_PIN2_CHANGE:
768                 payload_len = strlen((char *)payload);
769                 payload2 = payload + payload_len + 1;
770                 payload_len2 = strlen((char *)payload2);
771                 if (payload_len < 4 || payload_len > 8) {
772                         LOGP(DSIM, LOGL_ERROR, "key1 not in range 4..8\n");
773                         break;
774                 }
775                 if (payload_len2 < 4 || payload_len2 > 8) {
776                         LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
777                         break;
778                 }
779                 sim->job_state = SIM_JST_PIN2_CHANGE;
780                 return gsm1111_tx_change_chv(ms, 0x02, payload, payload_len,
781                         payload2, payload_len2);
782         case SIM_JOB_PIN1_DISABLE:
783                 payload_len = strlen((char *)payload);
784                 if (payload_len < 4 || payload_len > 8) {
785                         LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
786                         break;
787                 }
788                 sim->job_state = SIM_JST_PIN1_DISABLE;
789                 return gsm1111_tx_disable_chv(ms, payload, payload_len);
790         case SIM_JOB_PIN1_ENABLE:
791                 payload_len = strlen((char *)payload);
792                 if (payload_len < 4 || payload_len > 8) {
793                         LOGP(DSIM, LOGL_ERROR, "key not in range 4..8\n");
794                         break;
795                 }
796                 sim->job_state = SIM_JST_PIN1_ENABLE;
797                 return gsm1111_tx_enable_chv(ms, payload, payload_len);
798         case SIM_JOB_PIN1_UNBLOCK:
799                 payload_len = strlen((char *)payload);
800                 payload2 = payload + payload_len + 1;
801                 payload_len2 = strlen((char *)payload2);
802                 if (payload_len !=  8) {
803                         LOGP(DSIM, LOGL_ERROR, "key1 not 8 digits\n");
804                         break;
805                 }
806                 if (payload_len2 < 4 || payload_len2 > 8) {
807                         LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
808                         break;
809                 }
810                 sim->job_state = SIM_JST_PIN1_UNBLOCK;
811                 /* NOTE: CHV1 is coded 0x00 here */
812                 return gsm1111_tx_unblock_chv(ms, 0x00, payload, payload_len,
813                         payload2, payload_len2);
814         case SIM_JOB_PIN2_UNBLOCK:
815                 payload_len = strlen((char *)payload);
816                 payload2 = payload + payload_len + 1;
817                 payload_len2 = strlen((char *)payload2);
818                 if (payload_len !=  8) {
819                         LOGP(DSIM, LOGL_ERROR, "key1 not 8 digits\n");
820                         break;
821                 }
822                 if (payload_len2 < 4 || payload_len2 > 8) {
823                         LOGP(DSIM, LOGL_ERROR, "key2 not in range 4..8\n");
824                         break;
825                 }
826                 sim->job_state = SIM_JST_PIN2_UNBLOCK;
827                 return gsm1111_tx_unblock_chv(ms, 0x02, payload, payload_len,
828                         payload2, payload_len2);
829         }
830
831         LOGP(DSIM, LOGL_ERROR, "unknown job %x, please fix\n", sh->job_type);
832         cause = SIM_CAUSE_REQUEST_ERROR;
833         gsm_sim_reply(ms, SIM_JOB_ERROR, &cause, 1);
834
835         return 0;
836 }
837
838 /* receive SIM response */
839 int sim_apdu_resp(struct osmocom_ms *ms, struct msgb *msg)
840 {
841         struct gsm_sim *sim = &ms->sim;
842         uint8_t *payload;
843         uint16_t payload_len;
844         uint8_t *data = msg->data;
845         int length = msg->len, ef_len;
846         uint8_t sw1, sw2;
847         uint8_t cause;
848         uint8_t pin_cause[2];
849         struct sim_hdr *sh;
850         struct gsm1111_response_ef *ef;
851         struct gsm1111_response_mfdf *mfdf;
852         struct gsm1111_response_mfdf_gsm *mfdf_gsm;
853         int i;
854
855         /* ignore, if current job already gone */
856         if (!sim->job_msg) {
857                 LOGP(DSIM, LOGL_ERROR, "received APDU but no job, "
858                         "please fix!\n");
859                 msgb_free(msg);
860                 return 0;
861         }
862
863         sh = (struct sim_hdr *)sim->job_msg->data;
864         payload = sim->job_msg->data + sizeof(*sh);
865         payload_len = sim->job_msg->len - sizeof(*sh);
866
867         /* process status */
868         if (length < 2) {
869                 msgb_free(msg);
870                 return 0;
871         }
872         sw1 = data[length - 2];
873         sw2 = data[length - 1];
874         length -= 2;
875         LOGP(DSIM, LOGL_INFO, "received APDU (len=%d sw1=0x%02x sw2=0x%02x)\n",
876                 length, sw1, sw2);
877
878         switch (sw1) {
879         case GSM1111_STAT_SECURITY:
880                 LOGP(DSIM, LOGL_NOTICE, "SIM Security\n");
881                 /* error */
882                 if (sw2 != GSM1111_SEC_NO_ACCESS && sw2 != GSM1111_SEC_BLOCKED)
883                         goto sim_error;
884
885                 /* select the right remaining counter an cause */
886                 // FIXME: read status to replace "*_remain"-counters
887                 switch (sim->job_state) {
888                 case SIM_JST_PIN1_UNBLOCK:
889                         if (sw2 == GSM1111_SEC_NO_ACCESS) {
890                                 pin_cause[0] = SIM_CAUSE_PIN1_BLOCKED;
891                                 pin_cause[1] = --sim->unblk1_remain;
892                         } else {
893                                 pin_cause[0] = SIM_CAUSE_PUC_BLOCKED;
894                                 pin_cause[1] = 0;
895                         }
896                         break;
897                 case SIM_JST_PIN2_UNLOCK:
898                 case SIM_JST_PIN2_CHANGE:
899                         if (sw2 == GSM1111_SEC_NO_ACCESS && sim->chv2_remain) {
900                                 pin_cause[0] = SIM_CAUSE_PIN2_REQUIRED;
901                                 pin_cause[1] = sim->chv2_remain--;
902                         } else {
903                                 pin_cause[0] = SIM_CAUSE_PIN2_BLOCKED;
904                                 pin_cause[1] = sim->unblk2_remain;
905                         }
906                         break;
907                 case SIM_JST_PIN2_UNBLOCK:
908                         if (sw2 == GSM1111_SEC_NO_ACCESS) {
909                                 pin_cause[0] = SIM_CAUSE_PIN2_BLOCKED;
910                                 pin_cause[1] = --sim->unblk2_remain;
911                         } else {
912                                 pin_cause[0] = SIM_CAUSE_PUC_BLOCKED;
913                                 pin_cause[1] = 0;
914                         }
915                 case SIM_JST_PIN1_UNLOCK:
916                 case SIM_JST_PIN1_CHANGE:
917                 case SIM_JST_PIN1_DISABLE:
918                 case SIM_JST_PIN1_ENABLE:
919                 default:
920                         if (sw2 == GSM1111_SEC_NO_ACCESS && sim->chv1_remain) {
921                                 pin_cause[0] = SIM_CAUSE_PIN1_REQUIRED;
922                                 pin_cause[1] = sim->chv1_remain--;
923                         } else {
924                                 pin_cause[0] = SIM_CAUSE_PIN1_BLOCKED;
925                                 pin_cause[1] = sim->unblk1_remain;
926                         }
927                         break;
928                 }
929                 gsm_sim_reply(ms, SIM_JOB_ERROR, pin_cause, 2);
930                 msgb_free(msg);
931                 return 0;
932         case GSM1111_STAT_MEM_PROBLEM:
933                 if (sw2 >= 0x40) {
934                         LOGP(DSIM, LOGL_NOTICE, "memory of SIM failed\n");
935                         sim_error:
936                         cause = SIM_CAUSE_SIM_ERROR;
937                         gsm_sim_reply(ms, SIM_JOB_ERROR, &cause, 1);
938                         msgb_free(msg);
939                         return 0;
940                 }
941                 LOGP(DSIM, LOGL_NOTICE, "memory of SIM is bad (write took %d "
942                         "times to succeed)\n", sw2);
943                 /* fall through */
944         case GSM1111_STAT_NORMAL:
945         case GSM1111_STAT_PROACTIVE:
946         case GSM1111_STAT_DL_ERROR:
947         case GSM1111_STAT_RESPONSE:
948         case GSM1111_STAT_RESPONSE_TOO:
949                 LOGP(DSIM, LOGL_INFO, "command successfull\n");
950                 break;
951         default:
952                 LOGP(DSIM, LOGL_INFO, "command failed\n");
953                 request_error:
954                 cause = SIM_CAUSE_REQUEST_ERROR;
955                 gsm_sim_reply(ms, SIM_JOB_ERROR, &cause, 1);
956                 msgb_free(msg);
957                 return 0;
958         }
959
960
961         switch (sim->job_state) {
962         /* step 1: after selecting MF / DF, request the response */
963         case SIM_JST_SELECT_MFDF:
964                 /* not enough data */
965                 if (sw2 < 22) {
966                         LOGP(DSIM, LOGL_NOTICE, "expecting minimum 22 bytes\n");
967                         goto sim_error;
968                 }
969                 /* request response */
970                 sim->job_state = SIM_JST_SELECT_MFDF_RESP;
971                 gsm1111_tx_get_response(ms, sw2);
972                 msgb_free(msg);
973                 return 0;
974         /* step 2: after getting response of selecting MF / DF, continue
975          * to "process_job".
976          */
977         case SIM_JST_SELECT_MFDF_RESP:
978                 if (length < 22) {
979                         LOGP(DSIM, LOGL_NOTICE, "expecting minimum 22 bytes\n");
980                         goto sim_error;
981                 }
982                 mfdf = (struct gsm1111_response_mfdf *)data;
983                 mfdf_gsm = (struct gsm1111_response_mfdf_gsm *)(data + 13);
984                 sim->chv1_remain = mfdf_gsm->chv1_remain;
985                 sim->chv2_remain = mfdf_gsm->chv2_remain;
986                 sim->unblk1_remain = mfdf_gsm->unblk1_remain;
987                 sim->unblk2_remain = mfdf_gsm->unblk2_remain;
988                 /* if MF was selected */
989                 if (sim->path[0] == 0) {
990                         /* if MF was selected, but MF is not indicated */
991                         if (ntohs(mfdf->file_id) != 0x3f00) {
992                                 LOGP(DSIM, LOGL_NOTICE, "Not MF\n");
993                                 goto sim_error;
994                         }
995                         /* if MF was selected, but type is not indicated */
996                         if (mfdf->tof != GSM1111_TOF_MF) {
997                                 LOGP(DSIM, LOGL_NOTICE, "MF %02x != %02x "
998                                         "%04x\n", mfdf->tof, GSM1111_TOF_MF,
999                                         sim->path[0]);
1000                                 goto sim_error;
1001                         }
1002                         /* now continue */
1003                         msgb_free(msg);
1004                         return sim_process_job(ms);
1005                 }
1006                 /* if DF was selected, but this DF is not indicated */
1007                 i = 0;
1008                 while (sim->path[i + 1])
1009                         i++;
1010                 if (ntohs(mfdf->file_id) != sim->path[i]) {
1011                         LOGP(DSIM, LOGL_NOTICE, "Path %04x != %04x\n",
1012                                 ntohs(mfdf->file_id), sim->path[i]);
1013                         goto sim_error;
1014                 }
1015                 /* if DF was selected, but type is not indicated */
1016                 if (mfdf->tof != GSM1111_TOF_DF) {
1017                         LOGP(DSIM, LOGL_NOTICE, "TOF error\n");
1018                         goto sim_error;
1019                 }
1020                 /* now continue */
1021                 msgb_free(msg);
1022                 return sim_process_job(ms);
1023         /* step 1: after selecting EF, request response of SELECT */
1024         case SIM_JST_SELECT_EF:
1025                 /* not enough data */
1026                 if (sw2 < 14) {
1027                         LOGP(DSIM, LOGL_NOTICE, "expecting minimum 14 bytes\n");
1028                         goto sim_error;
1029                 }
1030                 /* request response */
1031                 sim->job_state = SIM_JST_SELECT_EF_RESP;
1032                 gsm1111_tx_get_response(ms, sw2);
1033                 msgb_free(msg);
1034                 return 0;
1035         /* step 2: after getting response of selecting EF, do file command */
1036         case SIM_JST_SELECT_EF_RESP:
1037                 if (length < 14) {
1038                         LOGP(DSIM, LOGL_NOTICE, "expecting minimum 14 bytes\n");
1039                         goto sim_error;
1040                 }
1041                 ef = (struct gsm1111_response_ef *)data;
1042                 /* if EF was selected, but type is not indicated */
1043                 if (ntohs(ef->file_id) != sim->file) {
1044                         LOGP(DSIM, LOGL_NOTICE, "EF ID %04x != %04x\n",
1045                                 ntohs(ef->file_id), sim->file);
1046                         goto sim_error;
1047                 }
1048                 /* get length of file */
1049                 ef_len = ntohs(ef->file_size);
1050                 /* do file command */
1051                 sim->job_state = SIM_JST_WAIT_FILE;
1052                 switch (sh->job_type) {
1053                 case SIM_JOB_READ_BINARY:
1054                         // FIXME: do chunks when greater or equal 256 bytes */
1055                         gsm1111_tx_read_binary(ms, 0, ef_len);
1056                         break;
1057                 case SIM_JOB_UPDATE_BINARY:
1058                         // FIXME: do chunks when greater or equal 256 bytes */
1059                         if (ef_len < payload_len) {
1060                                 LOGP(DSIM, LOGL_NOTICE, "selected file is "
1061                                         "smaller (%d) than data to update "
1062                                         "(%d)\n", ef_len, payload_len);
1063                                 goto request_error;
1064                         }
1065                         gsm1111_tx_update_binary(ms, 0, payload, payload_len);
1066                         break;
1067                 case SIM_JOB_READ_RECORD:
1068                         gsm1111_tx_read_record(ms, sh->rec_no, sh->rec_mode,
1069                                 ef_len);
1070                         break;
1071                 case SIM_JOB_UPDATE_RECORD:
1072                         if (ef_len != payload_len) {
1073                                 LOGP(DSIM, LOGL_NOTICE, "selected file length "
1074                                         "(%d) does not equal record to update "
1075                                         "(%d)\n", ef_len, payload_len);
1076                                 goto request_error;
1077                         }
1078                         gsm1111_tx_update_record(ms, sh->rec_no, sh->rec_mode,
1079                                 payload, payload_len);
1080                         break;
1081                 case SIM_JOB_SEEK_RECORD:
1082                         gsm1111_tx_seek(ms, sh->seek_type_mode, data, length);
1083                         break;
1084                 case SIM_JOB_INCREASE:
1085                         if (length != 4) {
1086                                 LOGP(DSIM, LOGL_ERROR, "expecting uint32_t as "
1087                                         "value lenght, but got %d bytes\n",
1088                                         length);
1089                                 goto request_error;
1090                         }
1091                         gsm1111_tx_increase(ms, *((uint32_t *)data));
1092                         break;
1093                 case SIM_JOB_INVALIDATE:
1094                         gsm1111_tx_invalidate(ms);
1095                         break;
1096                 case SIM_JOB_REHABILITATE:
1097                         gsm1111_tx_rehabilitate(ms);
1098                         break;
1099                 }
1100                 msgb_free(msg);
1101                 return 0;
1102         /* step 3: after processing file command, job is done */
1103         case SIM_JST_WAIT_FILE:
1104                 /* reply job with data */
1105                 gsm_sim_reply(ms, SIM_JOB_OK, data, length);
1106                 msgb_free(msg);
1107                 return 0;
1108         /* step 1: after running GSM algorithm, request response */
1109         case SIM_JST_RUN_GSM_ALGO:
1110                 /* not enough data */
1111                 if (sw2 < 12) {
1112                         LOGP(DSIM, LOGL_NOTICE, "expecting minimum 12 bytes\n");
1113                         goto sim_error;
1114                 }
1115                 /* request response */
1116                 sim->job_state = SIM_JST_RUN_GSM_ALGO_RESP;
1117                 gsm1111_tx_get_response(ms, sw2);
1118                 msgb_free(msg);
1119                 return 0;
1120         /* step 2: after processing GSM command, job is done */
1121         case SIM_JST_RUN_GSM_ALGO_RESP:
1122                 /* reply job with data */
1123                 gsm_sim_reply(ms, SIM_JOB_OK, data, length);
1124                 msgb_free(msg);
1125                 return 0;
1126         case SIM_JST_PIN1_UNLOCK:
1127         case SIM_JST_PIN1_CHANGE:
1128         case SIM_JST_PIN1_DISABLE:
1129         case SIM_JST_PIN1_ENABLE:
1130         case SIM_JST_PIN1_UNBLOCK:
1131         case SIM_JST_PIN2_UNLOCK:
1132         case SIM_JST_PIN2_CHANGE:
1133         case SIM_JST_PIN2_UNBLOCK:
1134                 /* reply job with data */
1135                 gsm_sim_reply(ms, SIM_JOB_OK, data, length);
1136                 msgb_free(msg);
1137                 return 0;
1138         }
1139
1140         LOGP(DSIM, LOGL_ERROR, "unknown state %u, please fix!\n",
1141                 sim->job_state);
1142         goto request_error;
1143 }
1144
1145 /*
1146  * API
1147  */
1148
1149 /* open access to sim */
1150 uint32_t sim_open(struct osmocom_ms *ms,
1151         void (*cb)(struct osmocom_ms *ms, struct msgb *msg))
1152 {
1153         struct gsm_sim *sim = &ms->sim;
1154         struct gsm_sim_handler *handler;
1155
1156         /* create handler and attach */
1157         handler = talloc_zero(l23_ctx, struct gsm_sim_handler);
1158         if (!handler)
1159                 return 0;
1160         handler->handle = new_handle++;
1161         handler->cb = cb;
1162         llist_add_tail(&handler->entry, &sim->handlers);
1163
1164         return handler->handle;
1165 }
1166
1167 /* close access to sim */
1168 void sim_close(struct osmocom_ms *ms, uint32_t handle)
1169 {
1170         struct gsm_sim *sim = &ms->sim;
1171         struct gsm_sim_handler *handler;
1172
1173         handler = sim_get_handler(sim, handle);
1174         if (!handle)
1175                 return;
1176
1177         /* kill ourself */
1178         llist_del(&handler->entry);
1179         talloc_free(handler);
1180 }
1181
1182 /* send job */
1183 void sim_job(struct osmocom_ms *ms, struct msgb *msg)
1184 {
1185         struct gsm_sim *sim = &ms->sim;
1186
1187         msgb_enqueue(&sim->jobs, msg);
1188 }
1189
1190 /*
1191  * init
1192  */
1193
1194 int gsm_sim_init(struct osmocom_ms *ms)
1195 {
1196         struct gsm_sim *sim = &ms->sim;
1197
1198         /* current path is undefined, forching MF */
1199         sim->path[0] = 0x0bad;
1200         sim->path[1] = 0;
1201         sim->file = 0;
1202
1203         INIT_LLIST_HEAD(&sim->handlers);
1204         INIT_LLIST_HEAD(&sim->jobs);
1205
1206         LOGP(DSIM, LOGL_INFO, "init SIM client\n");
1207
1208         return 0;
1209 }
1210
1211 int gsm_sim_exit(struct osmocom_ms *ms)
1212 {
1213         struct gsm_sim *sim = &ms->sim;
1214         struct gsm_sim_handler *handler, *handler2;
1215         struct msgb *msg;
1216
1217         LOGP(DSIM, LOGL_INFO, "exit SIM client\n");
1218
1219         /* remove pending job msg */
1220         if (sim->job_msg) {
1221                 msgb_free(sim->job_msg);
1222                 sim->job_msg = NULL;
1223         }
1224         /* flush handlers */
1225         llist_for_each_entry_safe(handler, handler2, &sim->handlers, entry)
1226                 sim_close(ms, handler->handle);
1227         /* flush jobs */
1228         while ((msg = msgb_dequeue(&sim->jobs)))
1229                 msgb_free(msg);
1230
1231         return 0;
1232 }
1233
1234
1235
1236