source: trunk/reader-viaccess.c@ 1

Last change on this file since 1 was 1, checked in by root, 14 years ago

initial import

File size: 17.6 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(uchar *cmd, 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 cs_log("ready for requests");
233 memset(&last_geo, 0, sizeof(last_geo));
234 return(1);
235}
236
237int viaccess_do_ecm(ECM_REQUEST *er)
238{
239 static unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id
240 static unsigned char ins88[] = { 0xca,0x88,0x00,0x00,0x00 }; // set ecm
241 static unsigned char insf8[] = { 0xca,0xf8,0x00,0x00,0x00 }; // set geographic info
242 static unsigned char insc0[] = { 0xca,0xc0,0x00,0x00,0x12 }; // read dcw
243
244 const uchar *ecm88Data=er->ecm+4; //XXX what is the 4th byte for ??
245 int ecm88Len=SCT_LEN(er->ecm)-4;
246 ulong provid;
247 int rc=0;
248
249 if (ecm88Data[0]==0x90 && ecm88Data[1]==0x03)
250 {
251 uchar ident[3], keynr;
252 //uchar buff[256]; // MAX_LEN
253 uchar *ecmf8Data=0;
254 int ecmf8Len=0;
255
256 memcpy (ident, &ecm88Data[2], sizeof(ident));
257 provid = b2i(3, ident);
258 ident[2]&=0xF0;
259 keynr=ecm88Data[4]&0x0F;
260 if (!chk_prov(ident, keynr))
261 {
262 cs_debug("smartcardviaccess ecm: provider or key not found on card");
263 return(0);
264 }
265 ecm88Data+=5;
266 ecm88Len-=5;
267
268 if( last_geo.provid != provid )
269 {
270 last_geo.provid = provid;
271 last_geo.geo_len = 0;
272 last_geo.geo[0] = 0;
273 write_cmd(insa4, ident); // set provider
274 }
275
276 while(ecm88Len>0 && ecm88Data[0]<0xA0)
277 {
278 int nanoLen=ecm88Data[1]+2;
279 if (!ecmf8Data)
280 ecmf8Data=(uchar *)ecm88Data;
281 ecmf8Len+=nanoLen;
282 ecm88Len-=nanoLen;
283 ecm88Data+=nanoLen;
284 }
285 if(ecmf8Len)
286 {
287 if( last_geo.geo_len!=ecmf8Len ||
288 memcmp(last_geo.geo, ecmf8Data, last_geo.geo_len))
289 {
290 memcpy(last_geo.geo, ecmf8Data, ecmf8Len);
291 last_geo.geo_len= ecmf8Len;
292 insf8[3]=keynr;
293 insf8[4]=ecmf8Len;
294 write_cmd(insf8, ecmf8Data);
295 }
296 }
297 ins88[2]=ecmf8Len?1:0;
298 ins88[3]=keynr;
299 ins88[4]=ecm88Len;
300 write_cmd(ins88, (uchar *)ecm88Data); // request dcw
301 read_cmd(insc0, NULL); // read dcw
302 switch(cta_res[0])
303 {
304 case 0xe8: // even
305 if(cta_res[1]==8) { memcpy(er->cw,cta_res+2,8); rc=1; }
306 break;
307 case 0xe9: // odd
308 if(cta_res[1]==8) { memcpy(er->cw+8,cta_res+2,8); rc=1; }
309 break;
310 case 0xea: // complete
311 if(cta_res[1]==16) { memcpy(er->cw,cta_res+2,16); rc=1; }
312 break;
313 }
314 }
315 return(rc?1:0);
316}
317
318int viaccess_do_emm(EMM_PACKET *ep)
319{
320 static unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id
321 static unsigned char insf0[] = { 0xca,0xf0,0x00,0x01,0x22 }; // set adf
322 static unsigned char insf4[] = { 0xca,0xf4,0x00,0x01,0x00 }; // set adf, encrypted
323 static unsigned char ins18[] = { 0xca,0x18,0x01,0x01,0x00 }; // set subscription
324 static unsigned char ins1c[] = { 0xca,0x1c,0x01,0x01,0x00 }; // set subscription, encrypted
325 static unsigned char insc8[] = { 0xca,0xc8,0x00,0x00,0x02 }; // read extended status
326 static unsigned char insc8Data[] = { 0x00,0x00 }; // data for read extended status
327
328 int emmLen=SCT_LEN(ep->emm)-7;
329 int rc=0;
330
331 ///cs_dump(ep->emm, emmLen+7, "RECEIVED EMM VIACCESS");
332
333 int emmUpToEnd;
334 uchar *emmParsed = ep->emm+7;
335 int provider_ok = 0;
336 uchar keynr = 0;
337 int ins18Len = 0;
338 uchar ins18Data[512];
339 uchar insData[512];
340 uchar *nano81Data = 0;
341 uchar *nano91Data = 0;
342 uchar *nano92Data = 0;
343 uchar *nano9EData = 0;
344 uchar *nanoF0Data = 0;
345
346 for (emmUpToEnd=emmLen; (emmParsed[1] != 0) && (emmUpToEnd > 0); emmUpToEnd -= (2 + emmParsed[1]), emmParsed += (2 + emmParsed[1])) {
347 ///cs_dump (emmParsed, emmParsed[1] + 2, "NANO");
348
349 if (emmParsed[0]==0x90 && emmParsed[1]==0x03) {
350 /* identification of the service operator */
351
352 uchar soid[3], ident[3], i;
353
354 for (i=0; i<3; i++) {
355 soid[i]=ident[i]=emmParsed[2+i];
356 }
357 ident[2]&=0xF0;
358 keynr=soid[2]&0x0F;
359 if (chk_prov(ident, keynr)) {
360 provider_ok = 1;
361 } else {
362 cs_debug("smartcardviaccess emm: provider or key not found on card (%x, %x)", ident, keynr);
363 return 0;
364 }
365
366 // set provider
367 write_cmd(insa4, soid);
368 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
369 cs_dump(insa4, 5, "set provider cmd:");
370 cs_dump(soid, 3, "set provider data:");
371 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
372 return 0;
373 }
374 } else if (emmParsed[0]==0x9e && emmParsed[1]==0x20) {
375 /* adf */
376
377 if (!nano91Data) {
378 /* adf is not crypted, so test it */
379
380 uchar custwp;
381 uchar *afd;
382
383 custwp=reader[ridx].sa[0][3];
384 afd=(uchar*)emmParsed+2;
385
386 if( afd[31-custwp/8] & (1 << (custwp & 7)) )
387 cs_debug("emm for our card %08X", b2i(4, &reader[ridx].sa[0][0]));
388 else
389 return 2; // skipped
390 }
391
392 // memorize
393 nano9EData = emmParsed;
394
395 } else if (emmParsed[0]==0x81) {
396 nano81Data = emmParsed;
397 } else if (emmParsed[0]==0x91 && emmParsed[1]==0x08) {
398 nano91Data = emmParsed;
399 } else if (emmParsed[0]==0x92 && emmParsed[1]==0x08) {
400 nano92Data = emmParsed;
401 } else if (emmParsed[0]==0xF0 && emmParsed[1]==0x08) {
402 nanoF0Data = emmParsed;
403 } else if (emmParsed[0]==0x1D && emmParsed[0]==0x01 && emmParsed[0]==0x01) {
404 /* from cccam... skip it... */
405 } else {
406 /* other nanos */
407 show_subs(emmParsed);
408
409 memcpy(ins18Data+ins18Len, emmParsed, emmParsed[1] + 2);
410 ins18Len += emmParsed [1] + 2;
411 }
412 }
413
414 if (!provider_ok) {
415 cs_debug("viaccess: provider not found in emm... continue anyway...");
416 // force key to 1...
417 keynr = 1;
418 ///return 0;
419 }
420
421 if (!nano9EData) {
422 cs_dump(ep->emm, ep->l, "can't find 0x9e in emm, confidential used?");
423 return 0; // error
424 }
425
426 if (!nanoF0Data) {
427 cs_dump(ep->emm, ep->l, "can't find 0xf0 in emm...");
428 return 0; // error
429 }
430
431 if (!nano91Data) {
432 // set adf
433 insf0[3] = keynr; // key
434 write_cmd(insf0, nano9EData);
435 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
436 cs_dump(insf0, 5, "set adf cmd:");
437 cs_dump(nano9EData, 0x22, "set adf data:");
438 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
439 return 0;
440 }
441 } else {
442 // set adf crypte
443 insf4[3] = keynr; // key
444 insf4[4] = nano91Data[1] + 2 + nano9EData[1] + 2;
445 memcpy (insData, nano91Data, nano91Data[1] + 2);
446 memcpy (insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2);
447 write_cmd(insf4, insData);
448 if(( cta_res[cta_lr-2]!=0x90 && cta_res[cta_lr-2]!=0x91) || cta_res[cta_lr-1]!=0x00 ) {
449 cs_dump(insf4, 5, "set adf encrypted cmd:");
450 cs_dump(insData, insf4[4], "set adf encrypted data:");
451 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
452 return 0;
453 }
454 }
455
456 if (!nano92Data) {
457 // send subscription
458 ins18[4] = ins18Len + nanoF0Data[1] + 2;
459 memcpy (insData, ins18Data, ins18Len);
460 memcpy (insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2);
461 write_cmd(ins18, insData);
462 if( cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0x00 ) {
463 cs_debug("update successfully written");
464 rc=1; // written
465 } else {
466 cs_dump(ins18, 5, "set subscription cmd:");
467 cs_dump(insData, ins18[4], "set subscription data:");
468 cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
469 }
470
471 } else {
472 // send subscription encrypted
473
474 if (!nano81Data) {
475 cs_dump(ep->emm, ep->l, "0x92 found, but can't find 0x81 in emm...");
476 return 0; // error
477 }
478
479 ins1c[3] = keynr; // key
480 ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2;
481 memcpy (insData, nano92Data, nano92Data[1] + 2);
482 memcpy (insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2);
483 memcpy (insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2);
484 write_cmd(ins1c, insData);
485 if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
486 /* maybe a 2nd level status, so read it */
487 ///cs_dump(ins1c, 5, "set subscription encrypted cmd:");
488 ///cs_dump(insData, ins1c[4], "set subscription encrypted data:");
489 ///cs_log("update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
490
491 read_cmd(insc8, insc8Data);
492 if( cta_res[0] != 0x00 || cta_res[1] != 00 || cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
493 ///cs_dump(cta_res, cta_lr, "extended status error:");
494 return 0;
495 } else {
496 cs_debug("update successfully written (with extended status OK)");
497 rc=1; // written
498 }
499 } else {
500 cs_debug("update successfully written");
501 rc=1; // written
502 }
503 }
504
505 memset(&last_geo, 0, sizeof(last_geo));
506
507 /*
508 Sub Main()
509 Sc.Write("CA A4 04 00 03")
510 RX
511 Sc.Write("02 07 11")
512 RX
513 Sc.Write("CA F0 00 01 22")
514 RX
515 Sc.Write("9E 20")
516 Sc.Write("10 10 08 8A 80 00 04 00 10 10 26 E8 54 80 1E 80")
517 Sc.Write("00 01 00 00 00 00 00 50 00 00 80 02 22 00 08 50")
518 RX
519 Sc.Write("CA 18 01 01 11")
520 RX
521 Sc.Write("A9 05 34 DE 34 FF 80")
522 Sc.Write("F0 08 1A 3E AF B5 2B EE E3 3B")
523 RX
524
525 End Sub
526*/
527 return rc;
528}
529
530int viaccess_card_info(void)
531{
532 int i, l, scls, show_cls;
533 static uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
534 static uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
535 static uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
536 static uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
537 static uchar ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin
538
539 static uchar cls[] = { 0x00, 0x21, 0xff, 0x9f};
540 static uchar pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
541
542 show_cls=reader[ridx].show_cls;
543 memset(&last_geo, 0, sizeof(last_geo));
544
545 // set pin
546 write_cmd(ins24, pin);
547
548 insac[2]=0xa4; write_cmd(insac, NULL); // request unique id
549 insb8[4]=0x07; read_cmd(insb8, NULL); // read unique id
550 cs_log("serial: %llu", b2ll(5, cta_res+2));
551
552 scls=0;
553 insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0
554 for (i=1; (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0); i++)
555 {
556 ulong l_provid, l_sa;
557 uchar l_name[64];
558 insc0[4]=0x1a; read_cmd(insc0, NULL); // show provider properties
559 cta_res[2]&=0xF0;
560 l_provid=b2i(3, cta_res);
561
562 insac[2]=0xa5; write_cmd(insac, NULL); // request sa
563 insb8[4]=0x06; read_cmd(insb8, NULL); // read sa
564 l_sa=b2i(4, cta_res+2);
565
566 insac[2]=0xa7; write_cmd(insac, NULL); // request name
567 insb8[4]=0x02; read_cmd(insb8, NULL); // read name nano + len
568 l=cta_res[1];
569 insb8[4]=l; read_cmd(insb8, NULL); // read name
570 cta_res[l]=0;
571 trim((char *)cta_res);
572 if (cta_res[0])
573 snprintf((char *)l_name, sizeof(l_name), ", name: %s", cta_res);
574 else
575 l_name[0]=0;
576
577 // read GEO
578 insac[2]=0xa6; write_cmd(insac, NULL); // request GEO
579 insb8[4]=0x02; read_cmd(insb8, NULL); // read GEO nano + len
580 l=cta_res[1];
581 insb8[4]=l; read_cmd(insb8, NULL); // read geo
582 cs_ri_log("provider: %d, id: %06X%s, sa: %08X, geo: %s",
583 i, l_provid, l_name, l_sa, (l<4) ? "empty" : cs_hexdump(1, cta_res, l));
584
585 // read classes subscription
586 insac[2]=0xa9; insac[4]=4;
587 write_cmd(insac, cls); // request class subs
588 scls=0;
589 while( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
590 {
591 insb8[4]=0x02; read_cmd(insb8, NULL); // read class subs nano + len
592 if( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
593 {
594 int fshow;
595 l=cta_res[1];
596 //fshow=(client[cs_idx].dbglvl==D_DUMP)?1:(scls < show_cls)?1:0;
597 fshow=(scls<show_cls);
598 insb8[4]=l; read_cmd(insb8, NULL); // read class subs
599 if( (cta_res[cta_lr-2]==0x90) && (fshow) &&
600 (cta_res[cta_lr-1]==0x00 || cta_res[cta_lr-1]==0x08) )
601 {
602 show_class(NULL, cta_res, cta_lr-2);
603 scls++;
604 }
605 }
606 }
607
608 insac[4]=0;
609 insa4[2]=0x02;
610 write_cmd(insa4, NULL); // select next provider
611 }
612
613 return 0;
614}
Note: See TracBrowser for help on using the repository browser.