blob: 869075217c7fa36aa4952ee29d8b72b351bcb3c0 [file] [log] [blame]
Harald Weltead418632012-09-10 10:49:59 +02001/* Core routines for SIM/UICC/USIM access */
2/*
3 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
4 *
5 * 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 as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23
Harald Welted54c2ee2012-01-17 18:25:50 +010024#include <stdlib.h>
25#include <stdint.h>
26
27#include <osmocom/core/talloc.h>
28#include <osmocom/sim/sim.h>
29
Harald Weltead418632012-09-10 10:49:59 +020030struct osim_decoded_data *osim_file_decode(struct osim_file *file,
31 int len, uint8_t *data)
32{
33 struct osim_decoded_data *dd;
34
35 if (!file->desc->ops.parse)
36 return NULL;
37
38 dd = talloc_zero(file, struct osim_decoded_data);
39 dd->file = file;
40
41 if (file->desc->ops.parse(dd, file->desc, len, data) < 0) {
42 talloc_free(dd);
43 return NULL;
44 } else
45 return dd;
46}
47
48struct msgb *osim_file_encode(const struct osim_file_desc *desc,
49 const struct osim_decoded_data *data)
50{
51 if (!desc->ops.encode)
52 return NULL;
53
54 return desc->ops.encode(desc, data);
55}
56
Harald Welted54c2ee2012-01-17 18:25:50 +010057static struct osim_decoded_element *
58__element_alloc(void *ctx, const char *name, enum osim_element_type type,
59 enum osim_element_repr repr)
60{
61 struct osim_decoded_element *elem;
62
63 elem = talloc_zero(ctx, struct osim_decoded_element);
64 if (!elem)
65 return NULL;
66 elem->name = name;
67 elem->type = type;
68 elem->representation = repr;
69
70 if (elem->type == ELEM_T_GROUP)
71 INIT_LLIST_HEAD(&elem->u.siblings);
72
73 return elem;
74}
75
76
77struct osim_decoded_element *
78element_alloc(struct osim_decoded_data *dd, const char *name,
79 enum osim_element_type type, enum osim_element_repr repr)
80{
81 struct osim_decoded_element *elem;
82
83 elem = __element_alloc(dd, name, type, repr);
84 if (!elem)
85 return NULL;
86
87 llist_add_tail(&elem->list, &dd->decoded_elements);
88
89 return elem;
90}
91
92struct osim_decoded_element *
93element_alloc_sub(struct osim_decoded_element *ee, const char *name,
94 enum osim_element_type type, enum osim_element_repr repr)
95{
96 struct osim_decoded_element *elem;
97
98 elem = __element_alloc(ee, name, type, repr);
99 if (!elem)
100 return NULL;
101
102 llist_add(&elem->list, &ee->u.siblings);
103
104 return elem;
105}
106
107
108void add_filedesc(struct osim_file_desc *root, const struct osim_file_desc *in, int num)
109{
110 int i;
111
112 for (i = 0; i < num; i++) {
113 struct osim_file_desc *ofd = talloc_memdup(root, &in[i], sizeof(*in));
114 llist_add_tail(&ofd->list, &root->child_list);
115 }
116}
117
118struct osim_file_desc *alloc_df(void *ctx, uint16_t fid, const char *name)
119{
120 struct osim_file_desc *mf;
121
122 mf = talloc_zero(ctx, struct osim_file_desc);
123 mf->type = TYPE_DF;
124 mf->fid = fid;
125 mf->short_name = name;
126 INIT_LLIST_HEAD(&mf->child_list);
127
128 return mf;
129}
130
131struct osim_file_desc *
132add_df_with_ef(struct osim_file_desc *parent,
133 uint16_t fid, const char *name,
134 const struct osim_file_desc *in, int num)
135{
136 struct osim_file_desc *df;
137
138 df = alloc_df(parent, fid, name);
139 df->parent = parent;
140 llist_add_tail(&df->list, &parent->child_list);
141 add_filedesc(df, in, num);
142
143 return df;
144}
145
146struct osim_file_desc *
147add_adf_with_ef(struct osim_file_desc *parent,
148 const uint8_t *adf_name, uint8_t adf_name_len,
149 const char *name, const struct osim_file_desc *in,
150 int num)
151{
152 struct osim_file_desc *df;
153
154 df = alloc_df(parent, 0xffff, name);
155 df->type = TYPE_ADF;
156 df->df_name = adf_name;
157 df->df_name_len = adf_name_len;
158 df->parent = parent;
159 llist_add_tail(&df->list, &parent->child_list);
160 add_filedesc(df, in, num);
161
162 return df;
163}
164
165struct osim_file_desc *
166osim_file_find_name(struct osim_file_desc *parent, const char *name)
167{
168 struct osim_file_desc *ofd;
169 llist_for_each_entry(ofd, &parent->child_list, list) {
170 if (!strcmp(ofd->short_name, name)) {
171 return ofd;
172 }
173 }
174 return NULL;
175}
176
Kevin Redon0f0ee322012-09-11 11:40:41 +0200177/* create an APDU header
178 * APDU format as defined in ISO/IEC 7816-4:2005(E) ยง5.1
179 * - cla: CLASS byte
180 * - ins: INSTRUCTION byte
181 * - p1: Parameter 1 byte
182 * - p2: Parameter 2 byte
183 * - lc: number of bytes in the command data field Nc, which will encoded in 0, 1 or 3 bytes into Lc
184 * - le: maximum number of bytes expected in the response data field, which will encoded in 0, 1, 2 or 3 bytes into Le
185 */
Harald Welted54c2ee2012-01-17 18:25:50 +0100186struct msgb *osim_new_apdumsg(uint8_t cla, uint8_t ins, uint8_t p1,
187 uint8_t p2, uint16_t lc, uint16_t le)
188{
189 struct osim_apdu_cmd_hdr *ch;
190 struct msgb *msg = msgb_alloc(lc+le+sizeof(*ch)+2, "APDU");
191 if (!msg)
192 return NULL;
193
194 ch = (struct osim_apdu_cmd_hdr *) msgb_put(msg, sizeof(*ch));
195 msg->l2h = (char *) ch;
196
197 ch->cla = cla;
198 ch->ins = ins;
199 ch->p1 = p1;
200 ch->p2 = p2;
201
202 msgb_apdu_lc(msg) = lc;
203 msgb_apdu_le(msg) = le;
204
205 if (lc == 0 && le == 0)
206 msgb_apdu_case(msg) = APDU_CASE_1;
207 else if (lc == 0 && le >= 1) {
208 if (le <= 256)
209 msgb_apdu_case(msg) = APDU_CASE_2;
210 else
211 msgb_apdu_case(msg) = APDU_CASE_2_EXT;
212 } else if (le == 0 && lc >= 1) {
213 if (lc <= 255)
214 msgb_apdu_case(msg) = APDU_CASE_3;
215 else
216 msgb_apdu_case(msg) = APDU_CASE_3_EXT;
217 } else if (lc >= 1 && le >= 1) {
218 if (lc <= 255 & le <= 256)
219 msgb_apdu_case(msg) = APDU_CASE_4;
220 else
221 msgb_apdu_case(msg) = APDU_CASE_4_EXT;
222 }
223
224 return msg;
225}