blob: e3705ae1496281a9cd84ce9f5615979a6fde0d4a [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"
Harald Welte8d186ad2019-05-15 19:40:29 +020011#include "ccid_device.h"
Harald Welte63653742019-01-03 16:54:16 +010012
Harald Welte8579ce52019-05-15 12:22:24 +020013/* decode on-the-wire T0 parameters into their parsed form */
14static int decode_ccid_pars_t0(struct ccid_pars_decoded *out, const struct ccid_proto_data_t0 *in)
15{
16 /* input validation: only 0x00 and 0x02 permitted for bmTCCKST0 */
17 if (in->bmTCCKST0 & 0xFD)
18 return -11;
19 /* input validation: only 0x00 to 0x03 permitted for bClockSTop */
20 if (in->bClockStop & 0xFC)
21 return -14;
22
23 out->fi = in->bmFindexDindex >> 4;
24 out->di = in->bmFindexDindex & 0xF;
25 if (in->bmTCCKST0 & 2)
26 out->inverse_convention = true;
27 else
28 out->inverse_convention = false;
29 if (in->bGuardTimeT0 == 0xff)
30 out->t0.guard_time_etu = 0;
31 else
32 out->t0.guard_time_etu = in->bGuardTimeT0;
33 out->t0.waiting_integer = in->bWaitingIntegerT0;
34 out->clock_stop = in->bClockStop & 0x03;
35
36 return 0;
37}
38
39/* encode T0 parameters from parsed form into on-the-wire encoding */
40static void encode_ccid_pars_t0(struct ccid_proto_data_t0 *out, const struct ccid_pars_decoded *in)
41{
42 out->bmFindexDindex = ((in->fi << 4) & 0xF0) | (in->di & 0x0F);
43 if (in->inverse_convention)
44 out->bmTCCKST0 = 0x02;
45 else
46 out->bmTCCKST0 = 0x00;
47 out->bGuardTimeT0 = in->t0.guard_time_etu;
48 out->bWaitingIntegerT0 = in->t0.waiting_integer;
49 out->bClockStop = in->clock_stop & 0x03;
50}
51
52/* decode on-the-wire T1 parameters into their parsed form */
53static int decode_ccid_pars_t1(struct ccid_pars_decoded *out, const struct ccid_proto_data_t1 *in)
54{
55 /* input validation: only some values permitted for bmTCCKST0 */
56 if (in->bmTCCKST1 & 0xE8)
57 return -11;
58 /* input validation: only 0x00 to 0x9F permitted for bmWaitingIntegersT1 */
59 if (in->bWaitingIntegersT1 > 0x9F)
60 return -13;
61 /* input validation: only 0x00 to 0x03 permitted for bClockSTop */
62 if (in->bClockStop & 0xFC)
63 return -14;
64 /* input validation: only 0x00 to 0xFE permitted for bIFSC */
65 if (in->bIFSC > 0xFE)
66 return -15;
67
68 out->fi = in->bmFindexDindex >> 4;
69 out->di = in->bmFindexDindex & 0xF;
70 if (in->bmTCCKST1 & 1)
71 out->t1.csum_type = CCID_CSUM_TYPE_CRC;
72 else
73 out->t1.csum_type = CCID_CSUM_TYPE_LRC;
74 if (in->bmTCCKST1 & 2)
75 out->inverse_convention = true;
76 else
77 out->inverse_convention = false;
78 out->t1.guard_time_t1 = in->bGuardTimeT1;
79 out->t1.bwi = in->bWaitingIntegersT1 >> 4;
80 out->t1.cwi = in->bWaitingIntegersT1 & 0xF;
81 out->clock_stop = in->bClockStop & 0x03;
82 out->t1.ifsc = in->bIFSC;
83 out->t1.nad = in->bNadValue;
84
85 return 0;
86}
87
88/* encode T1 parameters from parsed form into on-the-wire encoding */
89static void encode_ccid_pars_t1(struct ccid_proto_data_t1 *out, const struct ccid_pars_decoded *in)
90{
91 out->bmFindexDindex = ((in->fi << 4) & 0xF0) | (in->di & 0x0F);
92 out->bmTCCKST1 = 0x10;
93 if (in->t1.csum_type == CCID_CSUM_TYPE_CRC)
94 out->bmTCCKST1 |= 0x01;
95 if (in->inverse_convention)
96 out->bmTCCKST1 |= 0x02;
97 out->bGuardTimeT1 = in->t1.guard_time_t1;
98 out->bWaitingIntegersT1 = ((in->t1.bwi << 4) & 0xF0) | (in->t1.cwi & 0x0F);
99 out->bClockStop = in->clock_stop & 0x03;
100 out->bIFSC = in->t1.ifsc;
101 out->bNadValue = in->t1.nad;
102}
103
Harald Welte63653742019-01-03 16:54:16 +0100104#define msgb_ccid_out(x) (union ccid_pc_to_rdr *)msgb_data(x)
105#define msgb_ccid_in(x) (union ccid_rdr_to_pc *)msgb_data(x)
106
107static struct ccid_slot *get_ccid_slot(struct ccid_instance *ci, uint8_t slot_nr)
108{
109 if (slot_nr >= sizeof(ci->slot))
110 return NULL;
111 else
Harald Welte92e7c0b2019-05-14 09:32:10 +0200112 return &ci->slot[slot_nr];
Harald Welte63653742019-01-03 16:54:16 +0100113}
114
115static uint8_t get_icc_status(const struct ccid_slot *cs)
116{
117 if (cs->icc_present && cs->icc_powered && !cs->icc_in_reset)
118 return CCID_ICC_STATUS_PRES_ACT;
119 else if (!cs->icc_present)
120 return CCID_ICC_STATUS_NO_ICC;
121 else
122 return CCID_ICC_STATUS_PRES_INACT;
123}
124
125#define SET_HDR(x, msg_type, slot, seq) do { \
126 (x)->hdr.bMessageType = msg_type; \
127 (x)->hdr.dwLength = 0; \
128 (x)->hdr.bSlot = slot; \
129 (x)->hdr.bSeq = seq; \
130 } while (0)
131
132#define SET_HDR_IN(x, msg_type, slot, seq, status, error) do { \
133 SET_HDR(&(x)->hdr, msg_type, slot, seq); \
134 (x)->hdr.bStatus = status; \
135 (x)->hdr.bError = error; \
136 } while (0)
137
Harald Welte8772f582019-05-14 16:34:47 +0200138#if 0
139static uint8_t ccid_pc_to_rdr_get_seq(const struct ccid_pc_to_rdr *u)
140{
141 const struct ccid_header *ch = (const struct ccid_header *) u;
142 return ch->bSeq;
143}
144#endif
145
Harald Welte63653742019-01-03 16:54:16 +0100146/***********************************************************************
147 * Message generation / sending
148 ***********************************************************************/
149
150static struct msgb *ccid_msgb_alloc(void)
151{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200152 struct msgb *msg = msgb_alloc(512, "ccid");
Harald Welte63653742019-01-03 16:54:16 +0100153 OSMO_ASSERT(msg);
154 return msg;
155}
156
Harald Welte8772f582019-05-14 16:34:47 +0200157/* Send given CCID message */
Harald Welte63653742019-01-03 16:54:16 +0100158static int ccid_send(struct ccid_instance *ci, struct msgb *msg)
159{
Harald Weltebcbc1972019-05-15 21:57:32 +0200160 return ci->ops->send_in(ci, msg);
Harald Welte63653742019-01-03 16:54:16 +0100161}
162
Harald Welte8772f582019-05-14 16:34:47 +0200163/* Send given CCID message for given slot; patch bSlot into message */
Harald Welte63653742019-01-03 16:54:16 +0100164static int ccid_slot_send(struct ccid_slot *cs, struct msgb *msg)
165{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200166 struct ccid_header *ch = (struct ccid_header *) msgb_ccid_in(msg);
Harald Welte63653742019-01-03 16:54:16 +0100167
168 /* patch bSlotNr into message */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200169 ch->bSlot = cs->slot_nr;
Harald Welte63653742019-01-03 16:54:16 +0100170 return ccid_send(cs->ci, msg);
171}
172
Harald Welte8772f582019-05-14 16:34:47 +0200173/* Send given CCID message and mark slot as un-busy */
174static int ccid_slot_send_unbusy(struct ccid_slot *cs, struct msgb *msg)
175{
176 cs->cmd_busy = false;
177 return ccid_slot_send(cs, msg);
178}
Harald Welte63653742019-01-03 16:54:16 +0100179
180/* Section 6.2.1 */
Harald Welte8772f582019-05-14 16:34:47 +0200181static struct msgb *ccid_gen_data_block_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq,
182 uint8_t cmd_sts, enum ccid_error_code err,
183 const uint8_t *data, uint32_t data_len)
Harald Welte63653742019-01-03 16:54:16 +0100184{
185 struct msgb *msg = ccid_msgb_alloc();
Harald Welte8772f582019-05-14 16:34:47 +0200186 struct ccid_rdr_to_pc_data_block *db =
Harald Welte92e7c0b2019-05-14 09:32:10 +0200187 (struct ccid_rdr_to_pc_data_block *) msgb_put(msg, sizeof(*db) + data_len);
Harald Welte8772f582019-05-14 16:34:47 +0200188 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100189
Harald Welte8772f582019-05-14 16:34:47 +0200190 SET_HDR_IN(db, RDR_to_PC_DataBlock, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200191 osmo_store32le(data_len, &db->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100192 memcpy(db->abData, data, data_len);
193 return msg;
194}
Harald Welte8772f582019-05-14 16:34:47 +0200195static struct msgb *ccid_gen_data_block(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
196 enum ccid_error_code err, const uint8_t *data,
197 uint32_t data_len)
198{
199 return ccid_gen_data_block_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, data, data_len);
200}
Harald Welte63653742019-01-03 16:54:16 +0100201
202/* Section 6.2.2 */
Harald Welte8772f582019-05-14 16:34:47 +0200203static struct msgb *ccid_gen_slot_status_nr(uint8_t slot_nr, uint8_t icc_status,
204 uint8_t seq, uint8_t cmd_sts,
205 enum ccid_error_code err)
Harald Welte63653742019-01-03 16:54:16 +0100206{
207 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200208 struct ccid_rdr_to_pc_slot_status *ss =
209 (struct ccid_rdr_to_pc_slot_status *) msgb_put(msg, sizeof(*ss));
Harald Welte8772f582019-05-14 16:34:47 +0200210 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100211
Harald Welte8772f582019-05-14 16:34:47 +0200212 SET_HDR_IN(ss, RDR_to_PC_SlotStatus, slot_nr, seq, sts, err);
Harald Welte63653742019-01-03 16:54:16 +0100213 return msg;
214}
Harald Welte8772f582019-05-14 16:34:47 +0200215static struct msgb *ccid_gen_slot_status(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
216 enum ccid_error_code err)
217{
218 return ccid_gen_slot_status_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err);
219}
Harald Welte63653742019-01-03 16:54:16 +0100220
221/* Section 6.2.3 */
Harald Welte8772f582019-05-14 16:34:47 +0200222static struct msgb *ccid_gen_parameters_t0_nr(uint8_t slot_nr, uint8_t icc_status,
223 uint8_t seq, uint8_t cmd_sts, enum ccid_error_code err,
Harald Welte8579ce52019-05-15 12:22:24 +0200224 const struct ccid_pars_decoded *dec_par)
Harald Welte8772f582019-05-14 16:34:47 +0200225{
226 struct msgb *msg = ccid_msgb_alloc();
227 struct ccid_rdr_to_pc_parameters *par =
Harald Welte8579ce52019-05-15 12:22:24 +0200228 (struct ccid_rdr_to_pc_parameters *) msgb_put(msg, sizeof(par->hdr)+sizeof(par->abProtocolData.t0));
Harald Welte8772f582019-05-14 16:34:47 +0200229 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
230
231 SET_HDR_IN(par, RDR_to_PC_Parameters, slot_nr, seq, sts, err);
Harald Welte8579ce52019-05-15 12:22:24 +0200232 if (dec_par) {
233 osmo_store32le(sizeof(par->abProtocolData.t0), &par->hdr.hdr.dwLength);
234 encode_ccid_pars_t0(&par->abProtocolData.t0, dec_par);
Harald Welte8772f582019-05-14 16:34:47 +0200235 }
236 return msg;
237}
238static struct msgb *ccid_gen_parameters_t0(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
Harald Welte8579ce52019-05-15 12:22:24 +0200239 enum ccid_error_code err)
Harald Welte8772f582019-05-14 16:34:47 +0200240{
Harald Welte8579ce52019-05-15 12:22:24 +0200241 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 +0200242}
243
244static struct msgb *ccid_gen_parameters_t1_nr(uint8_t slot_nr, uint8_t icc_status,
245 uint8_t seq, uint8_t cmd_sts, enum ccid_error_code err,
Harald Welte8579ce52019-05-15 12:22:24 +0200246 const struct ccid_pars_decoded *dec_par)
Harald Welte8772f582019-05-14 16:34:47 +0200247{
248 struct msgb *msg = ccid_msgb_alloc();
249 struct ccid_rdr_to_pc_parameters *par =
Harald Welte8579ce52019-05-15 12:22:24 +0200250 (struct ccid_rdr_to_pc_parameters *) msgb_put(msg, sizeof(par->hdr)+sizeof(par->abProtocolData.t1));
Harald Welte8772f582019-05-14 16:34:47 +0200251 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
252
253 SET_HDR_IN(par, RDR_to_PC_Parameters, slot_nr, seq, sts, err);
Harald Welte8579ce52019-05-15 12:22:24 +0200254 if (dec_par) {
255 osmo_store32le(sizeof(par->abProtocolData.t1), &par->hdr.hdr.dwLength);
256 encode_ccid_pars_t1(&par->abProtocolData.t1, dec_par);
Harald Welte8772f582019-05-14 16:34:47 +0200257 }
258 return msg;
259}
260static struct msgb *ccid_gen_parameters_t1(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
Harald Welte8579ce52019-05-15 12:22:24 +0200261 enum ccid_error_code err)
Harald Welte8772f582019-05-14 16:34:47 +0200262{
Harald Welte8579ce52019-05-15 12:22:24 +0200263 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 +0200264}
265
Harald Welte63653742019-01-03 16:54:16 +0100266
267/* Section 6.2.4 */
Harald Welte8772f582019-05-14 16:34:47 +0200268static struct msgb *ccid_gen_escape_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq, uint8_t cmd_sts,
269 enum ccid_error_code err, const uint8_t *data, uint32_t data_len)
Harald Welte63653742019-01-03 16:54:16 +0100270{
271 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200272 struct ccid_rdr_to_pc_escape *esc =
273 (struct ccid_rdr_to_pc_escape *) msgb_put(msg, sizeof(*esc) + data_len);
Harald Welte8772f582019-05-14 16:34:47 +0200274 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100275
Harald Welte8772f582019-05-14 16:34:47 +0200276 SET_HDR_IN(esc, RDR_to_PC_Escape, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200277 osmo_store32le(data_len, &esc->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100278 memcpy(esc->abData, data, data_len);
279 return msg;
280}
Harald Welte8772f582019-05-14 16:34:47 +0200281static struct msgb *ccid_gen_escape(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
282 enum ccid_error_code err, const uint8_t *data,
283 uint32_t data_len)
284{
285 return ccid_gen_escape_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, data, data_len);
286}
Harald Welte63653742019-01-03 16:54:16 +0100287
288/* Section 6.2.5 */
Harald Welte8772f582019-05-14 16:34:47 +0200289static struct msgb *ccid_gen_clock_and_rate_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq,
290 uint8_t cmd_sts, enum ccid_error_code err,
291 uint32_t clock_khz, uint32_t rate_bps)
Harald Welte63653742019-01-03 16:54:16 +0100292{
293 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200294 struct ccid_rdr_to_pc_data_rate_and_clock *drc =
295 (struct ccid_rdr_to_pc_data_rate_and_clock *) msgb_put(msg, sizeof(*drc));
Harald Welte8772f582019-05-14 16:34:47 +0200296 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100297
Harald Welte8772f582019-05-14 16:34:47 +0200298 SET_HDR_IN(drc, RDR_to_PC_DataRateAndClockFrequency, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200299 osmo_store32le(8, &drc->hdr.hdr.dwLength); /* Message-specific data length (wtf?) */
300 osmo_store32le(clock_khz, &drc->dwClockFrequency); /* kHz */
301 osmo_store32le(rate_bps, &drc->dwDataRate); /* bps */
Harald Welte63653742019-01-03 16:54:16 +0100302 return msg;
303}
Harald Welte8772f582019-05-14 16:34:47 +0200304static struct msgb *ccid_gen_clock_and_rate(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
305 enum ccid_error_code err, uint32_t clock_khz,
306 uint32_t rate_bps)
Harald Welte63653742019-01-03 16:54:16 +0100307{
Harald Welte8772f582019-05-14 16:34:47 +0200308 return ccid_gen_clock_and_rate_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err,
309 clock_khz, rate_bps);
Harald Welte63653742019-01-03 16:54:16 +0100310}
Harald Welte8772f582019-05-14 16:34:47 +0200311
312/*! generate an error response for given input message_type/slot_nr/seq
313 * \param[in] msg_type CCID Message Type against which response is to be created
314 * \param[in] slot_nr CCID Slot Number
315 * \param[in] icc_status ICC Status of the slot
316 * \param[in] seq CCID Sequence number
317 * \param[in] err_code CCID Error Code to send
318 * \returns dynamically-allocated message buffer containing error response */
319static struct msgb *gen_err_resp(enum ccid_msg_type msg_type, uint8_t slot_nr, uint8_t icc_status,
320 uint8_t seq, enum ccid_error_code err_code)
321{
322 struct msgb *resp = NULL;
323
324 switch (msg_type) {
325 case PC_to_RDR_IccPowerOn:
326 case PC_to_RDR_XfrBlock:
327 case PC_to_RDR_Secure:
328 /* Return RDR_to_PC_DataBlock */
329 resp = ccid_gen_data_block_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
330 err_code, NULL, 0);
331 break;
332
333 case PC_to_RDR_IccPowerOff:
334 case PC_to_RDR_GetSlotStatus:
335 case PC_to_RDR_IccClock:
336 case PC_to_RDR_T0APDU:
337 case PC_to_RDR_Mechanical:
338 case PC_to_RDR_Abort:
339 /* Return RDR_to_PC_SlotStatus */
340 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
341 err_code);
342 break;
343
344 case PC_to_RDR_GetParameters:
345 case PC_to_RDR_ResetParameters:
346 case PC_to_RDR_SetParameters:
347 /* Return RDR_to_PC_Parameters */
348 resp = ccid_gen_parameters_t0_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
349 err_code, NULL); /* FIXME: parameters? */
350 break;
351
352 case PC_to_RDR_Escape:
353 /* Return RDR_to_PC_Escape */
354 resp = ccid_gen_escape_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
355 err_code, NULL, 0);
356 break;
357
358 case PC_to_RDR_SetDataRateAndClockFrequency:
359 /* Return RDR_to_PC_SlotStatus */
360 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
361 err_code);
362 break;
363
364 default:
365 /* generate general error */
366 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
367 CCID_ERR_CMD_NOT_SUPPORTED);
368 break;
369 }
370 return resp;
371}
Harald Welte63653742019-01-03 16:54:16 +0100372
373/***********************************************************************
374 * Message reception / parsing
375 ***********************************************************************/
376
377/* Section 6.1.3 */
378static int ccid_handle_get_slot_status(struct ccid_slot *cs, struct msgb *msg)
379{
380 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200381 const struct ccid_header *ch = (const struct ccid_header *) u;
382 uint8_t seq = u->get_slot_status.hdr.bSeq;
Harald Welte63653742019-01-03 16:54:16 +0100383 struct msgb *resp;
384
Harald Welte8772f582019-05-14 16:34:47 +0200385 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte63653742019-01-03 16:54:16 +0100386
Harald Welte8772f582019-05-14 16:34:47 +0200387 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100388}
389
390
391/* Section 6.1.1 */
392static int ccid_handle_icc_power_on(struct ccid_slot *cs, struct msgb *msg)
393{
394 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200395 const struct ccid_header *ch = (const struct ccid_header *) u;
396 uint8_t seq = u->icc_power_on.hdr.bSeq;
Harald Welte63653742019-01-03 16:54:16 +0100397 struct msgb *resp;
398
399 /* TODO: send actual ATR; handle error cases */
400 /* TODO: handle this asynchronously */
Harald Welte8772f582019-05-14 16:34:47 +0200401 resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
Harald Welte63653742019-01-03 16:54:16 +0100402
Harald Welte8772f582019-05-14 16:34:47 +0200403 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100404}
405
406/* Section 6.1.2 */
407static int ccid_handle_icc_power_off(struct ccid_slot *cs, struct msgb *msg)
408{
409 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200410 const struct ccid_header *ch = (const struct ccid_header *) u;
411 uint8_t seq = u->icc_power_off.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200412 struct msgb *resp;
413
Harald Welte8772f582019-05-14 16:34:47 +0200414 /* FIXME */
415 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
416 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100417}
418
419/* Section 6.1.4 */
420static int ccid_handle_xfr_block(struct ccid_slot *cs, struct msgb *msg)
421{
422 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200423 const struct ccid_header *ch = (const struct ccid_header *) u;
424 uint8_t seq = u->xfr_block.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200425 struct msgb *resp;
426
Harald Welte8772f582019-05-14 16:34:47 +0200427 /* FIXME */
428 resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
429 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100430}
431
432/* Section 6.1.5 */
433static int ccid_handle_get_parameters(struct ccid_slot *cs, struct msgb *msg)
434{
435 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200436 const struct ccid_header *ch = (const struct ccid_header *) u;
437 uint8_t seq = u->get_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200438 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200439
Harald Welte8579ce52019-05-15 12:22:24 +0200440 /* FIXME: T=1 */
441 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte8772f582019-05-14 16:34:47 +0200442 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100443}
444
445/* Section 6.1.6 */
446static int ccid_handle_reset_parameters(struct ccid_slot *cs, struct msgb *msg)
447{
448 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200449 const struct ccid_header *ch = (const struct ccid_header *) u;
450 uint8_t seq = u->reset_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200451 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200452
Harald Welte8579ce52019-05-15 12:22:24 +0200453 /* FIXME: copy default parameters from somewhere */
454 /* FIXME: T=1 */
455 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte8772f582019-05-14 16:34:47 +0200456 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100457}
458
459/* Section 6.1.7 */
460static int ccid_handle_set_parameters(struct ccid_slot *cs, struct msgb *msg)
461{
462 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8579ce52019-05-15 12:22:24 +0200463 const struct ccid_pc_to_rdr_set_parameters *spar = &u->set_parameters;
Harald Welte8772f582019-05-14 16:34:47 +0200464 const struct ccid_header *ch = (const struct ccid_header *) u;
465 uint8_t seq = u->set_parameters.hdr.bSeq;
Harald Welte8579ce52019-05-15 12:22:24 +0200466 struct ccid_pars_decoded pars_dec;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200467 struct msgb *resp;
Harald Welte8579ce52019-05-15 12:22:24 +0200468 int rc;
Harald Welte8772f582019-05-14 16:34:47 +0200469
Harald Welte8579ce52019-05-15 12:22:24 +0200470 switch (spar->bProtocolNum) {
471 case CCID_PROTOCOL_NUM_T0:
472 rc = decode_ccid_pars_t0(&pars_dec, &spar->abProtocolData.t0);
473 if (rc < 0)
474 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_FAILED, -rc);
475 /* FIXME: validate parameters; abort if they are not supported */
476 cs->pars = pars_dec;
477 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_OK, 0);
478 break;
479 case CCID_PROTOCOL_NUM_T1:
480 rc = decode_ccid_pars_t1(&pars_dec, &spar->abProtocolData.t1);
481 if (rc < 0)
482 resp = ccid_gen_parameters_t1(cs, seq, CCID_CMD_STATUS_FAILED, -rc);
483 /* FIXME: validate parameters; abort if they are not supported */
484 cs->pars = pars_dec;
485 resp = ccid_gen_parameters_t1(cs, seq, CCID_CMD_STATUS_OK, 0);
486 break;
487 default:
488 resp = ccid_gen_parameters_t0(cs, seq, CCID_CMD_STATUS_FAILED, 0);
489 break;
490 }
Harald Welte8772f582019-05-14 16:34:47 +0200491 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100492}
493
494/* Section 6.1.8 */
495static int ccid_handle_escape(struct ccid_slot *cs, struct msgb *msg)
496{
497 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200498 const struct ccid_header *ch = (const struct ccid_header *) u;
499 uint8_t seq = u->escape.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200500 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200501
502 resp = ccid_gen_escape(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED, NULL, 0);
503 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100504}
505
506/* Section 6.1.9 */
507static int ccid_handle_icc_clock(struct ccid_slot *cs, struct msgb *msg)
508{
509 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200510 const struct ccid_header *ch = (const struct ccid_header *) u;
511 uint8_t seq = u->icc_clock.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200512 struct msgb *resp;
513
Harald Welte8772f582019-05-14 16:34:47 +0200514 /* FIXME: Actually Stop/Start the clock */
515 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
516 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100517}
518
519/* Section 6.1.10 */
520static int ccid_handle_t0apdu(struct ccid_slot *cs, struct msgb *msg)
521{
522 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200523 const struct ccid_header *ch = (const struct ccid_header *) u;
524 uint8_t seq = u->t0apdu.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200525 struct msgb *resp;
526
Harald Welte8772f582019-05-14 16:34:47 +0200527 /* FIXME */
528 //resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
529 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
530 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100531}
532
533/* Section 6.1.11 */
534static int ccid_handle_secure(struct ccid_slot *cs, struct msgb *msg)
535{
536 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200537 const struct ccid_header *ch = (const struct ccid_header *) u;
538 uint8_t seq = u->secure.hdr.bSeq;
539 struct msgb *resp;
540
541 /* FIXME */
542 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
543 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100544}
545
546/* Section 6.1.12 */
547static int ccid_handle_mechanical(struct ccid_slot *cs, struct msgb *msg)
548{
549 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200550 const struct ccid_header *ch = (const struct ccid_header *) u;
551 uint8_t seq = u->mechanical.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200552 struct msgb *resp;
553
Harald Welte8772f582019-05-14 16:34:47 +0200554 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
555 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100556}
557
558/* Section 6.1.13 */
559static int ccid_handle_abort(struct ccid_slot *cs, struct msgb *msg)
560{
561 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200562 const struct ccid_header *ch = (const struct ccid_header *) u;
563 uint8_t seq = u->abort.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200564 struct msgb *resp;
565
Harald Welte8772f582019-05-14 16:34:47 +0200566 /* Check if the currently in-progress message is Abortable */
567 switch (0/* FIXME */) {
568 case PC_to_RDR_IccPowerOn:
569 case PC_to_RDR_XfrBlock:
570 case PC_to_RDR_Escape:
571 case PC_to_RDR_Secure:
572 case PC_to_RDR_Mechanical:
573 //case PC_to_RDR_Abort: /* seriously? WTF! */
574 break;
575 default:
576 /* CCID spec lists CMD_NOT_ABORTED, but gives no numberic value ?!? */
577 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
578 return ccid_slot_send_unbusy(cs, resp);
579 }
580
581 /* FIXME */
582 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
583 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100584}
585
586/* Section 6.1.14 */
587static int ccid_handle_set_rate_and_clock(struct ccid_slot *cs, struct msgb *msg)
588{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200589 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200590 const struct ccid_header *ch = (const struct ccid_header *) u;
591 uint8_t seq = u->set_rate_and_clock.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200592 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200593
594 /* FIXME */
595 resp = ccid_gen_clock_and_rate(cs, seq, CCID_CMD_STATUS_OK, 0, 9600, 2500000);
596 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100597}
598
Harald Welte8772f582019-05-14 16:34:47 +0200599/*! Handle data arriving from the host on the OUT endpoint.
600 * \param[in] cs CCID Instance on which to operate
601 * \param[in] msgb received message buffer containing one CCID OUT EP message from the host
602 * \returns 0 on success; negative on error */
Harald Welte63653742019-01-03 16:54:16 +0100603int ccid_handle_out(struct ccid_instance *ci, struct msgb *msg)
604{
605 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
606 const struct ccid_header *ch = (const struct ccid_header *) u;
607 unsigned int len = msgb_length(msg);
608 struct ccid_slot *cs;
Harald Welte8772f582019-05-14 16:34:47 +0200609 struct msgb *resp;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200610 int rc;
Harald Welte63653742019-01-03 16:54:16 +0100611
612 if (len < sizeof(*ch)) {
613 /* FIXME */
614 return -1;
615 }
616
Harald Welte8772f582019-05-14 16:34:47 +0200617 /* Check for invalid slot number */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200618 cs = get_ccid_slot(ci, ch->bSlot);
Harald Welte63653742019-01-03 16:54:16 +0100619 if (!cs) {
Harald Welte8772f582019-05-14 16:34:47 +0200620 resp = gen_err_resp(ch->bMessageType, ch->bSlot, CCID_ICC_STATUS_NO_ICC, ch->bSeq, 5);
621 return ccid_send(ci, resp);
Harald Welte63653742019-01-03 16:54:16 +0100622 }
623
Harald Welte8772f582019-05-14 16:34:47 +0200624 /* Check if slot is already busy; Reject any additional commands meanwhile */
625 if (cs->cmd_busy) {
626 /* FIXME: ABORT logic as per section 5.3.1 of CCID Spec v1.1 */
627 resp = gen_err_resp(ch->bMessageType, ch->bSlot, get_icc_status(cs), ch->bSeq,
628 CCID_ERR_CMD_SLOT_BUSY);
629 return ccid_send(ci, resp);
630 }
631
632 /* we're now processing a command for the slot; mark slot as busy */
633 cs->cmd_busy = true;
634
635 /* TODO: enqueue into the per-slot specific input queue */
636
Harald Welte63653742019-01-03 16:54:16 +0100637 switch (ch->bMessageType) {
638 case PC_to_RDR_GetSlotStatus:
639 if (len != sizeof(u->get_slot_status))
640 goto short_msg;
641 rc = ccid_handle_get_slot_status(cs, msg);
642 break;
643 case PC_to_RDR_IccPowerOn:
644 if (len != sizeof(u->icc_power_on))
645 goto short_msg;
646 rc = ccid_handle_icc_power_on(cs, msg);
647 break;
648 case PC_to_RDR_IccPowerOff:
649 if (len != sizeof(u->icc_power_off))
650 goto short_msg;
651 rc = ccid_handle_icc_power_off(cs, msg);
652 break;
653 case PC_to_RDR_XfrBlock:
654 if (len < sizeof(u->xfr_block))
655 goto short_msg;
656 rc = ccid_handle_xfr_block(cs, msg);
657 break;
658 case PC_to_RDR_GetParameters:
659 if (len != sizeof(u->get_parameters))
660 goto short_msg;
661 rc = ccid_handle_get_parameters(cs, msg);
662 break;
663 case PC_to_RDR_ResetParameters:
664 if (len != sizeof(u->reset_parameters))
665 goto short_msg;
666 rc = ccid_handle_reset_parameters(cs, msg);
667 break;
668 case PC_to_RDR_SetParameters:
669 if (len != sizeof(u->set_parameters))
670 goto short_msg;
671 rc = ccid_handle_set_parameters(cs, msg);
672 break;
673 case PC_to_RDR_Escape:
674 if (len < sizeof(u->escape))
675 goto short_msg;
676 rc = ccid_handle_escape(cs, msg);
677 break;
678 case PC_to_RDR_IccClock:
679 if (len != sizeof(u->icc_clock))
680 goto short_msg;
681 rc = ccid_handle_icc_clock(cs, msg);
682 break;
683 case PC_to_RDR_T0APDU:
684 if (len != /*FIXME*/ sizeof(u->t0apdu))
685 goto short_msg;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200686 rc = ccid_handle_t0apdu(cs, msg);
Harald Welte63653742019-01-03 16:54:16 +0100687 break;
688 case PC_to_RDR_Secure:
689 if (len < sizeof(u->secure))
690 goto short_msg;
691 rc = ccid_handle_secure(cs, msg);
692 break;
693 case PC_to_RDR_Mechanical:
694 if (len != sizeof(u->mechanical))
695 goto short_msg;
696 rc = ccid_handle_mechanical(cs, msg);
697 break;
698 case PC_to_RDR_Abort:
699 if (len != sizeof(u->abort))
700 goto short_msg;
701 rc = ccid_handle_abort(cs, msg);
702 break;
703 case PC_to_RDR_SetDataRateAndClockFrequency:
704 if (len != sizeof(u->set_rate_and_clock))
705 goto short_msg;
706 rc = ccid_handle_set_rate_and_clock(cs, msg);
707 break;
708 default:
Harald Welte8772f582019-05-14 16:34:47 +0200709 /* generic response with bERror = 0 (command not supported) */
710 resp = gen_err_resp(ch->bMessageType, ch->bSlot, CCID_ICC_STATUS_NO_ICC, ch->bSeq,
711 CCID_ERR_CMD_NOT_SUPPORTED);
712 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100713 }
Harald Welte92e7c0b2019-05-14 09:32:10 +0200714 return 0;
715
Harald Welte63653742019-01-03 16:54:16 +0100716short_msg:
Harald Welte92e7c0b2019-05-14 09:32:10 +0200717 /* FIXME */
718 return -1;
Harald Welte63653742019-01-03 16:54:16 +0100719}
Harald Weltebcbc1972019-05-15 21:57:32 +0200720
721void ccid_instance_init(struct ccid_instance *ci, const struct ccid_ops *ops, const char *name,
722 void *priv)
723{
724 int i;
725
726 for (i = 0; i < ARRAY_SIZE(ci->slot); i++) {
727 struct ccid_slot *cs = &ci->slot[i];
728 cs->slot_nr = i;
729 cs->ci = ci;
730 }
731 ci->ops= ops;
732 ci->name = name;
733 ci->priv = priv;
734}