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