source: trunk/reader-viaccess.c@ 109

Last change on this file since 109 was 99, checked in by rorothetroll, 11 years ago

reader-viaccess.c : a log message was lost in the last commit. re-adding.

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 (!nanoF0Data) {
441 cs_dump(ep->emm, ep->l, "can't find 0xf0 in emm...");
442 return 0; // error
443 }
444
445 if (nano9EData) {
446 if (!nano91Data) {
447 // set adf
448 insf0[3] = keynr; // key
449 write_cmd(insf0, nano9EData);
450 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
451 cs_dump(insf0, 5, "set adf cmd:");
452 cs_dump(nano9EData, 0x22, "set adf data:");
453 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
454 return 0;
455 }
456 } else {
457 // set adf crypte
458 insf4[3] = keynr; // key
459 insf4[4] = nano91Data[1] + 2 + nano9EData[1] + 2;
460 memcpy (insData, nano91Data, nano91Data[1] + 2);
461 memcpy (insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2);
462 write_cmd(insf4, insData);
463 if(( cta_res[cta_lr-2]!=0x90 && cta_res[cta_lr-2]!=0x91) || cta_res[cta_lr-1]!=0x00 ) {
464 cs_dump(insf4, 5, "set adf encrypted cmd:");
465 cs_dump(insData, insf4[4], "set adf encrypted data:");
466 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
467 return 0;
468 }
469 }
470 }
471
472 if (!nano92Data) {
473 // send subscription
474 ins18[4] = ins18Len + nanoF0Data[1] + 2;
475 memcpy (insData, ins18Data, ins18Len);
476 memcpy (insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2);
477 write_cmd(ins18, insData);
478 if( cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0x00 ) {
479 cs_debug("update successfully written");
480 rc=1; // written
481 } else {
482 cs_dump(ins18, 5, "set subscription cmd:");
483 cs_dump(insData, ins18[4], "set subscription data:");
484 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
485 }
486
487 } else {
488 // send subscription encrypted
489
490 if (!nano81Data) {
491 cs_dump(ep->emm, ep->l, "0x92 found, but can't find 0x81 in emm...");
492 return 0; // error
493 }
494
495 ins1c[3] = keynr; // key
496 ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2;
497 memcpy (insData, nano92Data, nano92Data[1] + 2);
498 memcpy (insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2);
499 memcpy (insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2);
500 write_cmd(ins1c, insData);
501 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
502 /* maybe a 2nd level status, so read it */
503 ///cs_dump(ins1c, 5, "set subscription encrypted cmd:");
504 ///cs_dump(insData, ins1c[4], "set subscription encrypted data:");
505 ///cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
506
507 read_cmd(insc8, insc8Data);
508 if( cta_res[0] != 0x00 || cta_res[1] != 00 || cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
509 ///cs_dump(cta_res, cta_lr, "extended status error:");
510 return 0;
511 } else {
512 cs_debug("update successfully written (with extended status OK)");
513 rc=1; // written
514 }
515 } else {
516 cs_debug("update successfully written");
517 rc=1; // written
518 }
519 }
520
521 memset(&last_geo, 0, sizeof(last_geo));
522
523 /*
524 Sub Main()
525 Sc.Write("CA A4 04 00 03")
526 RX
527 Sc.Write("02 07 11")
528 RX
529 Sc.Write("CA F0 00 01 22")
530 RX
531 Sc.Write("9E 20")
532 Sc.Write("10 10 08 8A 80 00 04 00 10 10 26 E8 54 80 1E 80")
533 Sc.Write("00 01 00 00 00 00 00 50 00 00 80 02 22 00 08 50")
534 RX
535 Sc.Write("CA 18 01 01 11")
536 RX
537 Sc.Write("A9 05 34 DE 34 FF 80")
538 Sc.Write("F0 08 1A 3E AF B5 2B EE E3 3B")
539 RX
540
541 End Sub
542*/
543 return rc;
544}
545
546int viaccess_card_info(void)
547{
548 int i, l, scls, show_cls;
549 static uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
550 static uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
551 static uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
552 static uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
553 static uchar ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin
554
555 static uchar cls[] = { 0x00, 0x21, 0xff, 0x9f};
556 static uchar pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
557
558 show_cls=reader[ridx].show_cls;
559 memset(&last_geo, 0, sizeof(last_geo));
560
561 cs_log("card detected");
562
563 // set pin
564 write_cmd(ins24, pin);
565
566 insac[2]=0xa4; write_cmd(insac, NULL); // request unique id
567 insb8[4]=0x07; read_cmd(insb8, NULL); // read unique id
568 cs_log("serial: %llu", b2ll(5, cta_res+2));
569
570 scls=0;
571 insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0
572 for (i=1; (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0); i++)
573 {
574 ulong l_provid, l_sa;
575 uchar l_name[64];
576 insc0[4]=0x1a; read_cmd(insc0, NULL); // show provider properties
577 cta_res[2]&=0xF0;
578 l_provid=b2i(3, cta_res);
579
580 insac[2]=0xa5; write_cmd(insac, NULL); // request sa
581 insb8[4]=0x06; read_cmd(insb8, NULL); // read sa
582 l_sa=b2i(4, cta_res+2);
583
584 insac[2]=0xa7; write_cmd(insac, NULL); // request name
585 insb8[4]=0x02; read_cmd(insb8, NULL); // read name nano + len
586 l=cta_res[1];
587 insb8[4]=l; read_cmd(insb8, NULL); // read name
588 cta_res[l]=0;
589 trim((char *)cta_res);
590 if (cta_res[0])
591 snprintf((char *)l_name, sizeof(l_name), ", name: %s", cta_res);
592 else
593 l_name[0]=0;
594
595 // read GEO
596 insac[2]=0xa6; write_cmd(insac, NULL); // request GEO
597 insb8[4]=0x02; read_cmd(insb8, NULL); // read GEO nano + len
598 l=cta_res[1];
599 insb8[4]=l; read_cmd(insb8, NULL); // read geo
600 cs_ri_log("provider: %d, id: %06X%s, sa: %08X, geo: %s",
601 i, l_provid, l_name, l_sa, (l<4) ? "empty" : cs_hexdump(1, cta_res, l));
602
603 // read classes subscription
604 insac[2]=0xa9; insac[4]=4;
605 write_cmd(insac, cls); // request class subs
606 scls=0;
607 while( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
608 {
609 insb8[4]=0x02; read_cmd(insb8, NULL); // read class subs nano + len
610 if( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
611 {
612 int fshow;
613 l=cta_res[1];
614 //fshow=(client[cs_idx].dbglvl==D_DUMP)?1:(scls < show_cls)?1:0;
615 fshow=(scls<show_cls);
616 insb8[4]=l; read_cmd(insb8, NULL); // read class subs
617 if( (cta_res[cta_lr-2]==0x90) && (fshow) &&
618 (cta_res[cta_lr-1]==0x00 || cta_res[cta_lr-1]==0x08) )
619 {
620 show_class(NULL, cta_res, cta_lr-2);
621 scls++;
622 }
623 }
624 }
625
626 insac[4]=0;
627 insa4[2]=0x02;
628 write_cmd(insa4, NULL); // select next provider
629 }
630
631 reader[ridx].online = 1;
632
633 return 0;
634}
Note: See TracBrowser for help on using the repository browser.