Create tag for version 1.20
[oscam.git] / reader-conax.c
blob3b08ade265badbf2a51f26e154e6879172cd7d53
1 #include "globals.h"
2 #ifdef READER_CONAX
3 #include "cscrypt/bn.h"
4 #include "reader-common.h"
5 #include "cscrypt/des.h"
7 static int32_t CWPK_CNX(struct s_reader *reader,uint8_t *msg)
9 int32_t ret = 0;
11 uint8_t CWp1[8];
12 uint8_t CWp2[8];
13 uint8_t CWs1[8];
14 uint8_t CWs2[8];
16 CWp1[0] = msg[7];
17 CWp1[1] = msg[8];
18 CWp1[2] = msg[9];
19 CWp1[3] = msg[10];
20 CWp1[4] = msg[11];
21 CWp1[5] = msg[12];
22 CWp1[6] = msg[13];
23 CWp1[7] = msg[14];
25 CWp2[0] = msg[22];
26 CWp2[1] = msg[23];
27 CWp2[2] = msg[24];
28 CWp2[3] = msg[25];
29 CWp2[4] = msg[26];
30 CWp2[5] = msg[27];
31 CWp2[6] = msg[28];
32 CWp2[7] = msg[29];
34 des_ecb3_decrypt(CWp1,reader->cwpk_mod);
35 des_ecb3_decrypt(CWp2,reader->cwpk_mod);
36 CWs1[0] = CWp1[4];
37 CWs1[1] = CWp1[5];
38 CWs1[2] = CWp1[6];
39 CWs1[3] = CWp1[7];
40 CWs1[4] = CWp1[0];
41 CWs1[5] = CWp1[1];
42 CWs1[6] = CWp1[2];
43 CWs1[7] = CWp1[3];
45 CWs2[0] = CWp2[4];
46 CWs2[1] = CWp2[5];
47 CWs2[2] = CWp2[6];
48 CWs2[3] = CWp2[7];
49 CWs2[4] = CWp2[0];
50 CWs2[5] = CWp2[1];
51 CWs2[6] = CWp2[2];
52 CWs2[7] = CWp2[3];
54 int chkok = 1;
55 if(((CWs1[0] + CWs1[1] + CWs1[2]) & 0xFF) != CWs1[3])
57 chkok = 0;
58 rdr_log(reader, "CW0 checksum error [0]");
60 if(((CWs1[4] + CWs1[5] + CWs1[6]) & 0xFF) != CWs1[7])
62 chkok = 0;
63 rdr_log(reader, "CW0 checksum error [1]");
65 if(((CWs2[0] + CWs2[1] + CWs2[2]) & 0xFF) != CWs2[3])
67 chkok = 0;
68 rdr_log(reader, "CW1 checksum error [0]");
70 if(((CWs2[4] + CWs2[5] + CWs2[6]) & 0xFF) != CWs2[7])
72 chkok = 0;
73 rdr_log(reader, "CW1 checksum error [1]");
76 if(chkok == 1)
78 memcpy(&msg[7],CWs1,0x08);
79 memcpy(&msg[22],CWs2,0x08);
81 ret = 0;
83 if(chkok != 1)
85 ret = -8;
88 return ret;
91 static int32_t RSA_CNX(struct s_reader *reader, uint8_t *msg, uint8_t *mod, uint8_t *exp, uint32_t cta_lr, uint32_t modbytes, uint32_t expbytes)
93 int32_t ret = 0;
94 uint32_t n = 0, pre_size = 0, size = 0;
95 BN_CTX *ctx;
96 BIGNUM *bn_mod, *bn_exp, *bn_data, *bn_res;
97 uint8_t data[64];
99 /*prefix size*/
100 pre_size = 2 + 4 + msg[5];
102 /*size of data to decryption*/
103 if(msg[1] > (pre_size - 2))
104 { size = msg[1] - pre_size + 2; }
106 if(cta_lr > (pre_size + size) && size >= modbytes && size < 128)
108 ctx = BN_CTX_new();
110 if(ctx == NULL)
112 rdr_log_dbg(reader, D_READER, "RSA Error in RSA_CNX");
115 BN_CTX_start(ctx);
116 bn_mod = BN_CTX_get(ctx);
117 bn_exp = BN_CTX_get(ctx);
118 bn_data = BN_CTX_get(ctx);
119 bn_res = BN_CTX_get(ctx);
121 /*RSA first round*/
122 BN_bin2bn(mod, modbytes, bn_mod); // rsa modulus
123 BN_bin2bn(exp, expbytes, bn_exp); // exponent
124 BN_bin2bn(msg + pre_size, modbytes, bn_data);
125 BN_mod_exp(bn_res, bn_data, bn_exp, bn_mod, ctx);
127 n = BN_bn2bin(bn_res, data);
129 size -= modbytes; // 3
130 pre_size += modbytes;
132 /*Check if second round is needed*/
133 if(0 < size)
135 /*check if length of data from first RSA round will be enough to padding rest of data*/
136 if((n + size) >= modbytes)
138 /*RSA second round*/
139 /*move the remaining data at the beginning of the buffer*/
140 memcpy(msg, msg + pre_size, size);
141 /*padding buffer with data from first round*/
142 memcpy(msg + size, data + (n - (modbytes - size)), modbytes - size);
144 BN_bin2bn(msg, modbytes, bn_data);
145 BN_mod_exp(bn_res, bn_data, bn_exp, bn_mod, ctx);
146 n = BN_bn2bin(bn_res, data);
147 if(0x25 != data[0])
148 { ret = -1; } /*RSA key is probably wrong*/
150 else
151 { ret = -3; } /*wrong size of data for second round*/
154 if(0 == ret)
155 { memcpy(msg, data, n); }
157 BN_CTX_end(ctx);
158 BN_CTX_free(ctx);
160 else
161 { ret = -2; } /*wrong size of data*/
163 return ret;
166 static time_t chid_date(const uint8_t *ptr, char *buf, int32_t l)
168 time_t rc = 0;
169 struct tm timeinfo;
170 memset(&timeinfo, 0, sizeof(struct tm));
172 if(buf)
174 timeinfo.tm_year = 90 + (ptr[1] >> 4) + (((ptr[0] >> 5) & 7) * 10);
175 timeinfo.tm_mon = (ptr[1] & 0xf) - 1;
176 timeinfo.tm_mday = ptr[0] & 0x1f;
177 timeinfo.tm_isdst = -1;
178 rc = mktime(&timeinfo);
179 strftime(buf, l, "%Y/%m/%d", &timeinfo);
181 return (rc);
184 static int32_t read_record(struct s_reader *reader, const uint8_t *cmd, const uint8_t *data, uint8_t *cta_res)
186 uint16_t cta_lr;
187 uint8_t insCA[] = { 0xDD, 0xCA, 0x00, 0x00, 0x00 };
189 write_cmd(cmd, data); // select record
190 if(cta_res[0] != 0x98)
191 { return (-1); }
193 insCA[4] = cta_res[1]; // get len
194 write_cmd(insCA, NULL); // read record
196 if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1]))
197 { return (-1); }
199 return (cta_lr - 2);
202 static int32_t check_pairing(struct s_reader *reader, const uint8_t *cmd, const uint8_t *data, uint8_t *cta_res)
204 uint16_t cta_lr;
206 if(reader->cwpk_mod_length)
208 write_cmd(cmd, data);
209 rdr_log(reader, "CWPK Pairing is active");
211 else if(reader->rsa_mod_length)
213 rdr_log(reader, "RSA Pairing is active");
215 else
217 rdr_log(reader, "Pairing is not active");
219 return OK;
222 static uint8_t PairingECMRotation(struct s_reader *reader, const ECM_REQUEST *er, int32_t n)
224 uint8_t cta_res[CTA_RES_LEN] = { 0x00 };
225 uint8_t ins26[] = { 0xDD, 0x26, 0x00, 0x00, 0x03, 0x10, 0x01, 0x00 };
226 uint8_t cnxcurrecm = 0;
228 if(0x0 != reader->rsa_mod[0] && n > 3 &&
229 0x54 == er->ecm[n - 3] &&
230 0x02 == er->ecm[n - 2] &&
231 0x00 == er->ecm[n - 1])
233 cnxcurrecm = 1;
236 if((0 == reader->cnxlastecm) != (0 == cnxcurrecm))
238 if(0 == cnxcurrecm) // not paired
239 { ins26[7] = 0x30; }
240 else
241 { ins26[7] = 0x40; }
243 if(read_record(reader, ins26, ins26 + 5, cta_res) <= 0)
244 { rdr_log(reader, "PairingECMRotation - ERROR"); }
246 reader->cnxlastecm = cnxcurrecm;
247 return cnxcurrecm;
250 static int32_t conax_card_init(struct s_reader *reader, ATR *newatr)
252 uint8_t cta_res[CTA_RES_LEN];
253 int32_t i, j, n;
254 static const uint8_t ins26[] = { 0xDD, 0x26, 0x00, 0x00, 0x03, 0x10, 0x01, 0x40 };
255 static const uint8_t inscp[] = { 0xDD, 0x26, 0x00, 0x00, 0x04, 0x6C, 0x02, 0x10,0x00 };
256 uint8_t ins82[] = { 0xDD, 0x82, 0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0xb0, 0x0f, 0xff,
257 0xff, 0xfb, 0x00, 0x00, 0x09, 0x04, 0x0b, 0x00, 0xe0, 0x30, 0x2b };
259 uint8_t cardver = 0;
261 get_hist;
262 if((hist_size < 4) || (memcmp(hist, "0B00", 4)))
263 { return ERROR; }
265 reader->caid = 0xB00;
267 if((n = read_record(reader, ins26, ins26 + 5, cta_res)) <= 0) { return ERROR; } // read caid, card-version
269 for(i = 0; i < n; i += cta_res[i + 1] + 2)
271 switch(cta_res[i])
273 case 0x20:
274 cardver = cta_res[i + 2];
275 break;
277 case 0x28:
278 reader->caid = (cta_res[i + 2] << 8) | cta_res[i + 3];
282 // Ins82 command needs to use the correct CAID reported in nano 0x28
283 ins82[17] = (reader->caid >> 8) & 0xFF;
284 ins82[18] = (reader->caid) & 0xFF;
286 if((n = read_record(reader, ins82, ins82 + 5, cta_res)) <= 0) { return ERROR; } // read serial
288 reader->nprov = 0;
290 for(j = 0, i = 2; i < n; i += cta_res[i + 1] + 2)
292 switch(cta_res[i])
294 case 0x23:
295 if(cta_res[i + 5] != 0x00)
297 memcpy(reader->hexserial, &cta_res[i + 3], 6);
299 else
301 memcpy(reader->sa[j], &cta_res[i + 5], 4);
302 j++;
303 reader->nprov++;
305 break;
309 memset(reader->prid, 0x00, sizeof(reader->prid));
311 rdr_log_sensitive(reader, "type: Conax, caid: %04X, serial: {%llu}, hex serial: {%02x%02x%02x%02x}, card: v%d",
312 reader->caid, (unsigned long long) b2ll(6, reader->hexserial), reader->hexserial[2],
313 reader->hexserial[3], reader->hexserial[4], reader->hexserial[5], cardver);
315 rdr_log(reader, "Providers: %d", reader->nprov);
317 for(j = 0; j < reader->nprov; j++)
319 rdr_log(reader, "Provider: %d Provider-Id: %06X", j + 1, b2i(4, reader->prid[j]));
320 rdr_log_sensitive(reader, "Provider: %d SharedAddress: {%08X}", j + 1, b2i(4, reader->sa[j]));
322 check_pairing(reader, inscp, inscp + 5, cta_res);
324 return OK;
327 static int32_t conax_send_pin(struct s_reader *reader)
329 def_resp;
330 uint8_t insPIN[] = { 0xDD, 0xC8, 0x00, 0x00, 0x07, 0x1D, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00 }; // Last four are the Pin-Code
331 memcpy(insPIN + 8, reader->pincode, 4);
333 write_cmd(insPIN, insPIN + 5);
334 rdr_log_dbg(reader, D_READER, "Sent pincode to card.");
336 return OK;
339 static int32_t conax_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
341 def_resp;
342 int32_t i, j, n, num_dw = 0, rc = 0;
343 uint8_t insA2[] = { 0xDD, 0xA2, 0x00, 0x00, 0x00 };
344 uint8_t insCA[] = { 0xDD, 0xCA, 0x00, 0x00, 0x00 };
346 uint8_t exp[] = { 0x01, 0x00, 0x01 };
347 uint8_t buf[256];
349 char ppp = 0x00;
351 if((n = check_sct_len(er->ecm, 3)) < 0)
352 { return ERROR; }
354 buf[0] = 0x14;
355 buf[1] = n + 1;
357 if(reader->cwpk_mod_length)
359 buf[2] = 4;
360 ppp = 0x01;
362 else if(0x0 != reader->rsa_mod[0])
364 if(0x0 != PairingECMRotation(reader, er, n))
366 buf[2] = 2;
367 ppp = 0x03;
369 else
371 buf[2] = 0;
372 ppp = 0x02;
375 else
377 buf[2] = 0;
378 ppp = 0x02;
381 memcpy(buf + 3, er->ecm, n);
382 insA2[4] = n + 3;
384 write_cmd(insA2, buf); // write Header + ECM
386 while((cta_res[cta_lr - 2] == 0x98) && // Antwort
387 ((insCA[4] = cta_res[cta_lr - 1]) > 0) && (insCA[4] != 0xFF))
389 write_cmd(insCA, NULL); // Codeword auslesen
391 if((cta_res[cta_lr - 2] == 0x98) || ((cta_res[cta_lr - 2] == 0x90)))
393 /*checks if answer is encrypted with RSA algo and decrypts it if needed*/
394 if(0x81 == cta_res[0] && 2 == cta_res[2] >> 5 && 0x03 == ppp) /*81 XX 5X*/
396 if(0x00 == cta_res[cta_lr - 1])
397 { rc = RSA_CNX(reader, cta_res, reader->rsa_mod, exp, cta_lr, 64u, 3u); }
398 else
399 { rc = -4; } /*card has no right to decode this channel*/
401 else if(0x01 == ppp)
403 if(0x00 == cta_res[cta_lr - 1])
405 /*trying to decode using CWPK*/
406 rc = CWPK_CNX(reader, cta_res); /*enabled when no loging needed*/
408 else
410 rc = -4;
414 if(0 == rc)
416 for(i = 0; i < cta_lr - 2 && num_dw < 2; i += cta_res[i + 1] + 2)
418 switch(cta_res[i])
420 case 0x25:
421 if((cta_res[i + 1] >= 0xD) && !((n = cta_res[i + 4]) & 0xFE))
423 rc |= (1 << n);
424 memcpy(ea->cw + (n << 3), cta_res + i + 7, 8);
425 ++num_dw;
427 break;
429 case 0x31:
430 if((cta_res[i + 1] == 0x02 && cta_res[i + 2] == 0x00 && cta_res[i + 3] == 0x00) || \
431 (cta_res[i + 1] == 0x02 && cta_res[i + 2] == 0x40 && cta_res[i + 3] == 0x00))
432 { break; }
433 else if(strcmp(reader->pincode, "none"))
435 conax_send_pin(reader);
436 write_cmd(insA2, buf); // write Header + ECM
438 while((cta_res[cta_lr - 2] == 0x98) && // Antwort
439 ((insCA[4] = cta_res[cta_lr - 1]) > 0) && (insCA[4] != 0xFF))
441 write_cmd(insCA, NULL); // Codeword auslesen
443 if((cta_res[cta_lr - 2] == 0x98) ||
444 ((cta_res[cta_lr - 2] == 0x90) && (!cta_res[cta_lr - 1])))
446 for(j = 0; j < cta_lr - 2; j += cta_res[j + 1] + 2)
448 if((cta_res[j] == 0x25) && // access: is cw
449 (cta_res[j + 1] >= 0xD) && // 0xD: 5 header + 8 cw
450 !((n = cta_res[j + 4]) & 0xFE)) // cw idx must be 0 or 1
452 rc |= (1 << n);
453 memcpy(ea->cw + (n << 3), cta_res + j + 7, 8);
454 ++num_dw;
460 break;
467 switch(rc)
469 case -1:
470 rdr_log(reader, "conax decode ECM problem - RSA key is probably faulty");
471 break;
473 case -2:
474 rdr_log(reader, "conax RSA pairing - wrong size of data");
475 break;
477 case -3:
478 rdr_log(reader, "conax RSA pairing- wrong size of data for second round");
479 /* fallthrough */
481 case -4:
482 rdr_log(reader, "card has no right to decode this channel");
483 break;
485 case -8:
486 rdr_log(reader, "CWPK is faulty");
487 break;
490 /* answer 9011 - conax smart card need reset */
491 if(2 <= cta_lr && 0x90 == cta_res[cta_lr - 2] && 0x11 == cta_res[cta_lr - 1])
493 rdr_log(reader, "conax card hangs - reset is required");
494 reader->card_status = UNKNOWN;
497 if(rc == 3)
498 { return OK; }
499 else
500 { return ERROR; }
503 static int32_t conax_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
505 int32_t i, ok = 0;
506 char tmp_dbg[17];
508 rdr_log_dbg(rdr, D_EMM, "Entered conax_get_emm_type ep->emm[2]=%02x", ep->emm[2]);
510 for(i = 0; i < rdr->nprov; i++)
512 ok = (!memcmp(&ep->emm[6], rdr->sa[i], 4));
513 if(ok) { break; }
516 if(ok)
518 ep->type = SHARED;
519 memset(ep->hexserial, 0, 8);
520 memcpy(ep->hexserial, &ep->emm[6], 4);
521 rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED, ep->hexserial = {%s}",
522 cs_hexdump(1, ep->hexserial, 8, tmp_dbg, sizeof(tmp_dbg)));
523 return 1;
525 else
527 if(!memcmp(&ep->emm[6], rdr->hexserial + 2, 4))
529 ep->type = UNIQUE;
530 memset(ep->hexserial, 0, 8);
531 memcpy(ep->hexserial + 2, &ep->emm[6], 4);
532 rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE, ep->hexserial = {%s}",
533 cs_hexdump(1, ep->hexserial, 8, tmp_dbg, sizeof(tmp_dbg)));
534 return 1;
536 else
538 ep->type = GLOBAL;
539 rdr_log_dbg(rdr, D_EMM, "GLOBAL");
540 memset(ep->hexserial, 0, 8);
541 return 1;
546 static int32_t conax_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
548 if(*emm_filters == NULL)
550 const unsigned int max_filter_count = 2 + rdr->nprov;
551 if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
552 { return ERROR; }
554 struct s_csystem_emm_filter *filters = *emm_filters;
555 *filter_count = 0;
557 int idx = 0, prov;
559 filters[idx].type = EMM_GLOBAL;
560 filters[idx].enabled = 0; // FIXME: dont see any conax global EMM yet
561 filters[idx].filter[0] = 0x82;
562 filters[idx].mask[0] = 0xFF;
563 filters[idx].filter[8] = 0x70;
564 filters[idx].mask[8] = 0xFF;
565 idx++;
567 for(prov = 0; prov < rdr->nprov; prov++)
569 filters[idx].type = EMM_SHARED;
570 filters[idx].enabled = 1;
571 filters[idx].filter[0] = 0x82;
572 filters[idx].mask[0] = 0xFF;
573 memcpy(&filters[idx].filter[4], rdr->sa[prov], 4);
574 memset(&filters[idx].mask[4], 0xFF, 4);
575 idx++;
578 filters[idx].type = EMM_UNIQUE;
579 filters[idx].enabled = 1;
580 filters[idx].filter[0] = 0x82;
581 filters[idx].mask[0] = 0xFF;
582 memcpy(&filters[idx].filter[4], rdr->hexserial + 2, 4);
583 memset(&filters[idx].mask[4], 0xFF, 4);
584 idx++;
586 *filter_count = idx;
589 return OK;
592 static int32_t conax_do_emm(struct s_reader *reader, EMM_PACKET *ep)
594 def_resp;
595 uint8_t insCA[] = { 0xDD, 0xCA, 0x00, 0x00, 0x00 };
596 uint8_t insEMM[] = { 0xDD, 0x84, 0x00, 0x00, 0x00 };
597 uint8_t buf[255];
598 int32_t rc = 0;
600 const int32_t l = ep->emm[2];
602 insEMM[4] = l + 5;
603 buf[0] = 0x12;
604 buf[1] = l + 3;
605 memcpy(buf + 2, ep->emm, buf[1]);
606 write_cmd(insEMM, buf);
608 if(cta_res[0] == 0x98)
610 insCA[4] = cta_res[1];
611 write_cmd(insCA, NULL);
614 rc = ((cta_res[0] == 0x90) && (cta_res[1] == 0x00));
616 if(rc)
617 { return OK; }
618 else
619 { return ERROR; }
622 static int32_t conax_card_info(struct s_reader *reader)
624 def_resp;
625 int32_t type, i, j, k = 0, n = 0, l;
626 uint16_t provid = 0;
627 char provname[32], pdate[32], chid[32];
628 static const uint8_t insC6[] = { 0xDD, 0xC6, 0x00, 0x00, 0x03, 0x1C, 0x01, 0x00 };
629 static const uint8_t ins26[] = { 0xDD, 0x26, 0x00, 0x00, 0x03, 0x1C, 0x01, 0x01 };
630 uint8_t insCA[] = { 0xDD, 0xCA, 0x00, 0x00, 0x00 };
631 char *txt[] = { "Package", "PPV-Event" };
632 static const uint8_t *cmd[] = { insC6, ins26 };
633 time_t start_t = 0, end_t = 0;
634 uint32_t cxclass = 0;
636 cs_clear_entitlement(reader); // reset the entitlements
638 for(type = 0; type < 2; type++)
640 n = 0;
641 write_cmd(cmd[type], cmd[type] + 5);
642 while(cta_res[cta_lr - 2] == 0x98)
644 insCA[4] = cta_res[cta_lr - 1]; // get len
645 write_cmd(insCA, NULL); // read
647 if((cta_res[cta_lr - 2] == 0x90) || (cta_res[cta_lr - 2] == 0x98))
649 for(j = 0; j < cta_lr - 2; j += cta_res[j + 1] + 2)
651 provid = (cta_res[j + 2 + type] << 8) | cta_res[j + 3 + type];
652 chid[0] = '\0';
654 for(k = 0, i = j + 4 + type; (i < j + cta_res[j + 1]); i += cta_res[i + 1] + 2)
656 switch(cta_res[i])
658 case 0x01:
659 l = (cta_res[i + 1] < (sizeof(provname) - 1)) ? cta_res[i + 1] : sizeof(provname) - 1;
660 memcpy(provname, cta_res + i + 2, l);
661 provname[l] = '\0';
662 break;
664 case 0x30:
665 if(k > 1)
667 rdr_log(reader, "%s: %d, id: %04X%s, date: %s - %s, name: %s",
668 txt[type], ++n, provid, chid, pdate, pdate + 16, trim(provname));
670 // add entitlements to list
671 cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]),
672 provid, cxclass, start_t, end_t, type + 1, 1);
674 k = 0;
675 chid[0] = '\0';
677 if(k == 0) { start_t = chid_date(cta_res + i + 2, pdate, 15); }
678 else { end_t = chid_date(cta_res + i + 2, pdate + 16, 15) /* add 23:59:59 here: */ + 0x1517F; }
679 ++k;
680 break;
682 case 0x20: // Provider classes
683 case 0x90: // (?) not sure what this is, saw it once in log
684 snprintf(chid, sizeof(chid), ", classes: %02X%02X%02X%02X",
685 cta_res[i + 2], cta_res[i + 3], cta_res[i + 4] , cta_res[i + 5]);
686 cxclass = b2ll(4, &cta_res[i + 2]);
687 break;
690 rdr_log(reader, "%s: %d, id: %04X%s, date: %s - %s, name: %s",
691 txt[type], ++n, provid, chid, pdate, pdate + 16, trim(provname));
693 // add entitlements to list
694 cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]),
695 provid, cxclass, start_t, end_t, type + 1, 1);
700 rdr_log(reader, "ready for requests");
701 return OK;
704 const struct s_cardsystem reader_conax =
706 .desc = "conax",
707 .caids = (uint16_t[]){ 0x0B, 0 },
708 .do_emm = conax_do_emm,
709 .do_ecm = conax_do_ecm,
710 .card_info = conax_card_info,
711 .card_init = conax_card_init,
712 .get_emm_type = conax_get_emm_type,
713 .get_emm_filter = conax_get_emm_filter,
716 #endif