• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "sim_card.h"
13 #include <string.h>
14 #include <assert.h>
15 #include <stdio.h>
16 
17 /* set ENABLE_DYNAMIC_RECORDS to 1 to enable dynamic records
18  * for now, this is an experimental feature that needs more testing
19  */
20 #define  ENABLE_DYNAMIC_RECORDS  0
21 
22 #define  A_SIM_PIN_SIZE  4
23 #define  A_SIM_PUK_SIZE  8
24 
25 typedef struct ASimCardRec_ {
26     ASimStatus  status;
27     char        pin[ A_SIM_PIN_SIZE+1 ];
28     char        puk[ A_SIM_PUK_SIZE+1 ];
29     int         pin_retries;
30     int         port;
31 
32     char        out_buff[ 256 ];
33     int         out_size;
34 
35 } ASimCardRec;
36 
37 static ASimCardRec  _s_card[1];
38 
39 ASimCard
asimcard_create(int port)40 asimcard_create(int port)
41 {
42     ASimCard  card    = _s_card;
43     card->status      = A_SIM_STATUS_READY;
44     card->pin_retries = 0;
45     strncpy( card->pin, "0000", sizeof(card->pin) );
46     strncpy( card->puk, "12345678", sizeof(card->puk) );
47     card->port = port;
48     return card;
49 }
50 
51 void
asimcard_destroy(ASimCard card)52 asimcard_destroy( ASimCard  card )
53 {
54     /* nothing really */
55     card=card;
56 }
57 
58 static __inline__ int
asimcard_ready(ASimCard card)59 asimcard_ready( ASimCard  card )
60 {
61     return card->status == A_SIM_STATUS_READY;
62 }
63 
64 ASimStatus
asimcard_get_status(ASimCard sim)65 asimcard_get_status( ASimCard  sim )
66 {
67     return sim->status;
68 }
69 
70 void
asimcard_set_status(ASimCard sim,ASimStatus status)71 asimcard_set_status( ASimCard  sim, ASimStatus  status )
72 {
73     sim->status = status;
74 }
75 
76 const char*
asimcard_get_pin(ASimCard sim)77 asimcard_get_pin( ASimCard  sim )
78 {
79     return sim->pin;
80 }
81 
82 const char*
asimcard_get_puk(ASimCard sim)83 asimcard_get_puk( ASimCard  sim )
84 {
85     return sim->puk;
86 }
87 
88 void
asimcard_set_pin(ASimCard sim,const char * pin)89 asimcard_set_pin( ASimCard  sim, const char*  pin )
90 {
91     strncpy( sim->pin, pin, A_SIM_PIN_SIZE );
92     sim->pin_retries = 0;
93 }
94 
95 void
asimcard_set_puk(ASimCard sim,const char * puk)96 asimcard_set_puk( ASimCard  sim, const char*  puk )
97 {
98     strncpy( sim->puk, puk, A_SIM_PUK_SIZE );
99     sim->pin_retries = 0;
100 }
101 
102 
103 int
asimcard_check_pin(ASimCard sim,const char * pin)104 asimcard_check_pin( ASimCard  sim, const char*  pin )
105 {
106     if (sim->status != A_SIM_STATUS_PIN   &&
107         sim->status != A_SIM_STATUS_READY )
108         return 0;
109 
110     if ( !strcmp( sim->pin, pin ) ) {
111         sim->status      = A_SIM_STATUS_READY;
112         sim->pin_retries = 0;
113         return 1;
114     }
115 
116     if (sim->status != A_SIM_STATUS_READY) {
117         if (++sim->pin_retries == 3)
118             sim->status = A_SIM_STATUS_PUK;
119     }
120     return 0;
121 }
122 
123 
124 int
asimcard_check_puk(ASimCard sim,const char * puk,const char * pin)125 asimcard_check_puk( ASimCard  sim, const char* puk, const char*  pin )
126 {
127     if (sim->status != A_SIM_STATUS_PUK)
128         return 0;
129 
130     if ( !strcmp( sim->puk, puk ) ) {
131         strncpy( sim->puk, puk, A_SIM_PUK_SIZE );
132         strncpy( sim->pin, pin, A_SIM_PIN_SIZE );
133         sim->status      = A_SIM_STATUS_READY;
134         sim->pin_retries = 0;
135         return 1;
136     }
137 
138     if ( ++sim->pin_retries == 6 ) {
139         sim->status = A_SIM_STATUS_ABSENT;
140     }
141     return 0;
142 }
143 
144 typedef enum {
145     SIM_FILE_DM = 0,
146     SIM_FILE_DF,
147     SIM_FILE_EF_DEDICATED,
148     SIM_FILE_EF_LINEAR,
149     SIM_FILE_EF_CYCLIC
150 } SimFileType;
151 
152 typedef enum {
153     SIM_FILE_READ_ONLY       = (1 << 0),
154     SIM_FILE_NEED_PIN = (1 << 1),
155 } SimFileFlags;
156 
157 /* descriptor for a known SIM File */
158 #define  SIM_FILE_HEAD       \
159     SimFileType     type;    \
160     unsigned short  id;      \
161     unsigned short  flags;
162 
163 typedef struct {
164     SIM_FILE_HEAD
165 } SimFileAnyRec, *SimFileAny;
166 
167 typedef struct {
168     SIM_FILE_HEAD
169     cbytes_t   data;
170     int        length;
171 } SimFileEFDedicatedRec, *SimFileEFDedicated;
172 
173 typedef struct {
174     SIM_FILE_HEAD
175     byte_t     rec_count;
176     byte_t     rec_len;
177     cbytes_t   records;
178 } SimFileEFLinearRec, *SimFileEFLinear;
179 
180 typedef SimFileEFLinearRec   SimFileEFCyclicRec;
181 typedef SimFileEFCyclicRec*  SimFileEFCyclic;
182 
183 typedef union {
184     SimFileAnyRec          any;
185     SimFileEFDedicatedRec  dedicated;
186     SimFileEFLinearRec     linear;
187     SimFileEFCyclicRec     cyclic;
188 } SimFileRec, *SimFile;
189 
190 
191 #if ENABLE_DYNAMIC_RECORDS
192 /* convert a SIM File descriptor into an ASCII string,
193    assumes 'dst' is NULL or properly sized.
194    return the number of chars, or -1 on error */
195 static int
sim_file_to_hex(SimFile file,bytes_t dst)196 sim_file_to_hex( SimFile  file, bytes_t  dst )
197 {
198     SimFileType  type   = file->any.type;
199     int          result = 0;
200 
201     /* see 9.2.1 in TS 51.011 */
202     switch (type) {
203         case SIM_FILE_EF_DEDICATED:
204         case SIM_FILE_EF_LINEAR:
205         case SIM_FILE_EF_CYCLIC:
206             {
207                 if (dst) {
208                     int  file_size, perm;
209 
210                     memcpy(dst, "0000", 4);  /* bytes 1-2 are RFU */
211                     dst += 4;
212 
213                     /* bytes 3-4 are the file size */
214                     if (type == SIM_FILE_EF_DEDICATED)
215                         file_size = file->dedicated.length;
216                     else
217                         file_size = file->linear.rec_count * file->linear.rec_len;
218 
219                     gsm_hex_from_short( dst, file_size );
220                     dst += 4;
221 
222                     /* bytes 5-6 are the file id */
223                     gsm_hex_from_short( dst, file->any.id );
224                     dst += 4;
225 
226                     /* byte 7 is the file type - always EF, i.e. 0x04 */
227                     dst[0] = '0';
228                     dst[1] = '4';
229                     dst   += 2;
230 
231                     /* byte 8 is RFU, except bit 7 for cyclic files, which indicates
232                        that INCREASE is allowed. Since we don't support this yet... */
233                     dst[0] = '0';
234                     dst[1] = '0';
235                     dst   += 2;
236 
237                     /* byte 9-11 are access conditions */
238                     if (file->any.flags & SIM_FILE_READ_ONLY) {
239                         if (file->any.flags & SIM_FILE_NEED_PIN)
240                             perm = 0x1a;
241                         else
242                             perm = 0x0a;
243                     } else {
244                         if (file->any.flags & SIM_FILE_NEED_PIN)
245                             perm = 0x11;
246                         else
247                             perm = 0x00;
248                     }
249                     gsm_hex_from_byte(dst, perm);
250                     memcpy( dst+2, "a0aa", 4 );
251                     dst += 6;
252 
253                     /* byte 12 is file status, we don't support invalidation */
254                     dst[0] = '0';
255                     dst[1] = '0';
256                     dst   += 2;
257 
258                     /* byte 13 is length of the following data, always 2 */
259                     dst[0] = '0';
260                     dst[1] = '2';
261                     dst   += 2;
262 
263                     /* byte 14 is struct of EF */
264                     dst[0] = '0';
265                     if (type == SIM_FILE_EF_DEDICATED)
266                         dst[1] = '0';
267                     else if (type == SIM_FILE_EF_LINEAR)
268                         dst[1] = '1';
269                     else
270                         dst[1] = '3';
271 
272                     /* byte 15 is lenght of record, or 0 */
273                     if (type == SIM_FILE_EF_DEDICATED) {
274                         dst[0] = '0';
275                         dst[1] = '0';
276                     } else
277                         gsm_hex_from_byte( dst, file->linear.rec_len );
278                 }
279                 result = 30;
280             }
281             break;
282 
283         default:
284             result = -1;
285     }
286     return result;
287 }
288 
289 
290 static const byte_t  _const_spn_cphs[20] = {
291     0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0xff, 0xff, 0xff,
292     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
293 };
294 
295 static const byte_t  _const_voicemail_cphs[1] = {
296     0x55
297 };
298 
299 static const byte_t  _const_iccid[10] = {
300     0x98, 0x10, 0x14, 0x30, 0x12, 0x11, 0x81, 0x15, 0x70, 0x02
301 };
302 
303 static const byte_t  _const_cff_cphs[1] = {
304     0x55
305 };
306 
307 static SimFileEFDedicatedRec  _const_files_dedicated[] =
308 {
309     { SIM_FILE_EF_DEDICATED, 0x6f14, SIM_FILE_READ_ONLY | SIM_FILE_NEED_PIN,
310       _const_spn_cphs, sizeof(_const_spn_cphs) },
311 
312     { SIM_FILE_EF_DEDICATED, 0x6f11, SIM_FILE_NEED_PIN,
313       _const_voicemail_cphs, sizeof(_const_voicemail_cphs) },
314 
315     { SIM_FILE_EF_DEDICATED, 0x2fe2, SIM_FILE_READ_ONLY,
316       _const_iccid, sizeof(_const_iccid) },
317 
318     { SIM_FILE_EF_DEDICATED, 0x6f13, SIM_FILE_NEED_PIN,
319       _const_cff_cphs, sizeof(_const_cff_cphs) },
320 
321     { 0, 0, 0, NULL, 0 }  /* end of list */
322 };
323 #endif /* ENABLE_DYNAMIC_RECORDS */
324 
325 const char*
asimcard_io(ASimCard sim,const char * cmd)326 asimcard_io( ASimCard  sim, const char*  cmd )
327 {
328     int  nn;
329 #if ENABLE_DYNAMIC_RECORDS
330     int  command, id, p1, p2, p3;
331 #endif
332     static const struct { const char*  cmd; const char*  answer; } answers[] =
333     {
334         { "+CRSM=192,28436,0,0,15", "+CRSM: 144,0,000000146f1404001aa0aa01020000" },
335         { "+CRSM=176,28436,0,0,20", "+CRSM: 144,0,416e64726f6964ffffffffffffffffffffffffff" },
336 
337         { "+CRSM=192,28433,0,0,15", "+CRSM: 144,0,000000016f11040011a0aa01020000" },
338         { "+CRSM=176,28433,0,0,1", "+CRSM: 144,0,55" },
339 
340         { "+CRSM=192,12258,0,0,15", "+CRSM: 144,0,0000000a2fe204000fa0aa01020000" },
341         { "+CRSM=176,12258,0,0,10", "+CRSM: 144,0,98101430121181157002" },
342 
343         { "+CRSM=192,28435,0,0,15", "+CRSM: 144,0,000000016f13040011a0aa01020000" },
344         { "+CRSM=176,28435,0,0,1",  "+CRSM: 144,0,55" },
345 
346         { "+CRSM=192,28472,0,0,15", "+CRSM: 144,0,0000000f6f3804001aa0aa01020000" },
347         { "+CRSM=176,28472,0,0,15", "+CRSM: 144,0,ff30ffff3c003c03000c0000f03f00" },
348 
349         { "+CRSM=192,28617,0,0,15", "+CRSM: 144,0,000000086fc9040011a0aa01020104" },
350         { "+CRSM=178,28617,1,4,4",  "+CRSM: 144,0,01000000" },
351 
352         { "+CRSM=192,28618,0,0,15", "+CRSM: 144,0,0000000a6fca040011a0aa01020105" },
353         { "+CRSM=178,28618,1,4,5",  "+CRSM: 144,0,0000000000" },
354 
355         { "+CRSM=192,28589,0,0,15", "+CRSM: 144,0,000000046fad04000aa0aa01020000" },
356         { "+CRSM=176,28589,0,0,4",  "+CRSM: 144,0,00000003" },
357 
358         { "+CRSM=192,28438,0,0,15", "+CRSM: 144,0,000000026f1604001aa0aa01020000" },
359         { "+CRSM=176,28438,0,0,2",  "+CRSM: 144,0,0233" },
360 
361         { "+CRSM=192,28486,0,0,15", "+CRSM: 148,4" },
362         { "+CRSM=192,28621,0,0,15", "+CRSM: 148,4" },
363 
364         { "+CRSM=192,28613,0,0,15", "+CRSM: 144,0,000000f06fc504000aa0aa01020118" },
365         { "+CRSM=178,28613,1,4,24", "+CRSM: 144,0,43058441aa890affffffffffffffffffffffffffffffffff" },
366 
367         { "+CRSM=192,28480,0,0,15", "+CRSM: 144,0,000000806f40040011a0aa01020120" },
368         { "+CRSM=178,28480,1,4,32", "+CRSM: 144,0,ffffffffffffffffffffffffffffffffffff07815155258131f5ffffffffffff" },
369 
370         { "+CRSM=192,28615,0,0,15", "+CRSM: 144,0,000000406fc7040011a0aa01020120" },
371         { "+CRSM=178,28615,1,4,32", "+CRSM: 144,0,566f6963656d61696cffffffffffffffffff07915155125740f9ffffffffffff" },
372 
373         { NULL, NULL }
374     };
375 
376     assert( memcmp( cmd, "+CRSM=", 6 ) == 0 );
377 
378 #if ENABLE_DYNAMIC_RECORDS
379     if ( sscanf(cmd, "+CRSM=%d,%d,%d,%d,%d", &command, &id, &p1, &p2, &p3) == 5 ) {
380         switch (command) {
381             case A_SIM_CMD_GET_RESPONSE:
382                 {
383                     const SimFileEFDedicatedRec*  file = _const_files_dedicated;
384 
385                     assert(p1 == 0 && p2 == 0 && p3 == 15);
386 
387                     for ( ; file->id != 0; file++ ) {
388                         if (file->id == id) {
389                             int    count;
390                             char*  out = sim->out_buff;
391                             strcpy( out, "+CRSM: 144,0," );
392                             out  += strlen(out);
393                             count = sim_file_to_hex( (SimFile) file, out );
394                             if (count < 0)
395                                 return "ERROR: INTERNAL SIM ERROR";
396                             out[count] = 0;
397                             return sim->out_buff;
398                         }
399                     }
400                     break;
401                 }
402 
403             case A_SIM_CMD_READ_BINARY:
404                 {
405                     const SimFileEFDedicatedRec*  file = _const_files_dedicated;
406 
407                     assert(p1 == 0 && p2 == 0);
408 
409                     for ( ; file->id != 0; file++ ) {
410                         if (file->id == id) {
411                             char*  out = sim->out_buff;
412 
413                             if (p3 > file->length)
414                                 return "ERROR: BINARY LENGTH IS TOO LONG";
415 
416                             strcpy( out, "+CRSM: 144,0," );
417                             out  += strlen(out);
418                             gsm_hex_from_bytes( out, file->data, p3 );
419                             out[p3*2] = 0;
420                             return sim->out_buff;
421                         }
422                     }
423                     break;
424                 }
425 
426             case A_SIM_CMD_READ_RECORD:
427                 break;
428 
429             default:
430                 return "ERROR: UNSUPPORTED SIM COMMAND";
431         }
432     }
433 #endif
434 
435     if (!strcmp("+CRSM=178,28480,1,4,32", cmd)) {
436         snprintf( sim->out_buff, sizeof(sim->out_buff), "+CRSM: 144,0,ffffffffffffffffffffffffffffffffffff0781515525%d1%d%df%dffffffffffff", (sim->port / 1000) % 10, (sim->port / 10) % 10, (sim->port / 100) % 10, sim->port % 10);
437         return sim->out_buff;
438         }
439 
440     for (nn = 0; answers[nn].cmd != NULL; nn++) {
441         if ( !strcmp( answers[nn].cmd, cmd ) ) {
442             return answers[nn].answer;
443         }
444     }
445     return "ERROR: BAD COMMAND";
446 }
447 
448