source: trunk/reader-viaccess.c@ 96

Last change on this file since 96 was 96, checked in by polo, 15 years ago

Add card info logging when log file reach MaxLogSize

File size: 18.0 KB
Line 
1#include "globals.h"
2#include "reader-common.h"
3
4extern uchar cta_cmd[], cta_res[];
5extern ushort cta_lr;
6
7#define CMD_LEN 5
8
9struct geo_cache
10{
11 ulong provid;
12 uchar geo[256];
13 uchar geo_len;
14};
15
16static struct geo_cache last_geo;
17
18struct via_date {
19 ushort day_s : 5;
20 ushort month_s : 4;
21 ushort year_s : 7;
22
23 ushort day_e : 5;
24 ushort month_e : 4;
25 ushort year_e : 7;
26};
27
28static void parse_via_date(const uchar *buf, struct via_date *vd, int fend)
29{
30 ushort date;
31
32 date = (buf[0]<<8) | buf[1];
33 vd->day_s = date & 0x1f;
34 vd->month_s = (date>>5) & 0x0f;
35 vd->year_s = (date>>9) & 0x7f;
36
37 if( fend )
38 {
39 date = (buf[2]<<8) | buf[3];
40 vd->day_e = date & 0x1f;
41 vd->month_e = (date>>5) & 0x0f;
42 vd->year_e = (date>>9) & 0x7f;
43 }
44}
45
46static void show_class(const char *p, const uchar *b, int l)
47{
48 int i, j;
49
50 // b -> via date (4 bytes)
51 b+=4;
52 l-=4;
53
54 j=l-1;
55 for (; j>=0; j--)
56 for (i=0; i<8; i++)
57 if (b[j] & (1 << (i&7)))
58 {
59 uchar cls;
60 struct via_date vd;
61 parse_via_date(b-4, &vd, 1);
62 cls=(l-(j+1))*8+i;
63 if (p)
64 cs_log("%sclass: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", p, cls,
65 vd.year_s+1980, vd.month_s, vd.day_s,
66 vd.year_e+1980, vd.month_e, vd.day_e);
67 else
68 cs_ri_log("class: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", cls,
69 vd.year_s+1980, vd.month_s, vd.day_s,
70 vd.year_e+1980, vd.month_e, vd.day_e);
71 }
72}
73
74static void show_subs(const uchar *emm)
75{
76 // emm -> A9, A6, B6
77
78 switch( emm[0] )
79 {
80 case 0xA9:
81 show_class("nano A9: ", emm+2, emm[1]);
82 break;
83/*
84 {
85 int i, j, byts;
86 const uchar *oemm;
87
88 oemm = emm;
89 byts = emm[1]-4;
90 emm+=6;
91
92 j=byts-1;
93 for( ; j>=0; j-- )
94 for( i=0; i<8; i++ )
95 if( emm[j] & (1 << (i&7)) )
96 {
97 uchar cls;
98 struct via_date vd;
99 parse_via_date(emm-4, &vd, 1);
100 cls=(byts-(j+1))*8+i;
101 cs_log("%sclass %02X: expiry date: %02d/%02d/%04d - %02d/%02d/%04d",
102 fnano?"nano A9: ":"", cls,
103 vd.day_s, vd.month_s, vd.year_s+1980,
104 vd.day_e, vd.month_e, vd.year_e+1980);
105 }
106 break;
107 }
108*/
109 case 0xA6:
110 {
111 char szGeo[256];
112
113 memset(szGeo, 0, 256);
114 strncpy(szGeo, (char *)emm+2, emm[1]);
115 cs_log("nano A6: geo %s", szGeo);
116 break;
117 }
118 case 0xB6:
119 {
120 uchar m; // modexp
121 struct via_date vd;
122
123 m=emm[emm[1]+1];
124 parse_via_date(emm+2, &vd, 0);
125 cs_log("nano B6: modexp %d%d%d%d%d%d: %02d/%02d/%04d", (m&0x20)?1:0,
126 (m&0x10)?1:0,(m&0x08)?1:0,(m&0x04)?1:0,(m&0x02)?1:0,(m&0x01)?1:0,
127 vd.day_s, vd.month_s, vd.year_s+1980);
128 break;
129 }
130 }
131}
132
133static int chk_prov(uchar *id, uchar keynr)
134{
135 int i, j, rc;
136 for (rc=i=0; (!rc) && (i<reader[ridx].nprov); i++)
137 if(!memcmp(&reader[ridx].prid[i][1], id, 3))
138 for (j=0; (!rc) && (j<16); j++)
139 if (reader[ridx].availkeys[i][j]==keynr)
140 rc=1;
141 return(rc);
142}
143
144static int card_write(const uchar *cmd, const uchar *data, int wflag)
145{
146 int l;
147 uchar buf[256];
148 memcpy(buf, cmd, CMD_LEN);
149 l=wflag ? cmd[4] : 0;
150 if (l && data) memcpy(buf+CMD_LEN, data, l);
151 l=reader_cmd2icc(buf, CMD_LEN+l);
152 return(l);
153}
154
155#define write_cmd(cmd, data) \
156{ \
157 if (card_write(cmd, data, 1)) return(0); \
158}
159
160#define read_cmd(cmd, data) \
161{ \
162 if (card_write(cmd, data, 0)) return(0); \
163}
164
165int viaccess_card_init(uchar *atr, int atrsize)
166{
167 int i;
168 uchar buf[256];
169 static uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
170 static uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
171 static uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
172 static uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
173
174 static uchar insFAC[] = { 0x87, 0x02, 0x00, 0x00, 0x03 }; // init FAC
175 static uchar FacDat[] = { 0x00, 0x00, 0x28 };
176
177 if ((atr[0]!=0x3f) || (atr[1]!=0x77) || (atr[2]!=0x18) || (atr[9]!=0x68)) return(0);
178
179 write_cmd(insFAC, FacDat);
180 if( !(cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0) )
181 return(0);
182
183// switch((atr[atrsize-4]<<8)|atr[atrsize-3])
184// {
185// case 0x6268: ver="2.3"; break;
186// case 0x6668: ver="2.4(?)"; break;
187// case 0xa268:
188// default: ver="unknown"; break;
189// }
190
191 reader[ridx].caid[0]=0x500;
192 memset(reader[ridx].prid, 0xff, sizeof(reader[ridx].prid));
193 insac[2]=0xa4; write_cmd(insac, NULL); // request unique id
194 insb8[4]=0x07; read_cmd(insb8, NULL); // read unique id
195 memcpy(reader[ridx].hexserial, cta_res+2, 5);
196// cs_log("type: viaccess, ver: %s serial: %llu", ver, b2ll(5, cta_res+2));
197 cs_ri_log("type: viaccess(%sstandard atr), caid: %04X, serial: %llu",
198 atr[9]==0x68?"":"non-",reader[ridx].caid[0], b2ll(5, cta_res+2));
199
200 i=0;
201 insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0
202 buf[0]=0;
203 while((cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0))
204 {
205 insc0[4]=0x1a; read_cmd(insc0, NULL); // show provider properties
206 cta_res[2]&=0xF0;
207 reader[ridx].prid[i][0]=0;
208 memcpy(&reader[ridx].prid[i][1], cta_res, 3);
209 memcpy(&reader[ridx].availkeys[i][0], cta_res+10, 16);
210 sprintf((char *)buf+strlen((char *)buf), ",%06lX", b2i(3, &reader[ridx].prid[i][1]));
211//cs_log("buf: %s", buf);
212
213 insac[2]=0xa5; write_cmd(insac, NULL); // request sa
214 insb8[4]=0x06; read_cmd(insb8, NULL); // read sa
215 memcpy(&reader[ridx].sa[i][0], cta_res+2, 4);
216
217/*
218 insac[2]=0xa7; write_cmd(insac, NULL); // request name
219 insb8[4]=0x02; read_cmd(insb8, NULL); // read name nano + len
220 l=cta_res[1];
221 insb8[4]=l; read_cmd(insb8, NULL); // read name
222 cta_res[l]=0;
223cs_log("name: %s", cta_res);
224*/
225
226 insa4[2]=0x02;
227 write_cmd(insa4, NULL); // select next issuer
228 i++;
229 }
230 reader[ridx].nprov=i;
231 cs_ri_log("providers: %d (%s)", reader[ridx].nprov, buf+1);
232
233 /* init the maybe existing aes key */
234 aes_set_key((char *)reader[ridx].aes_key);
235
236 cs_log("ready for requests");
237 memset(&last_geo, 0, sizeof(last_geo));
238 return(1);
239}
240
241int viaccess_do_ecm(ECM_REQUEST *er)
242{
243 static unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id
244 static unsigned char ins88[] = { 0xca,0x88,0x00,0x00,0x00 }; // set ecm
245 static unsigned char insf8[] = { 0xca,0xf8,0x00,0x00,0x00 }; // set geographic info
246 static unsigned char insc0[] = { 0xca,0xc0,0x00,0x00,0x12 }; // read dcw
247
248 const uchar *ecm88Data=er->ecm+4; //XXX what is the 4th byte for ??
249 int ecm88Len=SCT_LEN(er->ecm)-4;
250 ulong provid;
251 int rc=0;
252 int hasD2 = 0;
253
254 if(ecm88Data[0]==0xd2)
255 {
256 // FIXME: use the d2 arguments
257 int len = ecm88Data[1] + 2;
258 ecm88Data += len;
259 ecm88Len -= len;
260 hasD2 = 1;
261 }
262
263 if ((ecm88Data[0]==0x90 || ecm88Data[0]==0x40) && ecm88Data[1]==0x03)
264 {
265 uchar ident[3], keynr;
266 //uchar buff[256]; // MAX_LEN
267 uchar *ecmf8Data=0;
268 int ecmf8Len=0;
269
270 memcpy (ident, &ecm88Data[2], sizeof(ident));
271 provid = b2i(3, ident);
272 ident[2]&=0xF0;
273 keynr=ecm88Data[4]&0x0F;
274 if (!chk_prov(ident, keynr))
275 {
276 cs_debug("smartcardviaccess ecm: provider or key not found on card");
277 return(0);
278 }
279 ecm88Data+=5;
280 ecm88Len-=5;
281
282 if( last_geo.provid != provid )
283 {
284 last_geo.provid = provid;
285 last_geo.geo_len = 0;
286 last_geo.geo[0] = 0;
287 write_cmd(insa4, ident); // set provider
288 }
289
290 while(ecm88Len>0 && ecm88Data[0]<0xA0)
291 {
292 int nanoLen=ecm88Data[1]+2;
293 if (!ecmf8Data)
294 ecmf8Data=(uchar *)ecm88Data;
295 ecmf8Len+=nanoLen;
296 ecm88Len-=nanoLen;
297 ecm88Data+=nanoLen;
298 }
299 if(ecmf8Len)
300 {
301 if( last_geo.geo_len!=ecmf8Len ||
302 memcmp(last_geo.geo, ecmf8Data, last_geo.geo_len))
303 {
304 memcpy(last_geo.geo, ecmf8Data, ecmf8Len);
305 last_geo.geo_len= ecmf8Len;
306 insf8[3]=keynr;
307 insf8[4]=ecmf8Len;
308 write_cmd(insf8, ecmf8Data);
309 }
310 }
311 ins88[2]=ecmf8Len?1:0;
312 ins88[3]=keynr;
313 ins88[4]=ecm88Len;
314 write_cmd(ins88, ecm88Data); // request dcw
315 read_cmd(insc0, NULL); // read dcw
316 switch(cta_res[0])
317 {
318 case 0xe8: // even
319 if(cta_res[1]==8) { memcpy(er->cw,cta_res+2,8); rc=1; }
320 break;
321 case 0xe9: // odd
322 if(cta_res[1]==8) { memcpy(er->cw+8,cta_res+2,8); rc=1; }
323 break;
324 case 0xea: // complete
325 if(cta_res[1]==16) { memcpy(er->cw,cta_res+2,16); rc=1; }
326 break;
327 }
328 }
329
330 if (hasD2) {
331 aes_decrypt(er->cw, 16);
332 }
333
334 return(rc?1:0);
335}
336
337int viaccess_do_emm(EMM_PACKET *ep)
338{
339 static unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id
340 static unsigned char insf0[] = { 0xca,0xf0,0x00,0x01,0x22 }; // set adf
341 static unsigned char insf4[] = { 0xca,0xf4,0x00,0x01,0x00 }; // set adf, encrypted
342 static unsigned char ins18[] = { 0xca,0x18,0x01,0x01,0x00 }; // set subscription
343 static unsigned char ins1c[] = { 0xca,0x1c,0x01,0x01,0x00 }; // set subscription, encrypted
344 static unsigned char insc8[] = { 0xca,0xc8,0x00,0x00,0x02 }; // read extended status
345 static unsigned char insc8Data[] = { 0x00,0x00 }; // data for read extended status
346
347 int emmLen=SCT_LEN(ep->emm)-7;
348 int rc=0;
349
350 ///cs_dump(ep->emm, emmLen+7, "RECEIVED EMM VIACCESS");
351
352 int emmUpToEnd;
353 uchar *emmParsed = ep->emm+7;
354 int provider_ok = 0;
355 uchar keynr = 0;
356 int ins18Len = 0;
357 uchar ins18Data[512];
358 uchar insData[512];
359 uchar *nano81Data = 0;
360 uchar *nano91Data = 0;
361 uchar *nano92Data = 0;
362 uchar *nano9EData = 0;
363 uchar *nanoF0Data = 0;
364
365 for (emmUpToEnd=emmLen; (emmParsed[1] != 0) && (emmUpToEnd > 0); emmUpToEnd -= (2 + emmParsed[1]), emmParsed += (2 + emmParsed[1])) {
366 ///cs_dump (emmParsed, emmParsed[1] + 2, "NANO");
367
368 if (emmParsed[0]==0x90 && emmParsed[1]==0x03) {
369 /* identification of the service operator */
370
371 uchar soid[3], ident[3], i;
372
373 for (i=0; i<3; i++) {
374 soid[i]=ident[i]=emmParsed[2+i];
375 }
376 ident[2]&=0xF0;
377 keynr=soid[2]&0x0F;
378 if (chk_prov(ident, keynr)) {
379 provider_ok = 1;
380 } else {
381 cs_debug("smartcardviaccess emm: provider or key not found on card (%x, %x)", ident, keynr);
382 return 0;
383 }
384
385 // set provider
386 write_cmd(insa4, soid);
387 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
388 cs_dump(insa4, 5, "set provider cmd:");
389 cs_dump(soid, 3, "set provider data:");
390 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
391 return 0;
392 }
393 } else if (emmParsed[0]==0x9e && emmParsed[1]==0x20) {
394 /* adf */
395
396 if (!nano91Data) {
397 /* adf is not crypted, so test it */
398
399 uchar custwp;
400 uchar *afd;
401
402 custwp=reader[ridx].sa[0][3];
403 afd=(uchar*)emmParsed+2;
404
405 if( afd[31-custwp/8] & (1 << (custwp & 7)) )
406 cs_debug("emm for our card %08X", b2i(4, &reader[ridx].sa[0][0]));
407 else
408 return 2; // skipped
409 }
410
411 // memorize
412 nano9EData = emmParsed;
413
414 } else if (emmParsed[0]==0x81) {
415 nano81Data = emmParsed;
416 } else if (emmParsed[0]==0x91 && emmParsed[1]==0x08) {
417 nano91Data = emmParsed;
418 } else if (emmParsed[0]==0x92 && emmParsed[1]==0x08) {
419 nano92Data = emmParsed;
420 } else if (emmParsed[0]==0xF0 && emmParsed[1]==0x08) {
421 nanoF0Data = emmParsed;
422 } else if (emmParsed[0]==0x1D && emmParsed[0]==0x01 && emmParsed[0]==0x01) {
423 /* from cccam... skip it... */
424 } else {
425 /* other nanos */
426 show_subs(emmParsed);
427
428 memcpy(ins18Data+ins18Len, emmParsed, emmParsed[1] + 2);
429 ins18Len += emmParsed [1] + 2;
430 }
431 }
432
433 if (!provider_ok) {
434 cs_debug("viaccess: provider not found in emm... continue anyway...");
435 // force key to 1...
436 keynr = 1;
437 ///return 0;
438 }
439
440 if (!nano9EData) {
441 cs_dump(ep->emm, ep->l, "can't find 0x9e in emm, confidential used?");
442 return 0; // error
443 }
444
445 if (!nanoF0Data) {
446 cs_dump(ep->emm, ep->l, "can't find 0xf0 in emm...");
447 return 0; // error
448 }
449
450 if (!nano91Data) {
451 // set adf
452 insf0[3] = keynr; // key
453 write_cmd(insf0, nano9EData);
454 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
455 cs_dump(insf0, 5, "set adf cmd:");
456 cs_dump(nano9EData, 0x22, "set adf data:");
457 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
458 return 0;
459 }
460 } else {
461 // set adf crypte
462 insf4[3] = keynr; // key
463 insf4[4] = nano91Data[1] + 2 + nano9EData[1] + 2;
464 memcpy (insData, nano91Data, nano91Data[1] + 2);
465 memcpy (insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2);
466 write_cmd(insf4, insData);
467 if(( cta_res[cta_lr-2]!=0x90 && cta_res[cta_lr-2]!=0x91) || cta_res[cta_lr-1]!=0x00 ) {
468 cs_dump(insf4, 5, "set adf encrypted cmd:");
469 cs_dump(insData, insf4[4], "set adf encrypted data:");
470 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
471 return 0;
472 }
473 }
474
475 if (!nano92Data) {
476 // send subscription
477 ins18[4] = ins18Len + nanoF0Data[1] + 2;
478 memcpy (insData, ins18Data, ins18Len);
479 memcpy (insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2);
480 write_cmd(ins18, insData);
481 if( cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0x00 ) {
482 cs_debug("update successfully written");
483 rc=1; // written
484 } else {
485 cs_dump(ins18, 5, "set subscription cmd:");
486 cs_dump(insData, ins18[4], "set subscription data:");
487 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
488 }
489
490 } else {
491 // send subscription encrypted
492
493 if (!nano81Data) {
494 cs_dump(ep->emm, ep->l, "0x92 found, but can't find 0x81 in emm...");
495 return 0; // error
496 }
497
498 ins1c[3] = keynr; // key
499 ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2;
500 memcpy (insData, nano92Data, nano92Data[1] + 2);
501 memcpy (insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2);
502 memcpy (insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2);
503 write_cmd(ins1c, insData);
504 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
505 /* maybe a 2nd level status, so read it */
506 ///cs_dump(ins1c, 5, "set subscription encrypted cmd:");
507 ///cs_dump(insData, ins1c[4], "set subscription encrypted data:");
508 ///cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
509
510 read_cmd(insc8, insc8Data);
511 if( cta_res[0] != 0x00 || cta_res[1] != 00 || cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
512 ///cs_dump(cta_res, cta_lr, "extended status error:");
513 return 0;
514 } else {
515 cs_debug("update successfully written (with extended status OK)");
516 rc=1; // written
517 }
518 } else {
519 cs_debug("update successfully written");
520 rc=1; // written
521 }
522 }
523
524 memset(&last_geo, 0, sizeof(last_geo));
525
526 /*
527 Sub Main()
528 Sc.Write("CA A4 04 00 03")
529 RX
530 Sc.Write("02 07 11")
531 RX
532 Sc.Write("CA F0 00 01 22")
533 RX
534 Sc.Write("9E 20")
535 Sc.Write("10 10 08 8A 80 00 04 00 10 10 26 E8 54 80 1E 80")
536 Sc.Write("00 01 00 00 00 00 00 50 00 00 80 02 22 00 08 50")
537 RX
538 Sc.Write("CA 18 01 01 11")
539 RX
540 Sc.Write("A9 05 34 DE 34 FF 80")
541 Sc.Write("F0 08 1A 3E AF B5 2B EE E3 3B")
542 RX
543
544 End Sub
545*/
546 return rc;
547}
548
549int viaccess_card_info(void)
550{
551 int i, l, scls, show_cls;
552 static uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
553 static uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
554 static uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
555 static uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
556 static uchar ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin
557
558 static uchar cls[] = { 0x00, 0x21, 0xff, 0x9f};
559 static uchar pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
560
561 show_cls=reader[ridx].show_cls;
562 memset(&last_geo, 0, sizeof(last_geo));
563 cs_log("card detected");
564
565 // set pin
566 write_cmd(ins24, pin);
567
568 insac[2]=0xa4; write_cmd(insac, NULL); // request unique id
569 insb8[4]=0x07; read_cmd(insb8, NULL); // read unique id
570 cs_log("serial: %llu", b2ll(5, cta_res+2));
571
572 scls=0;
573 insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0
574 for (i=1; (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0); i++)
575 {
576 ulong l_provid, l_sa;
577 uchar l_name[64];
578 insc0[4]=0x1a; read_cmd(insc0, NULL); // show provider properties
579 cta_res[2]&=0xF0;
580 l_provid=b2i(3, cta_res);
581
582 insac[2]=0xa5; write_cmd(insac, NULL); // request sa
583 insb8[4]=0x06; read_cmd(insb8, NULL); // read sa
584 l_sa=b2i(4, cta_res+2);
585
586 insac[2]=0xa7; write_cmd(insac, NULL); // request name
587 insb8[4]=0x02; read_cmd(insb8, NULL); // read name nano + len
588 l=cta_res[1];
589 insb8[4]=l; read_cmd(insb8, NULL); // read name
590 cta_res[l]=0;
591 trim((char *)cta_res);
592 if (cta_res[0])
593 snprintf((char *)l_name, sizeof(l_name), ", name: %s", cta_res);
594 else
595 l_name[0]=0;
596
597 // read GEO
598 insac[2]=0xa6; write_cmd(insac, NULL); // request GEO
599 insb8[4]=0x02; read_cmd(insb8, NULL); // read GEO nano + len
600 l=cta_res[1];
601 insb8[4]=l; read_cmd(insb8, NULL); // read geo
602 cs_ri_log("provider: %d, id: %06X%s, sa: %08X, geo: %s",
603 i, l_provid, l_name, l_sa, (l<4) ? "empty" : cs_hexdump(1, cta_res, l));
604
605 // read classes subscription
606 insac[2]=0xa9; insac[4]=4;
607 write_cmd(insac, cls); // request class subs
608 scls=0;
609 while( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
610 {
611 insb8[4]=0x02; read_cmd(insb8, NULL); // read class subs nano + len
612 if( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
613 {
614 int fshow;
615 l=cta_res[1];
616 //fshow=(client[cs_idx].dbglvl==D_DUMP)?1:(scls < show_cls)?1:0;
617 fshow=(scls<show_cls);
618 insb8[4]=l; read_cmd(insb8, NULL); // read class subs
619 if( (cta_res[cta_lr-2]==0x90) && (fshow) &&
620 (cta_res[cta_lr-1]==0x00 || cta_res[cta_lr-1]==0x08) )
621 {
622 show_class(NULL, cta_res, cta_lr-2);
623 scls++;
624 }
625 }
626 }
627
628 insac[4]=0;
629 insa4[2]=0x02;
630 write_cmd(insa4, NULL); // select next provider
631 }
632
633 reader[ridx].online = 1;
634
635 return 0;
636}
Note: See TracBrowser for help on using the repository browser.