blob: 340ff6074c867a805eecb18f67d853d863786db2 [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;
Harald Welte8772f582019-05-14 16:34:47 +020020 bool cmd_busy;
Harald Welte63653742019-01-03 16:54:16 +010021};
22
23struct ccid_ops {
Harald Welte92e7c0b2019-05-14 09:32:10 +020024 int (*send_in)(struct ccid_instance *ci, struct msgb *msg);
Harald Welte63653742019-01-03 16:54:16 +010025};
26
27struct ccid_instance {
28 struct ccid_slot slot[NR_SLOTS];
29 struct ccid_ops ops;
Harald Welte8772f582019-05-14 16:34:47 +020030 const char *name;
Harald Welte63653742019-01-03 16:54:16 +010031};
32
33#define msgb_ccid_out(x) (union ccid_pc_to_rdr *)msgb_data(x)
34#define msgb_ccid_in(x) (union ccid_rdr_to_pc *)msgb_data(x)
35
Harald Welte8772f582019-05-14 16:34:47 +020036#define LOGPCI(ci, lvl, fmt, args ...) LOGP(DCCID, lvl, "%s: " fmt, (ci)->name, ## args)
37#define LOGPCS(cs, lvl, fmt, args ...) \
38 LOGP(DCCID, lvl, "%s(%u): " fmt, (cc)->ci->name, (cc)->slot_nr, ## args)
39
Harald Welte63653742019-01-03 16:54:16 +010040static struct ccid_slot *get_ccid_slot(struct ccid_instance *ci, uint8_t slot_nr)
41{
42 if (slot_nr >= sizeof(ci->slot))
43 return NULL;
44 else
Harald Welte92e7c0b2019-05-14 09:32:10 +020045 return &ci->slot[slot_nr];
Harald Welte63653742019-01-03 16:54:16 +010046}
47
48static uint8_t get_icc_status(const struct ccid_slot *cs)
49{
50 if (cs->icc_present && cs->icc_powered && !cs->icc_in_reset)
51 return CCID_ICC_STATUS_PRES_ACT;
52 else if (!cs->icc_present)
53 return CCID_ICC_STATUS_NO_ICC;
54 else
55 return CCID_ICC_STATUS_PRES_INACT;
56}
57
58#define SET_HDR(x, msg_type, slot, seq) do { \
59 (x)->hdr.bMessageType = msg_type; \
60 (x)->hdr.dwLength = 0; \
61 (x)->hdr.bSlot = slot; \
62 (x)->hdr.bSeq = seq; \
63 } while (0)
64
65#define SET_HDR_IN(x, msg_type, slot, seq, status, error) do { \
66 SET_HDR(&(x)->hdr, msg_type, slot, seq); \
67 (x)->hdr.bStatus = status; \
68 (x)->hdr.bError = error; \
69 } while (0)
70
Harald Welte8772f582019-05-14 16:34:47 +020071#if 0
72static uint8_t ccid_pc_to_rdr_get_seq(const struct ccid_pc_to_rdr *u)
73{
74 const struct ccid_header *ch = (const struct ccid_header *) u;
75 return ch->bSeq;
76}
77#endif
78
Harald Welte63653742019-01-03 16:54:16 +010079/***********************************************************************
80 * Message generation / sending
81 ***********************************************************************/
82
83static struct msgb *ccid_msgb_alloc(void)
84{
Harald Welte92e7c0b2019-05-14 09:32:10 +020085 struct msgb *msg = msgb_alloc(512, "ccid");
Harald Welte63653742019-01-03 16:54:16 +010086 OSMO_ASSERT(msg);
87 return msg;
88}
89
Harald Welte8772f582019-05-14 16:34:47 +020090/* Send given CCID message */
Harald Welte63653742019-01-03 16:54:16 +010091static int ccid_send(struct ccid_instance *ci, struct msgb *msg)
92{
93 return ci->ops.send_in(ci, msg);
94}
95
Harald Welte8772f582019-05-14 16:34:47 +020096/* Send given CCID message for given slot; patch bSlot into message */
Harald Welte63653742019-01-03 16:54:16 +010097static int ccid_slot_send(struct ccid_slot *cs, struct msgb *msg)
98{
Harald Welte92e7c0b2019-05-14 09:32:10 +020099 struct ccid_header *ch = (struct ccid_header *) msgb_ccid_in(msg);
Harald Welte63653742019-01-03 16:54:16 +0100100
101 /* patch bSlotNr into message */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200102 ch->bSlot = cs->slot_nr;
Harald Welte63653742019-01-03 16:54:16 +0100103 return ccid_send(cs->ci, msg);
104}
105
Harald Welte8772f582019-05-14 16:34:47 +0200106/* Send given CCID message and mark slot as un-busy */
107static int ccid_slot_send_unbusy(struct ccid_slot *cs, struct msgb *msg)
108{
109 cs->cmd_busy = false;
110 return ccid_slot_send(cs, msg);
111}
Harald Welte63653742019-01-03 16:54:16 +0100112
113/* Section 6.2.1 */
Harald Welte8772f582019-05-14 16:34:47 +0200114static struct msgb *ccid_gen_data_block_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq,
115 uint8_t cmd_sts, enum ccid_error_code err,
116 const uint8_t *data, uint32_t data_len)
Harald Welte63653742019-01-03 16:54:16 +0100117{
118 struct msgb *msg = ccid_msgb_alloc();
Harald Welte8772f582019-05-14 16:34:47 +0200119 struct ccid_rdr_to_pc_data_block *db =
Harald Welte92e7c0b2019-05-14 09:32:10 +0200120 (struct ccid_rdr_to_pc_data_block *) msgb_put(msg, sizeof(*db) + data_len);
Harald Welte8772f582019-05-14 16:34:47 +0200121 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100122
Harald Welte8772f582019-05-14 16:34:47 +0200123 SET_HDR_IN(db, RDR_to_PC_DataBlock, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200124 osmo_store32le(data_len, &db->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100125 memcpy(db->abData, data, data_len);
126 return msg;
127}
Harald Welte8772f582019-05-14 16:34:47 +0200128static struct msgb *ccid_gen_data_block(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
129 enum ccid_error_code err, const uint8_t *data,
130 uint32_t data_len)
131{
132 return ccid_gen_data_block_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, data, data_len);
133}
Harald Welte63653742019-01-03 16:54:16 +0100134
135/* Section 6.2.2 */
Harald Welte8772f582019-05-14 16:34:47 +0200136static struct msgb *ccid_gen_slot_status_nr(uint8_t slot_nr, uint8_t icc_status,
137 uint8_t seq, uint8_t cmd_sts,
138 enum ccid_error_code err)
Harald Welte63653742019-01-03 16:54:16 +0100139{
140 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200141 struct ccid_rdr_to_pc_slot_status *ss =
142 (struct ccid_rdr_to_pc_slot_status *) msgb_put(msg, sizeof(*ss));
Harald Welte8772f582019-05-14 16:34:47 +0200143 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100144
Harald Welte8772f582019-05-14 16:34:47 +0200145 SET_HDR_IN(ss, RDR_to_PC_SlotStatus, slot_nr, seq, sts, err);
Harald Welte63653742019-01-03 16:54:16 +0100146 return msg;
147}
Harald Welte8772f582019-05-14 16:34:47 +0200148static struct msgb *ccid_gen_slot_status(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
149 enum ccid_error_code err)
150{
151 return ccid_gen_slot_status_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err);
152}
Harald Welte63653742019-01-03 16:54:16 +0100153
154/* Section 6.2.3 */
Harald Welte8772f582019-05-14 16:34:47 +0200155static struct msgb *ccid_gen_parameters_t0_nr(uint8_t slot_nr, uint8_t icc_status,
156 uint8_t seq, uint8_t cmd_sts, enum ccid_error_code err,
157 const struct ccid_proto_data_t0 *t0)
158{
159 struct msgb *msg = ccid_msgb_alloc();
160 struct ccid_rdr_to_pc_parameters *par =
161 (struct ccid_rdr_to_pc_parameters *) msgb_put(msg, sizeof(par->hdr)+sizeof(*t0));
162 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
163
164 SET_HDR_IN(par, RDR_to_PC_Parameters, slot_nr, seq, sts, err);
165 if (t0) {
166 osmo_store32le(sizeof(*t0), &par->hdr.hdr.dwLength);
167 par->abProtocolData.t0 = *t0;
168 }
169 return msg;
170}
171static struct msgb *ccid_gen_parameters_t0(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
172 enum ccid_error_code err,
173 const struct ccid_proto_data_t0 *t0)
174{
175 return ccid_gen_parameters_t0_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, t0);
176}
177
178static struct msgb *ccid_gen_parameters_t1_nr(uint8_t slot_nr, uint8_t icc_status,
179 uint8_t seq, uint8_t cmd_sts, enum ccid_error_code err,
180 const struct ccid_proto_data_t1 *t1)
181{
182 struct msgb *msg = ccid_msgb_alloc();
183 struct ccid_rdr_to_pc_parameters *par =
184 (struct ccid_rdr_to_pc_parameters *) msgb_put(msg, sizeof(par->hdr)+sizeof(*t1));
185 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
186
187 SET_HDR_IN(par, RDR_to_PC_Parameters, slot_nr, seq, sts, err);
188 if (t1) {
189 osmo_store32le(sizeof(*t1), &par->hdr.hdr.dwLength);
190 par->abProtocolData.t1 = *t1;
191 }
192 return msg;
193}
194static struct msgb *ccid_gen_parameters_t1(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
195 enum ccid_error_code err,
196 const struct ccid_proto_data_t1 *t1)
197{
198 return ccid_gen_parameters_t1_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, t1);
199}
200
Harald Welte63653742019-01-03 16:54:16 +0100201
202/* Section 6.2.4 */
Harald Welte8772f582019-05-14 16:34:47 +0200203static struct msgb *ccid_gen_escape_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq, uint8_t cmd_sts,
204 enum ccid_error_code err, const uint8_t *data, uint32_t data_len)
Harald Welte63653742019-01-03 16:54:16 +0100205{
206 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200207 struct ccid_rdr_to_pc_escape *esc =
208 (struct ccid_rdr_to_pc_escape *) msgb_put(msg, sizeof(*esc) + data_len);
Harald Welte8772f582019-05-14 16:34:47 +0200209 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100210
Harald Welte8772f582019-05-14 16:34:47 +0200211 SET_HDR_IN(esc, RDR_to_PC_Escape, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200212 osmo_store32le(data_len, &esc->hdr.hdr.dwLength);
Harald Welte63653742019-01-03 16:54:16 +0100213 memcpy(esc->abData, data, data_len);
214 return msg;
215}
Harald Welte8772f582019-05-14 16:34:47 +0200216static struct msgb *ccid_gen_escape(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
217 enum ccid_error_code err, const uint8_t *data,
218 uint32_t data_len)
219{
220 return ccid_gen_escape_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err, data, data_len);
221}
Harald Welte63653742019-01-03 16:54:16 +0100222
223/* Section 6.2.5 */
Harald Welte8772f582019-05-14 16:34:47 +0200224static struct msgb *ccid_gen_clock_and_rate_nr(uint8_t slot_nr, uint8_t icc_status, uint8_t seq,
225 uint8_t cmd_sts, enum ccid_error_code err,
226 uint32_t clock_khz, uint32_t rate_bps)
Harald Welte63653742019-01-03 16:54:16 +0100227{
228 struct msgb *msg = ccid_msgb_alloc();
Harald Welte92e7c0b2019-05-14 09:32:10 +0200229 struct ccid_rdr_to_pc_data_rate_and_clock *drc =
230 (struct ccid_rdr_to_pc_data_rate_and_clock *) msgb_put(msg, sizeof(*drc));
Harald Welte8772f582019-05-14 16:34:47 +0200231 uint8_t sts = (cmd_sts & CCID_CMD_STATUS_MASK) | icc_status;
Harald Welte63653742019-01-03 16:54:16 +0100232
Harald Welte8772f582019-05-14 16:34:47 +0200233 SET_HDR_IN(drc, RDR_to_PC_DataRateAndClockFrequency, slot_nr, seq, sts, err);
Harald Welte92e7c0b2019-05-14 09:32:10 +0200234 osmo_store32le(8, &drc->hdr.hdr.dwLength); /* Message-specific data length (wtf?) */
235 osmo_store32le(clock_khz, &drc->dwClockFrequency); /* kHz */
236 osmo_store32le(rate_bps, &drc->dwDataRate); /* bps */
Harald Welte63653742019-01-03 16:54:16 +0100237 return msg;
238}
Harald Welte8772f582019-05-14 16:34:47 +0200239static struct msgb *ccid_gen_clock_and_rate(struct ccid_slot *cs, uint8_t seq, uint8_t cmd_sts,
240 enum ccid_error_code err, uint32_t clock_khz,
241 uint32_t rate_bps)
Harald Welte63653742019-01-03 16:54:16 +0100242{
Harald Welte8772f582019-05-14 16:34:47 +0200243 return ccid_gen_clock_and_rate_nr(cs->slot_nr, get_icc_status(cs), seq, cmd_sts, err,
244 clock_khz, rate_bps);
Harald Welte63653742019-01-03 16:54:16 +0100245}
Harald Welte8772f582019-05-14 16:34:47 +0200246
247/*! generate an error response for given input message_type/slot_nr/seq
248 * \param[in] msg_type CCID Message Type against which response is to be created
249 * \param[in] slot_nr CCID Slot Number
250 * \param[in] icc_status ICC Status of the slot
251 * \param[in] seq CCID Sequence number
252 * \param[in] err_code CCID Error Code to send
253 * \returns dynamically-allocated message buffer containing error response */
254static struct msgb *gen_err_resp(enum ccid_msg_type msg_type, uint8_t slot_nr, uint8_t icc_status,
255 uint8_t seq, enum ccid_error_code err_code)
256{
257 struct msgb *resp = NULL;
258
259 switch (msg_type) {
260 case PC_to_RDR_IccPowerOn:
261 case PC_to_RDR_XfrBlock:
262 case PC_to_RDR_Secure:
263 /* Return RDR_to_PC_DataBlock */
264 resp = ccid_gen_data_block_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
265 err_code, NULL, 0);
266 break;
267
268 case PC_to_RDR_IccPowerOff:
269 case PC_to_RDR_GetSlotStatus:
270 case PC_to_RDR_IccClock:
271 case PC_to_RDR_T0APDU:
272 case PC_to_RDR_Mechanical:
273 case PC_to_RDR_Abort:
274 /* Return RDR_to_PC_SlotStatus */
275 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
276 err_code);
277 break;
278
279 case PC_to_RDR_GetParameters:
280 case PC_to_RDR_ResetParameters:
281 case PC_to_RDR_SetParameters:
282 /* Return RDR_to_PC_Parameters */
283 resp = ccid_gen_parameters_t0_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
284 err_code, NULL); /* FIXME: parameters? */
285 break;
286
287 case PC_to_RDR_Escape:
288 /* Return RDR_to_PC_Escape */
289 resp = ccid_gen_escape_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
290 err_code, NULL, 0);
291 break;
292
293 case PC_to_RDR_SetDataRateAndClockFrequency:
294 /* Return RDR_to_PC_SlotStatus */
295 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
296 err_code);
297 break;
298
299 default:
300 /* generate general error */
301 resp = ccid_gen_slot_status_nr(slot_nr, icc_status, seq, CCID_CMD_STATUS_FAILED,
302 CCID_ERR_CMD_NOT_SUPPORTED);
303 break;
304 }
305 return resp;
306}
Harald Welte63653742019-01-03 16:54:16 +0100307
308/***********************************************************************
309 * Message reception / parsing
310 ***********************************************************************/
311
312/* Section 6.1.3 */
313static int ccid_handle_get_slot_status(struct ccid_slot *cs, struct msgb *msg)
314{
315 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200316 const struct ccid_header *ch = (const struct ccid_header *) u;
317 uint8_t seq = u->get_slot_status.hdr.bSeq;
Harald Welte63653742019-01-03 16:54:16 +0100318 struct msgb *resp;
319
Harald Welte8772f582019-05-14 16:34:47 +0200320 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
Harald Welte63653742019-01-03 16:54:16 +0100321
Harald Welte8772f582019-05-14 16:34:47 +0200322 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100323}
324
325
326/* Section 6.1.1 */
327static int ccid_handle_icc_power_on(struct ccid_slot *cs, struct msgb *msg)
328{
329 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200330 const struct ccid_header *ch = (const struct ccid_header *) u;
331 uint8_t seq = u->icc_power_on.hdr.bSeq;
Harald Welte63653742019-01-03 16:54:16 +0100332 struct msgb *resp;
333
334 /* TODO: send actual ATR; handle error cases */
335 /* TODO: handle this asynchronously */
Harald Welte8772f582019-05-14 16:34:47 +0200336 resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
Harald Welte63653742019-01-03 16:54:16 +0100337
Harald Welte8772f582019-05-14 16:34:47 +0200338 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100339}
340
341/* Section 6.1.2 */
342static int ccid_handle_icc_power_off(struct ccid_slot *cs, struct msgb *msg)
343{
344 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200345 const struct ccid_header *ch = (const struct ccid_header *) u;
346 uint8_t seq = u->icc_power_off.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200347 struct msgb *resp;
348
Harald Welte8772f582019-05-14 16:34:47 +0200349 /* FIXME */
350 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
351 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100352}
353
354/* Section 6.1.4 */
355static int ccid_handle_xfr_block(struct ccid_slot *cs, struct msgb *msg)
356{
357 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200358 const struct ccid_header *ch = (const struct ccid_header *) u;
359 uint8_t seq = u->xfr_block.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200360 struct msgb *resp;
361
Harald Welte8772f582019-05-14 16:34:47 +0200362 /* FIXME */
363 resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
364 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100365}
366
367/* Section 6.1.5 */
368static int ccid_handle_get_parameters(struct ccid_slot *cs, struct msgb *msg)
369{
370 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200371 const struct ccid_header *ch = (const struct ccid_header *) u;
372 uint8_t seq = u->get_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200373 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200374
375 /* FIXME */
376 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100377}
378
379/* Section 6.1.6 */
380static int ccid_handle_reset_parameters(struct ccid_slot *cs, struct msgb *msg)
381{
382 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200383 const struct ccid_header *ch = (const struct ccid_header *) u;
384 uint8_t seq = u->reset_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200385 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200386
387 /* FIXME */
388 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100389}
390
391/* Section 6.1.7 */
392static int ccid_handle_set_parameters(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->set_parameters.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200397 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200398
399 /* FIXME */
400 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100401}
402
403/* Section 6.1.8 */
404static int ccid_handle_escape(struct ccid_slot *cs, struct msgb *msg)
405{
406 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200407 const struct ccid_header *ch = (const struct ccid_header *) u;
408 uint8_t seq = u->escape.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200409 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200410
411 resp = ccid_gen_escape(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED, NULL, 0);
412 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100413}
414
415/* Section 6.1.9 */
416static int ccid_handle_icc_clock(struct ccid_slot *cs, struct msgb *msg)
417{
418 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200419 const struct ccid_header *ch = (const struct ccid_header *) u;
420 uint8_t seq = u->icc_clock.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200421 struct msgb *resp;
422
Harald Welte8772f582019-05-14 16:34:47 +0200423 /* FIXME: Actually Stop/Start the clock */
424 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
425 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100426}
427
428/* Section 6.1.10 */
429static int ccid_handle_t0apdu(struct ccid_slot *cs, struct msgb *msg)
430{
431 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200432 const struct ccid_header *ch = (const struct ccid_header *) u;
433 uint8_t seq = u->t0apdu.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200434 struct msgb *resp;
435
Harald Welte8772f582019-05-14 16:34:47 +0200436 /* FIXME */
437 //resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
438 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
439 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100440}
441
442/* Section 6.1.11 */
443static int ccid_handle_secure(struct ccid_slot *cs, struct msgb *msg)
444{
445 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200446 const struct ccid_header *ch = (const struct ccid_header *) u;
447 uint8_t seq = u->secure.hdr.bSeq;
448 struct msgb *resp;
449
450 /* FIXME */
451 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
452 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100453}
454
455/* Section 6.1.12 */
456static int ccid_handle_mechanical(struct ccid_slot *cs, struct msgb *msg)
457{
458 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200459 const struct ccid_header *ch = (const struct ccid_header *) u;
460 uint8_t seq = u->mechanical.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200461 struct msgb *resp;
462
Harald Welte8772f582019-05-14 16:34:47 +0200463 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
464 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100465}
466
467/* Section 6.1.13 */
468static int ccid_handle_abort(struct ccid_slot *cs, struct msgb *msg)
469{
470 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200471 const struct ccid_header *ch = (const struct ccid_header *) u;
472 uint8_t seq = u->abort.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200473 struct msgb *resp;
474
Harald Welte8772f582019-05-14 16:34:47 +0200475 /* Check if the currently in-progress message is Abortable */
476 switch (0/* FIXME */) {
477 case PC_to_RDR_IccPowerOn:
478 case PC_to_RDR_XfrBlock:
479 case PC_to_RDR_Escape:
480 case PC_to_RDR_Secure:
481 case PC_to_RDR_Mechanical:
482 //case PC_to_RDR_Abort: /* seriously? WTF! */
483 break;
484 default:
485 /* CCID spec lists CMD_NOT_ABORTED, but gives no numberic value ?!? */
486 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_FAILED, CCID_ERR_CMD_NOT_SUPPORTED);
487 return ccid_slot_send_unbusy(cs, resp);
488 }
489
490 /* FIXME */
491 resp = ccid_gen_slot_status(cs, seq, CCID_CMD_STATUS_OK, 0);
492 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100493}
494
495/* Section 6.1.14 */
496static int ccid_handle_set_rate_and_clock(struct ccid_slot *cs, struct msgb *msg)
497{
Harald Welte92e7c0b2019-05-14 09:32:10 +0200498 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
Harald Welte8772f582019-05-14 16:34:47 +0200499 const struct ccid_header *ch = (const struct ccid_header *) u;
500 uint8_t seq = u->set_rate_and_clock.hdr.bSeq;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200501 struct msgb *resp;
Harald Welte8772f582019-05-14 16:34:47 +0200502
503 /* FIXME */
504 resp = ccid_gen_clock_and_rate(cs, seq, CCID_CMD_STATUS_OK, 0, 9600, 2500000);
505 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100506}
507
Harald Welte8772f582019-05-14 16:34:47 +0200508/*! Handle data arriving from the host on the OUT endpoint.
509 * \param[in] cs CCID Instance on which to operate
510 * \param[in] msgb received message buffer containing one CCID OUT EP message from the host
511 * \returns 0 on success; negative on error */
Harald Welte63653742019-01-03 16:54:16 +0100512int ccid_handle_out(struct ccid_instance *ci, struct msgb *msg)
513{
514 const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
515 const struct ccid_header *ch = (const struct ccid_header *) u;
516 unsigned int len = msgb_length(msg);
517 struct ccid_slot *cs;
Harald Welte8772f582019-05-14 16:34:47 +0200518 struct msgb *resp;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200519 int rc;
Harald Welte63653742019-01-03 16:54:16 +0100520
521 if (len < sizeof(*ch)) {
522 /* FIXME */
523 return -1;
524 }
525
Harald Welte8772f582019-05-14 16:34:47 +0200526 /* Check for invalid slot number */
Harald Welte92e7c0b2019-05-14 09:32:10 +0200527 cs = get_ccid_slot(ci, ch->bSlot);
Harald Welte63653742019-01-03 16:54:16 +0100528 if (!cs) {
Harald Welte8772f582019-05-14 16:34:47 +0200529 resp = gen_err_resp(ch->bMessageType, ch->bSlot, CCID_ICC_STATUS_NO_ICC, ch->bSeq, 5);
530 return ccid_send(ci, resp);
Harald Welte63653742019-01-03 16:54:16 +0100531 }
532
Harald Welte8772f582019-05-14 16:34:47 +0200533 /* Check if slot is already busy; Reject any additional commands meanwhile */
534 if (cs->cmd_busy) {
535 /* FIXME: ABORT logic as per section 5.3.1 of CCID Spec v1.1 */
536 resp = gen_err_resp(ch->bMessageType, ch->bSlot, get_icc_status(cs), ch->bSeq,
537 CCID_ERR_CMD_SLOT_BUSY);
538 return ccid_send(ci, resp);
539 }
540
541 /* we're now processing a command for the slot; mark slot as busy */
542 cs->cmd_busy = true;
543
544 /* TODO: enqueue into the per-slot specific input queue */
545
Harald Welte63653742019-01-03 16:54:16 +0100546 switch (ch->bMessageType) {
547 case PC_to_RDR_GetSlotStatus:
548 if (len != sizeof(u->get_slot_status))
549 goto short_msg;
550 rc = ccid_handle_get_slot_status(cs, msg);
551 break;
552 case PC_to_RDR_IccPowerOn:
553 if (len != sizeof(u->icc_power_on))
554 goto short_msg;
555 rc = ccid_handle_icc_power_on(cs, msg);
556 break;
557 case PC_to_RDR_IccPowerOff:
558 if (len != sizeof(u->icc_power_off))
559 goto short_msg;
560 rc = ccid_handle_icc_power_off(cs, msg);
561 break;
562 case PC_to_RDR_XfrBlock:
563 if (len < sizeof(u->xfr_block))
564 goto short_msg;
565 rc = ccid_handle_xfr_block(cs, msg);
566 break;
567 case PC_to_RDR_GetParameters:
568 if (len != sizeof(u->get_parameters))
569 goto short_msg;
570 rc = ccid_handle_get_parameters(cs, msg);
571 break;
572 case PC_to_RDR_ResetParameters:
573 if (len != sizeof(u->reset_parameters))
574 goto short_msg;
575 rc = ccid_handle_reset_parameters(cs, msg);
576 break;
577 case PC_to_RDR_SetParameters:
578 if (len != sizeof(u->set_parameters))
579 goto short_msg;
580 rc = ccid_handle_set_parameters(cs, msg);
581 break;
582 case PC_to_RDR_Escape:
583 if (len < sizeof(u->escape))
584 goto short_msg;
585 rc = ccid_handle_escape(cs, msg);
586 break;
587 case PC_to_RDR_IccClock:
588 if (len != sizeof(u->icc_clock))
589 goto short_msg;
590 rc = ccid_handle_icc_clock(cs, msg);
591 break;
592 case PC_to_RDR_T0APDU:
593 if (len != /*FIXME*/ sizeof(u->t0apdu))
594 goto short_msg;
Harald Welte92e7c0b2019-05-14 09:32:10 +0200595 rc = ccid_handle_t0apdu(cs, msg);
Harald Welte63653742019-01-03 16:54:16 +0100596 break;
597 case PC_to_RDR_Secure:
598 if (len < sizeof(u->secure))
599 goto short_msg;
600 rc = ccid_handle_secure(cs, msg);
601 break;
602 case PC_to_RDR_Mechanical:
603 if (len != sizeof(u->mechanical))
604 goto short_msg;
605 rc = ccid_handle_mechanical(cs, msg);
606 break;
607 case PC_to_RDR_Abort:
608 if (len != sizeof(u->abort))
609 goto short_msg;
610 rc = ccid_handle_abort(cs, msg);
611 break;
612 case PC_to_RDR_SetDataRateAndClockFrequency:
613 if (len != sizeof(u->set_rate_and_clock))
614 goto short_msg;
615 rc = ccid_handle_set_rate_and_clock(cs, msg);
616 break;
617 default:
Harald Welte8772f582019-05-14 16:34:47 +0200618 /* generic response with bERror = 0 (command not supported) */
619 resp = gen_err_resp(ch->bMessageType, ch->bSlot, CCID_ICC_STATUS_NO_ICC, ch->bSeq,
620 CCID_ERR_CMD_NOT_SUPPORTED);
621 return ccid_slot_send_unbusy(cs, resp);
Harald Welte63653742019-01-03 16:54:16 +0100622 }
Harald Welte92e7c0b2019-05-14 09:32:10 +0200623 return 0;
624
Harald Welte63653742019-01-03 16:54:16 +0100625short_msg:
Harald Welte92e7c0b2019-05-14 09:32:10 +0200626 /* FIXME */
627 return -1;
Harald Welte63653742019-01-03 16:54:16 +0100628}