blob: 02d159998bfa9fe8fd226517b9289cabaec6d159 [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
Harald Welte8579ce52019-05-15 12:22:24 +020014struct ccid_pars_decoded {
15 /* global for T0/T1 */
16 uint8_t fi;
17 uint8_t di;
18 enum ccid_clock_stop clock_stop;
19 bool inverse_convention;
20
21 struct {
22 uint8_t guard_time_etu;
23 uint8_t waiting_integer;
24 } t0;
25
26 struct {
27 enum ccid_t1_csum_type csum_type;
28 uint8_t guard_time_t1;
29 uint8_t bwi;
30 uint8_t cwi;
31 uint8_t ifsc;
32 uint8_t nad;
33 } t1;
34};
35
Harald Welte63653742019-01-03 16:54:16 +010036struct ccid_slot {
37 struct ccid_instance *ci;
38 uint8_t slot_nr;
39 bool icc_present;
40 bool icc_powered;
41 bool icc_in_reset;
Harald Welte8772f582019-05-14 16:34:47 +020042 bool cmd_busy;
Harald Welte8579ce52019-05-15 12:22:24 +020043 struct ccid_pars_decoded pars;
Harald Welte63653742019-01-03 16:54:16 +010044};
45
Harald Welte8579ce52019-05-15 12:22:24 +020046/* decode on-the-wire T0 parameters into their parsed form */
47static int decode_ccid_pars_t0(struct ccid_pars_decoded *out, const struct ccid_proto_data_t0 *in)
48{
49 /* input validation: only 0x00 and 0x02 permitted for bmTCCKST0 */
50 if (in->bmTCCKST0 & 0xFD)
51 return -11;
52 /* input validation: only 0x00 to 0x03 permitted for bClockSTop */
53 if (in->bClockStop & 0xFC)
54 return -14;
55
56 out->fi = in->bmFindexDindex >> 4;
57 out->di = in->bmFindexDindex & 0xF;
58 if (in->bmTCCKST0 & 2)
59 out->inverse_convention = true;
60 else
61 out->inverse_convention = false;
62 if (in->bGuardTimeT0 == 0xff)
63 out->t0.guard_time_etu = 0;
64 else
65 out->t0.guard_time_etu = in->bGuardTimeT0;
66 out->t0.waiting_integer = in->bWaitingIntegerT0;
67 out->clock_stop = in->bClockStop & 0x03;
68
69 return 0;
70}
71
72/* encode T0 parameters from parsed form into on-the-wire encoding */
73static void encode_ccid_pars_t0(struct ccid_proto_data_t0 *out, const struct ccid_pars_decoded *in)
74{
75 out->bmFindexDindex = ((in->fi << 4) & 0xF0) | (in->di & 0x0F);
76 if (in->inverse_convention)
77 out->bmTCCKST0 = 0x02;
78 else
79 out->bmTCCKST0 = 0x00;
80 out->bGuardTimeT0 = in->t0.guard_time_etu;
81 out->bWaitingIntegerT0 = in->t0.waiting_integer;
82 out->bClockStop = in->clock_stop & 0x03;
83}
84
85/* decode on-the-wire T1 parameters into their parsed form */
86static int decode_ccid_pars_t1(struct ccid_pars_decoded *out, const struct ccid_proto_data_t1 *in)
87{
88 /* input validation: only some values permitted for bmTCCKST0 */
89 if (in->bmTCCKST1 & 0xE8)
90 return -11;
91 /* input validation: only 0x00 to 0x9F permitted for bmWaitingIntegersT1 */
92 if (in->bWaitingIntegersT1 > 0x9F)
93 return -13;
94 /* input validation: only 0x00 to 0x03 permitted for bClockSTop */
95 if (in->bClockStop & 0xFC)
96 return -14;
97 /* input validation: only 0x00 to 0xFE permitted for bIFSC */
98 if (in->bIFSC > 0xFE)
99 return -15;
100
101 out->fi = in->bmFindexDindex >> 4;
102 out->di = in->bmFindexDindex & 0xF;
103 if (in->bmTCCKST1 & 1)
104 out->t1.csum_type = CCID_CSUM_TYPE_CRC;
105 else
106 out->t1.csum_type = CCID_CSUM_TYPE_LRC;
107 if (in->bmTCCKST1 & 2)
108 out->inverse_convention = true;
109 else
110 out->inverse_convention = false;
111 out->t1.guard_time_t1 = in->bGuardTimeT1;
112 out->t1.bwi = in->bWaitingIntegersT1 >> 4;
113 out->t1.cwi = in->bWaitingIntegersT1 & 0xF;
114 out->clock_stop = in->bClockStop & 0x03;
115 out->t1.ifsc = in->bIFSC;
116 out->t1.nad = in->bNadValue;
117
118 return 0;
119}
120
121/* encode T1 parameters from parsed form into on-the-wire encoding */
122static void encode_ccid_pars_t1(struct ccid_proto_data_t1 *out, const struct ccid_pars_decoded *in)
123{
124 out->bmFindexDindex = ((in->fi << 4) & 0xF0) | (in->di & 0x0F);
125 out->bmTCCKST1 = 0x10;
126 if (in->t1.csum_type == CCID_CSUM_TYPE_CRC)
127 out->bmTCCKST1 |= 0x01;
128 if (in->inverse_convention)
129 out->bmTCCKST1 |= 0x02;
130 out->bGuardTimeT1 = in->t1.guard_time_t1;
131 out->bWaitingIntegersT1 = ((in->t1.bwi << 4) & 0xF0) | (in->t1.cwi & 0x0F);
132 out->bClockStop = in->clock_stop & 0x03;
133 out->bIFSC = in->t1.ifsc;
134 out->bNadValue = in->t1.nad;
135}
136
Harald Welte63653742019-01-03 16:54:16 +0100137struct ccid_ops {
Harald Welte92e7c0b2019-05-14 09:32:10 +0200138 int (*send_in)(struct ccid_instance *ci, struct msgb *msg);
Harald Welte63653742019-01-03 16:54:16 +0100139};
140
141struct ccid_instance {
142 struct ccid_slot slot[NR_SLOTS];
143 struct ccid_ops ops;
Harald Welte8772f582019-05-14 16:34:47 +0200144 const char *name;
Harald Welte63653742019-01-03 16:54:16 +0100145};
146
147#define msgb_ccid_out(x) (union ccid_pc_to_rdr *)msgb_data(x)
148#define msgb_ccid_in(x) (union ccid_rdr_to_pc *)msgb_data(x)
149
Harald Welte8772f582019-05-14 16:34:47 +0200150#define LOGPCI(ci, lvl, fmt, args ...) LOGP(DCCID, lvl, "%s: " fmt, (ci)->name, ## args)
151#define LOGPCS(cs, lvl, fmt, args ...) \
152 LOGP(DCCID, lvl, "%s(%u): " fmt, (cc)->ci->name, (cc)->slot_nr, ## args)
153
Harald Welte63653742019-01-03 16:54:16 +0100154static struct ccid_slot *get_ccid_slot(struct ccid_instance *ci, uint8_t slot_nr)
155{
156 if (slot_nr >= sizeof(ci->slot))
157 return NULL;
158 else
Harald Welte92e7c0b2019-05-14 09:32:10 +0200159 return &ci->slot[slot_nr];
Harald Welte63653742019-01-03 16:54:16 +0100160}
161
162static uint8_t get_icc_status(const struct ccid_slot *cs)
163{
164 if (cs->icc_present && cs->icc_powered && !cs->icc_in_reset)
165 return CCID_ICC_STATUS_PRES_ACT;
166 else if (!cs->icc_present)
167 return CCID_ICC_STATUS_NO_ICC;
168 else
169 return CCID_ICC_STATUS_PRES_INACT;
170}
171
172#define SET_HDR(x, msg_type, slot, seq) do { \
173 (x)->hdr.bMessageType = msg_type; \
174 (x)->hdr.dwLength = 0; \
175 (x)->hdr.bSlot = slot; \
176 (x)->hdr.bSeq = seq; \
177 } while (0)
178
179#define SET_HDR_IN(x, msg_type, slot, seq, status, error) do { \
180 SET_HDR(&(x)->hdr, msg_type, slot, seq); \
181 (x)->hdr.bStatus = status; \
182 (x)->hdr.bError = error; \
183 } while (0)
184
Harald Welte8772f582019-05-14 16:34:47 +0200185#if 0
186static uint8_t ccid_pc_to_rdr_get_seq(const struct ccid_pc_to_rdr *u)
187{
188 const struct ccid_header *ch = (const struct ccid_header *) u;
189 return ch->bSeq;
190}
191#endif
192
Harald Welte63653742019-01-03 16:54:16 +0100193/***********************************************************************
194 * Message generation / sending
195 ***********************************************************************/
196
197static struct msgb *ccid_msgb_alloc(void)
198{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200199 struct msgb *msg = msgb_alloc(512, "ccid");
Harald Welte63653742019-01-03 16:54:16 +0100200 OSMO_ASSERT(msg);
201 return msg;
202}
203
Harald Welte8772f582019-05-14 16:34:47 +0200204/* Send given CCID message */
Harald Welte63653742019-01-03 16:54:16 +0100205static int ccid_send(struct ccid_instance *ci, struct msgb *msg)
206{
207 return ci->ops.send_in(ci, msg);
208}
209
Harald Welte8772f582019-05-14 16:34:47 +0200210/* Send given CCID message for given slot; patch bSlot into message */
Harald Welte63653742019-01-03 16:54:16 +0100211static int ccid_slot_send(struct ccid_slot *cs, struct msgb *msg)
212{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200213 struct ccid_header *ch = (struct ccid_header *) msgb_ccid_in(msg);
Harald Welte63653742019-01-03 16:54:16 +0100214
215 /* patch bSlotNr into message */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200216 ch->bSlot = cs->slot_nr;
Harald Welte63653742019-01-03 16:54:16 +0100217 return ccid_send(cs->ci, msg);
218}
219
Harald Welte8772f582019-05-14 16:34:47 +0200220/* Send given CCID message and mark slot as un-busy */
221static int ccid_slot_send_unbusy(struct ccid_slot *cs, struct msgb *msg)
222{
223 cs->cmd_busy = false;
224 return ccid_slot_send(cs, msg);
225}
Harald Welte63653742019-01-03 16:54:16 +0100226
227/* Section 6.2.1 */
Harald Welte8772f582019-05-14 16:34:47 +0200228static struct msgb *ccid_gen_data_block_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq,
229 uint8_t cmd_sts, enum ccid_error_code err,
230 const uint8_t *data, uint32_t data_len)
Harald Welte63653742019-01-03 16:54:16 +0100231{
232 struct msgb *msg = ccid_msgb_alloc();
Harald Welte8772f582019-05-14 16:34:47 +0200233 struct ccid_rdr_to_pc_data_block *db =
Harald Welte92e7c0b2019-05-14 09:32:10 +0200234 (struct ccid_rdr_to_pc_data_block *) msgb_put(msg, sizeof(*db) + data_len);
Harald Welte8772f582019-05-14 16:34:47 +0200235 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100236
Harald Welte8772f582019-05-14 16:34:47 +0200237 SET_HDR_IN(db, RDR_to_PC_DataBlock, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200238 osmo_store32le(data_len, &db->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100239 memcpy(db->abData, data, data_len);
240 return msg;
241}
Harald Welte8772f582019-05-14 16:34:47 +0200242static struct msgb *ccid_gen_data_block(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
243 enum ccid_error_code err, const uint8_t *data,
244 uint32_t data_len)
245{
246 return ccid_gen_data_block_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, data, data_len);
247}
Harald Welte63653742019-01-03 16:54:16 +0100248
249/* Section 6.2.2 */
Harald Welte8772f582019-05-14 16:34:47 +0200250static struct msgb *ccid_gen_slot_status_nr(uint8_t slot_nr, uint8_t icc_status,
251 uint8_t seq, uint8_t cmd_sts,
252 enum ccid_error_code err)
Harald Welte63653742019-01-03 16:54:16 +0100253{
254 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200255 struct ccid_rdr_to_pc_slot_status *ss =
256 (struct ccid_rdr_to_pc_slot_status *) msgb_put(msg, sizeof(*ss));
Harald Welte8772f582019-05-14 16:34:47 +0200257 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100258
Harald Welte8772f582019-05-14 16:34:47 +0200259 SET_HDR_IN(ss, RDR_to_PC_SlotStatus, slot_nr, seq, sts, err);
Harald Welte63653742019-01-03 16:54:16 +0100260 return msg;
261}
Harald Welte8772f582019-05-14 16:34:47 +0200262static struct msgb *ccid_gen_slot_status(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
263 enum ccid_error_code err)
264{
265 return ccid_gen_slot_status_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err);
266}
Harald Welte63653742019-01-03 16:54:16 +0100267
268/* Section 6.2.3 */
Harald Welte8772f582019-05-14 16:34:47 +0200269static struct msgb *ccid_gen_parameters_t0_nr(uint8_t slot_nr, uint8_t icc_status,
270 uint8_t seq, uint8_t cmd_sts, enum ccid_error_code err,
Harald Welte8579ce52019-05-15 12:22:24 +0200271 const struct ccid_pars_decoded *dec_par)
Harald Welte8772f582019-05-14 16:34:47 +0200272{
273 struct msgb *msg = ccid_msgb_alloc();
274 struct ccid_rdr_to_pc_parameters *par =
Harald Welte8579ce52019-05-15 12:22:24 +0200275 (struct ccid_rdr_to_pc_parameters *) msgb_put(msg, sizeof(par->hdr)+sizeof(par->abProtocolData.t0));
Harald Welte8772f582019-05-14 16:34:47 +0200276 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
277
278 SET_HDR_IN(par, RDR_to_PC_Parameters, slot_nr, seq, sts, err);
Harald Welte8579ce52019-05-15 12:22:24 +0200279 if (dec_par) {
280 osmo_store32le(sizeof(par->abProtocolData.t0), &par->hdr.hdr.dwLength);
281 encode_ccid_pars_t0(&par->abProtocolData.t0, dec_par);
Harald Welte8772f582019-05-14 16:34:47 +0200282 }
283 return msg;
284}
285static struct msgb *ccid_gen_parameters_t0(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
Harald Welte8579ce52019-05-15 12:22:24 +0200286 enum ccid_error_code err)
Harald Welte8772f582019-05-14 16:34:47 +0200287{
Harald Welte8579ce52019-05-15 12:22:24 +0200288 return ccid_gen_parameters_t0_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, &cs->pars);
Harald Welte8772f582019-05-14 16:34:47 +0200289}
290
291static struct msgb *ccid_gen_parameters_t1_nr(uint8_t slot_nr, uint8_t icc_status,
292 uint8_t seq, uint8_t cmd_sts, enum ccid_error_code err,
Harald Welte8579ce52019-05-15 12:22:24 +0200293 const struct ccid_pars_decoded *dec_par)
Harald Welte8772f582019-05-14 16:34:47 +0200294{
295 struct msgb *msg = ccid_msgb_alloc();
296 struct ccid_rdr_to_pc_parameters *par =
Harald Welte8579ce52019-05-15 12:22:24 +0200297 (struct ccid_rdr_to_pc_parameters *) msgb_put(msg, sizeof(par->hdr)+sizeof(par->abProtocolData.t1));
Harald Welte8772f582019-05-14 16:34:47 +0200298 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
299
300 SET_HDR_IN(par, RDR_to_PC_Parameters, slot_nr, seq, sts, err);
Harald Welte8579ce52019-05-15 12:22:24 +0200301 if (dec_par) {
302 osmo_store32le(sizeof(par->abProtocolData.t1), &par->hdr.hdr.dwLength);
303 encode_ccid_pars_t1(&par->abProtocolData.t1, dec_par);
Harald Welte8772f582019-05-14 16:34:47 +0200304 }
305 return msg;
306}
307static struct msgb *ccid_gen_parameters_t1(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
Harald Welte8579ce52019-05-15 12:22:24 +0200308 enum ccid_error_code err)
Harald Welte8772f582019-05-14 16:34:47 +0200309{
Harald Welte8579ce52019-05-15 12:22:24 +0200310 return ccid_gen_parameters_t1_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, &cs->pars);
Harald Welte8772f582019-05-14 16:34:47 +0200311}
312
Harald Welte63653742019-01-03 16:54:16 +0100313
314/* Section 6.2.4 */
Harald Welte8772f582019-05-14 16:34:47 +0200315static struct msgb *ccid_gen_escape_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq, uint8_t cmd_sts,
316 enum ccid_error_code err, const uint8_t *data, uint32_t data_len)
Harald Welte63653742019-01-03 16:54:16 +0100317{
318 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200319 struct ccid_rdr_to_pc_escape *esc =
320 (struct ccid_rdr_to_pc_escape *) msgb_put(msg, sizeof(*esc) + data_len);
Harald Welte8772f582019-05-14 16:34:47 +0200321 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100322
Harald Welte8772f582019-05-14 16:34:47 +0200323 SET_HDR_IN(esc, RDR_to_PC_Escape, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200324 osmo_store32le(data_len, &esc->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100325 memcpy(esc->abData, data, data_len);
326 return msg;
327}
Harald Welte8772f582019-05-14 16:34:47 +0200328static struct msgb *ccid_gen_escape(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
329 enum ccid_error_code err, const uint8_t *data,
330 uint32_t data_len)
331{
332 return ccid_gen_escape_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, data, data_len);
333}
Harald Welte63653742019-01-03 16:54:16 +0100334
335/* Section 6.2.5 */
Harald Welte8772f582019-05-14 16:34:47 +0200336static struct msgb *ccid_gen_clock_and_rate_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq,
337 uint8_t cmd_sts, enum ccid_error_code err,
338 uint32_t clock_khz, uint32_t rate_bps)
Harald Welte63653742019-01-03 16:54:16 +0100339{
340 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200341 struct ccid_rdr_to_pc_data_rate_and_clock *drc =
342 (struct ccid_rdr_to_pc_data_rate_and_clock *) msgb_put(msg, sizeof(*drc));
Harald Welte8772f582019-05-14 16:34:47 +0200343 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100344
Harald Welte8772f582019-05-14 16:34:47 +0200345 SET_HDR_IN(drc, RDR_to_PC_DataRateAndClockFrequency, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200346 osmo_store32le(8, &drc->hdr.hdr.dwLength); /* Message-specific data length (wtf?) */
347 osmo_store32le(clock_khz, &drc->dwClockFrequency); /* kHz */
348 osmo_store32le(rate_bps, &drc->dwDataRate); /* bps */
Harald Welte63653742019-01-03 16:54:16 +0100349 return msg;
350}
Harald Welte8772f582019-05-14 16:34:47 +0200351static struct msgb *ccid_gen_clock_and_rate(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
352 enum ccid_error_code err, uint32_t clock_khz,
353 uint32_t rate_bps)
Harald Welte63653742019-01-03 16:54:16 +0100354{
Harald Welte8772f582019-05-14 16:34:47 +0200355 return ccid_gen_clock_and_rate_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err,
356 clock_khz, rate_bps);
Harald Welte63653742019-01-03 16:54:16 +0100357}
Harald Welte8772f582019-05-14 16:34:47 +0200358
359/*! generate an error response for given input message_type/slot_nr/seq
360 * \param[in] msg_type CCID Message Type against which response is to be created
361 * \param[in] slot_nr CCID Slot Number
362 * \param[in] icc_status ICC Status of the slot
363 * \param[in] seq CCID Sequence number
364 * \param[in] err_code CCID Error Code to send
365 * \returns dynamically-allocated message buffer containing error response */
366static struct msgb *gen_err_resp(enum ccid_msg_type msg_type, uint8_t slot_nr, uint8_t icc_status,
367 uint8_t seq, enum ccid_error_code err_code)
368{
369 struct msgb *resp = NULL;
370
371 switch (msg_type) {
372 case PC_to_RDR_IccPowerOn:
373 case PC_to_RDR_XfrBlock:
374 case PC_to_RDR_Secure:
375 /* Return RDR_to_PC_DataBlock */
376 resp = ccid_gen_data_block_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
377 err_code, NULL, 0);
378 break;
379
380 case PC_to_RDR_IccPowerOff:
381 case PC_to_RDR_GetSlotStatus:
382 case PC_to_RDR_IccClock:
383 case PC_to_RDR_T0APDU:
384 case PC_to_RDR_Mechanical:
385 case PC_to_RDR_Abort:
386 /* Return RDR_to_PC_SlotStatus */
387 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
388 err_code);
389 break;
390
391 case PC_to_RDR_GetParameters:
392 case PC_to_RDR_ResetParameters:
393 case PC_to_RDR_SetParameters:
394 /* Return RDR_to_PC_Parameters */
395 resp = ccid_gen_parameters_t0_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
396 err_code, NULL); /* FIXME: parameters? */
397 break;
398
399 case PC_to_RDR_Escape:
400 /* Return RDR_to_PC_Escape */
401 resp = ccid_gen_escape_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
402 err_code, NULL, 0);
403 break;
404
405 case PC_to_RDR_SetDataRateAndClockFrequency:
406 /* Return RDR_to_PC_SlotStatus */
407 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
408 err_code);
409 break;
410
411 default:
412 /* generate general error */
413 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
414 CCID_ERR_CMD_NOT_SUPPORTED);
415 break;
416 }
417 return resp;
418}
Harald Welte63653742019-01-03 16:54:16 +0100419
420/***********************************************************************
421 * Message reception / parsing
422 ***********************************************************************/
423
424/* Section 6.1.3 */
425static int ccid_handle_get_slot_status(struct ccid_slot *cs, struct msgb *msg)
426{
427 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200428 const struct ccid_header *ch = (const struct ccid_header *) u;
429 uint8_t seq = u->get_slot_status.hdr.bSeq;
Harald Welte63653742019-01-03 16:54:16 +0100430 struct msgb *resp;
431
Harald Welte8772f582019-05-14 16:34:47 +0200432 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte63653742019-01-03 16:54:16 +0100433
Harald Welte8772f582019-05-14 16:34:47 +0200434 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100435}
436
437
438/* Section 6.1.1 */
439static int ccid_handle_icc_power_on(struct ccid_slot *cs, struct msgb *msg)
440{
441 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200442 const struct ccid_header *ch = (const struct ccid_header *) u;
443 uint8_t seq = u->icc_power_on.hdr.bSeq;
Harald Welte63653742019-01-03 16:54:16 +0100444 struct msgb *resp;
445
446 /* TODO: send actual ATR; handle error cases */
447 /* TODO: handle this asynchronously */
Harald Welte8772f582019-05-14 16:34:47 +0200448 resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
Harald Welte63653742019-01-03 16:54:16 +0100449
Harald Welte8772f582019-05-14 16:34:47 +0200450 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100451}
452
453/* Section 6.1.2 */
454static int ccid_handle_icc_power_off(struct ccid_slot *cs, struct msgb *msg)
455{
456 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200457 const struct ccid_header *ch = (const struct ccid_header *) u;
458 uint8_t seq = u->icc_power_off.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200459 struct msgb *resp;
460
Harald Welte8772f582019-05-14 16:34:47 +0200461 /* FIXME */
462 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
463 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100464}
465
466/* Section 6.1.4 */
467static int ccid_handle_xfr_block(struct ccid_slot *cs, struct msgb *msg)
468{
469 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200470 const struct ccid_header *ch = (const struct ccid_header *) u;
471 uint8_t seq = u->xfr_block.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200472 struct msgb *resp;
473
Harald Welte8772f582019-05-14 16:34:47 +0200474 /* FIXME */
475 resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
476 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100477}
478
479/* Section 6.1.5 */
480static int ccid_handle_get_parameters(struct ccid_slot *cs, struct msgb *msg)
481{
482 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200483 const struct ccid_header *ch = (const struct ccid_header *) u;
484 uint8_t seq = u->get_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200485 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200486
Harald Welte8579ce52019-05-15 12:22:24 +0200487 /* FIXME: T=1 */
488 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte8772f582019-05-14 16:34:47 +0200489 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100490}
491
492/* Section 6.1.6 */
493static int ccid_handle_reset_parameters(struct ccid_slot *cs, struct msgb *msg)
494{
495 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200496 const struct ccid_header *ch = (const struct ccid_header *) u;
497 uint8_t seq = u->reset_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200498 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200499
Harald Welte8579ce52019-05-15 12:22:24 +0200500 /* FIXME: copy default parameters from somewhere */
501 /* FIXME: T=1 */
502 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte8772f582019-05-14 16:34:47 +0200503 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100504}
505
506/* Section 6.1.7 */
507static int ccid_handle_set_parameters(struct ccid_slot *cs, struct msgb *msg)
508{
509 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8579ce52019-05-15 12:22:24 +0200510 const struct ccid_pc_to_rdr_set_parameters *spar = &u->set_parameters;
Harald Welte8772f582019-05-14 16:34:47 +0200511 const struct ccid_header *ch = (const struct ccid_header *) u;
512 uint8_t seq = u->set_parameters.hdr.bSeq;
Harald Welte8579ce52019-05-15 12:22:24 +0200513 struct ccid_pars_decoded pars_dec;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200514 struct msgb *resp;
Harald Welte8579ce52019-05-15 12:22:24 +0200515 int rc;
Harald Welte8772f582019-05-14 16:34:47 +0200516
Harald Welte8579ce52019-05-15 12:22:24 +0200517 switch (spar->bProtocolNum) {
518 case CCID_PROTOCOL_NUM_T0:
519 rc = decode_ccid_pars_t0(&pars_dec, &spar->abProtocolData.t0);
520 if (rc < 0)
521 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_FAILED, -rc);
522 /* FIXME: validate parameters; abort if they are not supported */
523 cs->pars = pars_dec;
524 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_OK, 0);
525 break;
526 case CCID_PROTOCOL_NUM_T1:
527 rc = decode_ccid_pars_t1(&pars_dec, &spar->abProtocolData.t1);
528 if (rc < 0)
529 resp = ccid_gen_parameters_t1(cs, seq, CCID_CMD_STATUS_FAILED, -rc);
530 /* FIXME: validate parameters; abort if they are not supported */
531 cs->pars = pars_dec;
532 resp = ccid_gen_parameters_t1(cs, seq, CCID_CMD_STATUS_OK, 0);
533 break;
534 default:
535 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_FAILED, 0);
536 break;
537 }
Harald Welte8772f582019-05-14 16:34:47 +0200538 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100539}
540
541/* Section 6.1.8 */
542static int ccid_handle_escape(struct ccid_slot *cs, struct msgb *msg)
543{
544 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200545 const struct ccid_header *ch = (const struct ccid_header *) u;
546 uint8_t seq = u->escape.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200547 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200548
549 resp = ccid_gen_escape(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED, NULL, 0);
550 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100551}
552
553/* Section 6.1.9 */
554static int ccid_handle_icc_clock(struct ccid_slot *cs, struct msgb *msg)
555{
556 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200557 const struct ccid_header *ch = (const struct ccid_header *) u;
558 uint8_t seq = u->icc_clock.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200559 struct msgb *resp;
560
Harald Welte8772f582019-05-14 16:34:47 +0200561 /* FIXME: Actually Stop/Start the clock */
562 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
563 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100564}
565
566/* Section 6.1.10 */
567static int ccid_handle_t0apdu(struct ccid_slot *cs, struct msgb *msg)
568{
569 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200570 const struct ccid_header *ch = (const struct ccid_header *) u;
571 uint8_t seq = u->t0apdu.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200572 struct msgb *resp;
573
Harald Welte8772f582019-05-14 16:34:47 +0200574 /* FIXME */
575 //resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
576 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
577 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100578}
579
580/* Section 6.1.11 */
581static int ccid_handle_secure(struct ccid_slot *cs, struct msgb *msg)
582{
583 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200584 const struct ccid_header *ch = (const struct ccid_header *) u;
585 uint8_t seq = u->secure.hdr.bSeq;
586 struct msgb *resp;
587
588 /* FIXME */
589 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
590 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100591}
592
593/* Section 6.1.12 */
594static int ccid_handle_mechanical(struct ccid_slot *cs, struct msgb *msg)
595{
596 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200597 const struct ccid_header *ch = (const struct ccid_header *) u;
598 uint8_t seq = u->mechanical.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200599 struct msgb *resp;
600
Harald Welte8772f582019-05-14 16:34:47 +0200601 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
602 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100603}
604
605/* Section 6.1.13 */
606static int ccid_handle_abort(struct ccid_slot *cs, struct msgb *msg)
607{
608 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200609 const struct ccid_header *ch = (const struct ccid_header *) u;
610 uint8_t seq = u->abort.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200611 struct msgb *resp;
612
Harald Welte8772f582019-05-14 16:34:47 +0200613 /* Check if the currently in-progress message is Abortable */
614 switch (0/* FIXME */) {
615 case PC_to_RDR_IccPowerOn:
616 case PC_to_RDR_XfrBlock:
617 case PC_to_RDR_Escape:
618 case PC_to_RDR_Secure:
619 case PC_to_RDR_Mechanical:
620 //case PC_to_RDR_Abort: /* seriously? WTF! */
621 break;
622 default:
623 /* CCID spec lists CMD_NOT_ABORTED, but gives no numberic value ?!? */
624 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
625 return ccid_slot_send_unbusy(cs, resp);
626 }
627
628 /* FIXME */
629 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
630 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100631}
632
633/* Section 6.1.14 */
634static int ccid_handle_set_rate_and_clock(struct ccid_slot *cs, struct msgb *msg)
635{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200636 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200637 const struct ccid_header *ch = (const struct ccid_header *) u;
638 uint8_t seq = u->set_rate_and_clock.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200639 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200640
641 /* FIXME */
642 resp = ccid_gen_clock_and_rate(cs, seq, CCID_CMD_STATUS_OK, 0, 9600, 2500000);
643 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100644}
645
Harald Welte8772f582019-05-14 16:34:47 +0200646/*! Handle data arriving from the host on the OUT endpoint.
647 * \param[in] cs CCID Instance on which to operate
648 * \param[in] msgb received message buffer containing one CCID OUT EP message from the host
649 * \returns 0 on success; negative on error */
Harald Welte63653742019-01-03 16:54:16 +0100650int ccid_handle_out(struct ccid_instance *ci, struct msgb *msg)
651{
652 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
653 const struct ccid_header *ch = (const struct ccid_header *) u;
654 unsigned int len = msgb_length(msg);
655 struct ccid_slot *cs;
Harald Welte8772f582019-05-14 16:34:47 +0200656 struct msgb *resp;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200657 int rc;
Harald Welte63653742019-01-03 16:54:16 +0100658
659 if (len < sizeof(*ch)) {
660 /* FIXME */
661 return -1;
662 }
663
Harald Welte8772f582019-05-14 16:34:47 +0200664 /* Check for invalid slot number */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200665 cs = get_ccid_slot(ci, ch->bSlot);
Harald Welte63653742019-01-03 16:54:16 +0100666 if (!cs) {
Harald Welte8772f582019-05-14 16:34:47 +0200667 resp = gen_err_resp(ch->bMessageType, ch->bSlot, CCID_ICC_STATUS_NO_ICC, ch->bSeq, 5);
668 return ccid_send(ci, resp);
Harald Welte63653742019-01-03 16:54:16 +0100669 }
670
Harald Welte8772f582019-05-14 16:34:47 +0200671 /* Check if slot is already busy; Reject any additional commands meanwhile */
672 if (cs->cmd_busy) {
673 /* FIXME: ABORT logic as per section 5.3.1 of CCID Spec v1.1 */
674 resp = gen_err_resp(ch->bMessageType, ch->bSlot, get_icc_status(cs), ch->bSeq,
675 CCID_ERR_CMD_SLOT_BUSY);
676 return ccid_send(ci, resp);
677 }
678
679 /* we're now processing a command for the slot; mark slot as busy */
680 cs->cmd_busy = true;
681
682 /* TODO: enqueue into the per-slot specific input queue */
683
Harald Welte63653742019-01-03 16:54:16 +0100684 switch (ch->bMessageType) {
685 case PC_to_RDR_GetSlotStatus:
686 if (len != sizeof(u->get_slot_status))
687 goto short_msg;
688 rc = ccid_handle_get_slot_status(cs, msg);
689 break;
690 case PC_to_RDR_IccPowerOn:
691 if (len != sizeof(u->icc_power_on))
692 goto short_msg;
693 rc = ccid_handle_icc_power_on(cs, msg);
694 break;
695 case PC_to_RDR_IccPowerOff:
696 if (len != sizeof(u->icc_power_off))
697 goto short_msg;
698 rc = ccid_handle_icc_power_off(cs, msg);
699 break;
700 case PC_to_RDR_XfrBlock:
701 if (len < sizeof(u->xfr_block))
702 goto short_msg;
703 rc = ccid_handle_xfr_block(cs, msg);
704 break;
705 case PC_to_RDR_GetParameters:
706 if (len != sizeof(u->get_parameters))
707 goto short_msg;
708 rc = ccid_handle_get_parameters(cs, msg);
709 break;
710 case PC_to_RDR_ResetParameters:
711 if (len != sizeof(u->reset_parameters))
712 goto short_msg;
713 rc = ccid_handle_reset_parameters(cs, msg);
714 break;
715 case PC_to_RDR_SetParameters:
716 if (len != sizeof(u->set_parameters))
717 goto short_msg;
718 rc = ccid_handle_set_parameters(cs, msg);
719 break;
720 case PC_to_RDR_Escape:
721 if (len < sizeof(u->escape))
722 goto short_msg;
723 rc = ccid_handle_escape(cs, msg);
724 break;
725 case PC_to_RDR_IccClock:
726 if (len != sizeof(u->icc_clock))
727 goto short_msg;
728 rc = ccid_handle_icc_clock(cs, msg);
729 break;
730 case PC_to_RDR_T0APDU:
731 if (len != /*FIXME*/ sizeof(u->t0apdu))
732 goto short_msg;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200733 rc = ccid_handle_t0apdu(cs, msg);
Harald Welte63653742019-01-03 16:54:16 +0100734 break;
735 case PC_to_RDR_Secure:
736 if (len < sizeof(u->secure))
737 goto short_msg;
738 rc = ccid_handle_secure(cs, msg);
739 break;
740 case PC_to_RDR_Mechanical:
741 if (len != sizeof(u->mechanical))
742 goto short_msg;
743 rc = ccid_handle_mechanical(cs, msg);
744 break;
745 case PC_to_RDR_Abort:
746 if (len != sizeof(u->abort))
747 goto short_msg;
748 rc = ccid_handle_abort(cs, msg);
749 break;
750 case PC_to_RDR_SetDataRateAndClockFrequency:
751 if (len != sizeof(u->set_rate_and_clock))
752 goto short_msg;
753 rc = ccid_handle_set_rate_and_clock(cs, msg);
754 break;
755 default:
Harald Welte8772f582019-05-14 16:34:47 +0200756 /* generic response with bERror = 0 (command not supported) */
757 resp = gen_err_resp(ch->bMessageType, ch->bSlot, CCID_ICC_STATUS_NO_ICC, ch->bSeq,
758 CCID_ERR_CMD_NOT_SUPPORTED);
759 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100760 }
Harald Welte92e7c0b2019-05-14 09:32:10 +0200761 return 0;
762
Harald Welte63653742019-01-03 16:54:16 +0100763short_msg:
Harald Welte92e7c0b2019-05-14 09:32:10 +0200764 /* FIXME */
765 return -1;
Harald Welte63653742019-01-03 16:54:16 +0100766}