blob: f10b70029690e7b6edff66e779e4e77e100102f0 [file] [log] [blame]
Harald Welte63653742019-01-03 16:54:16 +01001#include <stdlib.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <assert.h>
Harald Welte92e7c0b2019-05-14 09:32:10 +02005#include <string.h>
Harald Welte63653742019-01-03 16:54:16 +01006
7#include <osmocom/core/msgb.h>
8#include <osmocom/core/utils.h>
9
10#include "ccid_proto.h"
11
12#define NR_SLOTS 8
13
14struct ccid_slot {
15 struct ccid_instance *ci;
16 uint8_t slot_nr;
17 bool icc_present;
18 bool icc_powered;
19 bool icc_in_reset;
20};
21
22struct ccid_ops {
Harald Welte92e7c0b2019-05-14 09:32:10 +020023 int (*send_in)(struct ccid_instance *ci, struct msgb *msg);
Harald Welte63653742019-01-03 16:54:16 +010024};
25
26struct ccid_instance {
27 struct ccid_slot slot[NR_SLOTS];
28 struct ccid_ops ops;
29};
30
31#define msgb_ccid_out(x) (union ccid_pc_to_rdr *)msgb_data(x)
32#define msgb_ccid_in(x) (union ccid_rdr_to_pc *)msgb_data(x)
33
34static struct ccid_slot *get_ccid_slot(struct ccid_instance *ci, uint8_t slot_nr)
35{
36 if (slot_nr >= sizeof(ci->slot))
37 return NULL;
38 else
Harald Welte92e7c0b2019-05-14 09:32:10 +020039 return &ci->slot[slot_nr];
Harald Welte63653742019-01-03 16:54:16 +010040}
41
42static uint8_t get_icc_status(const struct ccid_slot *cs)
43{
44 if (cs->icc_present && cs->icc_powered && !cs->icc_in_reset)
45 return CCID_ICC_STATUS_PRES_ACT;
46 else if (!cs->icc_present)
47 return CCID_ICC_STATUS_NO_ICC;
48 else
49 return CCID_ICC_STATUS_PRES_INACT;
50}
51
52#define SET_HDR(x, msg_type, slot, seq) do { \
53 (x)->hdr.bMessageType = msg_type; \
54 (x)->hdr.dwLength = 0; \
55 (x)->hdr.bSlot = slot; \
56 (x)->hdr.bSeq = seq; \
57 } while (0)
58
59#define SET_HDR_IN(x, msg_type, slot, seq, status, error) do { \
60 SET_HDR(&(x)->hdr, msg_type, slot, seq); \
61 (x)->hdr.bStatus = status; \
62 (x)->hdr.bError = error; \
63 } while (0)
64
65/***********************************************************************
66 * Message generation / sending
67 ***********************************************************************/
68
69static struct msgb *ccid_msgb_alloc(void)
70{
Harald Welte92e7c0b2019-05-14 09:32:10 +020071 struct msgb *msg = msgb_alloc(512, "ccid");
Harald Welte63653742019-01-03 16:54:16 +010072 OSMO_ASSERT(msg);
73 return msg;
74}
75
76static int ccid_send(struct ccid_instance *ci, struct msgb *msg)
77{
78 return ci->ops.send_in(ci, msg);
79}
80
81static int ccid_slot_send(struct ccid_slot *cs, struct msgb *msg)
82{
Harald Welte92e7c0b2019-05-14 09:32:10 +020083 struct ccid_header *ch = (struct ccid_header *) msgb_ccid_in(msg);
Harald Welte63653742019-01-03 16:54:16 +010084
85 /* patch bSlotNr into message */
Harald Welte92e7c0b2019-05-14 09:32:10 +020086 ch->bSlot = cs->slot_nr;
Harald Welte63653742019-01-03 16:54:16 +010087 return ccid_send(cs->ci, msg);
88}
89
90
91/* Section 6.2.1 */
92static struct msgb *ccid_gen_data_block(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
93 enum ccid_error_code err, const uint8_t *data,
94 uint32_t data_len)
95{
96 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +020097 struct ccid_rdr_to_pc_data_block *db =
98 (struct ccid_rdr_to_pc_data_block *) msgb_put(msg, sizeof(*db) + data_len);
Harald Welte63653742019-01-03 16:54:16 +010099 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | get_icc_status(cs);
100
101 SET_HDR_IN(db, RDR_to_PC_DataBlock, cs->slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200102 osmo_store32le(data_len, &db->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100103 memcpy(db->abData, data, data_len);
104 return msg;
105}
106
107/* Section 6.2.2 */
108static struct msgb *ccid_gen_slot_status(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
109 enum ccid_error_code err)
110{
111 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200112 struct ccid_rdr_to_pc_slot_status *ss =
113 (struct ccid_rdr_to_pc_slot_status *) msgb_put(msg, sizeof(*ss));
Harald Welte63653742019-01-03 16:54:16 +0100114 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | get_icc_status(cs);
115
116 SET_HDR_IN(ss, RDR_to_PC_SlotStatus, cs->slot_nr, seq, sts, err);
117 return msg;
118}
119
120/* Section 6.2.3 */
121/* TODO */
122
123/* Section 6.2.4 */
124static struct msgb *ccid_gen_escape(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
125 enum ccid_error_code err, const uint8_t *data,
126 uint32_t data_len)
127{
128 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200129 struct ccid_rdr_to_pc_escape *esc =
130 (struct ccid_rdr_to_pc_escape *) msgb_put(msg, sizeof(*esc) + data_len);
Harald Welte63653742019-01-03 16:54:16 +0100131 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | get_icc_status(cs);
132
133 SET_HDR_IN(esc, RDR_to_PC_Escape, cs->slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200134 osmo_store32le(data_len, &esc->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100135 memcpy(esc->abData, data, data_len);
136 return msg;
137}
138
139/* Section 6.2.5 */
140static struct msgb *ccid_gen_clock_and_rate(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
141 enum ccid_error_code err, uint32_t clock_khz, uint32_t rate_bps)
142{
143 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200144 struct ccid_rdr_to_pc_data_rate_and_clock *drc =
145 (struct ccid_rdr_to_pc_data_rate_and_clock *) msgb_put(msg, sizeof(*drc));
Harald Welte63653742019-01-03 16:54:16 +0100146 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | get_icc_status(cs);
147
148 SET_HDR_IN(drc, RDR_to_PC_DataRateAndClockFrequency, cs->slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200149 osmo_store32le(8, &drc->hdr.hdr.dwLength); /* Message-specific data length (wtf?) */
150 osmo_store32le(clock_khz, &drc->dwClockFrequency); /* kHz */
151 osmo_store32le(rate_bps, &drc->dwDataRate); /* bps */
Harald Welte63653742019-01-03 16:54:16 +0100152 return msg;
153}
154
155
156
157#if 0
158static struct msgb *gen_err_resp(struct ccid_instance *ci, enum ccid_msg_type msg_type,
159 enum ccid_error_code err_code)
160{
161 struct c
162}
163#endif
164
165/***********************************************************************
166 * Message reception / parsing
167 ***********************************************************************/
168
169/* Section 6.1.3 */
170static int ccid_handle_get_slot_status(struct ccid_slot *cs, struct msgb *msg)
171{
172 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
173 struct msgb *resp;
174
175 resp = ccid_gen_slot_status(cs, u->get_slot_status.hdr.bSeq, CCID_CMD_STATUS_OK, 0);
176
177 return ccid_send(cs->ci, resp);
178}
179
180
181/* Section 6.1.1 */
182static int ccid_handle_icc_power_on(struct ccid_slot *cs, struct msgb *msg)
183{
184 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
185 struct msgb *resp;
186
187 /* TODO: send actual ATR; handle error cases */
188 /* TODO: handle this asynchronously */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200189 resp = ccid_gen_data_block(cs, u->icc_power_on.hdr.bSeq, CCID_CMD_STATUS_OK, 0, NULL, 0);
Harald Welte63653742019-01-03 16:54:16 +0100190
191 return ccid_send(cs->ci, resp);
192}
193
194/* Section 6.1.2 */
195static int ccid_handle_icc_power_off(struct ccid_slot *cs, struct msgb *msg)
196{
197 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200198 struct msgb *resp;
199
Harald Welte63653742019-01-03 16:54:16 +0100200 resp = ccid_gen_slot_status(cs, u->get_slot_status.hdr.bSeq, CCID_CMD_STATUS_OK, 0);
201 return ccid_send(cs->ci, resp);
202}
203
204/* Section 6.1.4 */
205static int ccid_handle_xfr_block(struct ccid_slot *cs, struct msgb *msg)
206{
207 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200208 struct msgb *resp;
209
210 resp = ccid_gen_data_block(cs, u->icc_power_on.hdr.bSeq, CCID_CMD_STATUS_OK, 0, NULL, 0);
Harald Welte63653742019-01-03 16:54:16 +0100211 return ccid_send(cs->ci, resp);
212}
213
214/* Section 6.1.5 */
215static int ccid_handle_get_parameters(struct ccid_slot *cs, struct msgb *msg)
216{
217 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200218 struct msgb *resp;
Harald Welte63653742019-01-03 16:54:16 +0100219}
220
221/* Section 6.1.6 */
222static int ccid_handle_reset_parameters(struct ccid_slot *cs, struct msgb *msg)
223{
224 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200225 struct msgb *resp;
Harald Welte63653742019-01-03 16:54:16 +0100226}
227
228/* Section 6.1.7 */
229static int ccid_handle_set_parameters(struct ccid_slot *cs, struct msgb *msg)
230{
231 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200232 struct msgb *resp;
Harald Welte63653742019-01-03 16:54:16 +0100233}
234
235/* Section 6.1.8 */
236static int ccid_handle_escape(struct ccid_slot *cs, struct msgb *msg)
237{
238 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200239 struct msgb *resp;
Harald Welte63653742019-01-03 16:54:16 +0100240}
241
242/* Section 6.1.9 */
243static int ccid_handle_icc_clock(struct ccid_slot *cs, struct msgb *msg)
244{
245 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200246 struct msgb *resp;
247
Harald Welte63653742019-01-03 16:54:16 +0100248 resp = ccid_gen_slot_status(cs, u->get_slot_status.hdr.bSeq, CCID_CMD_STATUS_OK, 0);
249 return ccid_send(cs->ci, resp);
250}
251
252/* Section 6.1.10 */
253static int ccid_handle_t0apdu(struct ccid_slot *cs, struct msgb *msg)
254{
255 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200256 struct msgb *resp;
257
Harald Welte63653742019-01-03 16:54:16 +0100258 resp = ccid_gen_slot_status(cs, u->get_slot_status.hdr.bSeq, CCID_CMD_STATUS_OK, 0);
259 return ccid_send(cs->ci, resp);
260}
261
262/* Section 6.1.11 */
263static int ccid_handle_secure(struct ccid_slot *cs, struct msgb *msg)
264{
265 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
266}
267
268/* Section 6.1.12 */
269static int ccid_handle_mechanical(struct ccid_slot *cs, struct msgb *msg)
270{
271 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200272 struct msgb *resp;
273
Harald Welte63653742019-01-03 16:54:16 +0100274 resp = ccid_gen_slot_status(cs, u->get_slot_status.hdr.bSeq, CCID_CMD_STATUS_OK, 0);
275 return ccid_send(cs->ci, resp);
276}
277
278/* Section 6.1.13 */
279static int ccid_handle_abort(struct ccid_slot *cs, struct msgb *msg)
280{
281 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200282 struct msgb *resp;
283
Harald Welte63653742019-01-03 16:54:16 +0100284 resp = ccid_gen_slot_status(cs, u->get_slot_status.hdr.bSeq, CCID_CMD_STATUS_OK, 0);
285 return ccid_send(cs->ci, resp);
286}
287
288/* Section 6.1.14 */
289static int ccid_handle_set_rate_and_clock(struct ccid_slot *cs, struct msgb *msg)
290{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200291 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
292 struct msgb *resp;
Harald Welte63653742019-01-03 16:54:16 +0100293}
294
295/* handle data arriving from the host on the OUT endpoint */
296int ccid_handle_out(struct ccid_instance *ci, struct msgb *msg)
297{
298 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
299 const struct ccid_header *ch = (const struct ccid_header *) u;
300 unsigned int len = msgb_length(msg);
301 struct ccid_slot *cs;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200302 int rc;
Harald Welte63653742019-01-03 16:54:16 +0100303
304 if (len < sizeof(*ch)) {
305 /* FIXME */
306 return -1;
307 }
308
Harald Welte92e7c0b2019-05-14 09:32:10 +0200309 cs = get_ccid_slot(ci, ch->bSlot);
Harald Welte63653742019-01-03 16:54:16 +0100310 if (!cs) {
311 /* FIXME */
312 return -1;
313 }
314
315 switch (ch->bMessageType) {
316 case PC_to_RDR_GetSlotStatus:
317 if (len != sizeof(u->get_slot_status))
318 goto short_msg;
319 rc = ccid_handle_get_slot_status(cs, msg);
320 break;
321 case PC_to_RDR_IccPowerOn:
322 if (len != sizeof(u->icc_power_on))
323 goto short_msg;
324 rc = ccid_handle_icc_power_on(cs, msg);
325 break;
326 case PC_to_RDR_IccPowerOff:
327 if (len != sizeof(u->icc_power_off))
328 goto short_msg;
329 rc = ccid_handle_icc_power_off(cs, msg);
330 break;
331 case PC_to_RDR_XfrBlock:
332 if (len < sizeof(u->xfr_block))
333 goto short_msg;
334 rc = ccid_handle_xfr_block(cs, msg);
335 break;
336 case PC_to_RDR_GetParameters:
337 if (len != sizeof(u->get_parameters))
338 goto short_msg;
339 rc = ccid_handle_get_parameters(cs, msg);
340 break;
341 case PC_to_RDR_ResetParameters:
342 if (len != sizeof(u->reset_parameters))
343 goto short_msg;
344 rc = ccid_handle_reset_parameters(cs, msg);
345 break;
346 case PC_to_RDR_SetParameters:
347 if (len != sizeof(u->set_parameters))
348 goto short_msg;
349 rc = ccid_handle_set_parameters(cs, msg);
350 break;
351 case PC_to_RDR_Escape:
352 if (len < sizeof(u->escape))
353 goto short_msg;
354 rc = ccid_handle_escape(cs, msg);
355 break;
356 case PC_to_RDR_IccClock:
357 if (len != sizeof(u->icc_clock))
358 goto short_msg;
359 rc = ccid_handle_icc_clock(cs, msg);
360 break;
361 case PC_to_RDR_T0APDU:
362 if (len != /*FIXME*/ sizeof(u->t0apdu))
363 goto short_msg;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200364 rc = ccid_handle_t0apdu(cs, msg);
Harald Welte63653742019-01-03 16:54:16 +0100365 break;
366 case PC_to_RDR_Secure:
367 if (len < sizeof(u->secure))
368 goto short_msg;
369 rc = ccid_handle_secure(cs, msg);
370 break;
371 case PC_to_RDR_Mechanical:
372 if (len != sizeof(u->mechanical))
373 goto short_msg;
374 rc = ccid_handle_mechanical(cs, msg);
375 break;
376 case PC_to_RDR_Abort:
377 if (len != sizeof(u->abort))
378 goto short_msg;
379 rc = ccid_handle_abort(cs, msg);
380 break;
381 case PC_to_RDR_SetDataRateAndClockFrequency:
382 if (len != sizeof(u->set_rate_and_clock))
383 goto short_msg;
384 rc = ccid_handle_set_rate_and_clock(cs, msg);
385 break;
386 default:
Harald Welte92e7c0b2019-05-14 09:32:10 +0200387 /* FIXME */
Harald Welte63653742019-01-03 16:54:16 +0100388 break;
389 }
Harald Welte92e7c0b2019-05-14 09:32:10 +0200390 return 0;
391
Harald Welte63653742019-01-03 16:54:16 +0100392short_msg:
Harald Welte92e7c0b2019-05-14 09:32:10 +0200393 /* FIXME */
394 return -1;
Harald Welte63653742019-01-03 16:54:16 +0100395}