[3181] | 1 | //FIXME Not checked on threadsafety yet; after checking please remove this line
|
---|
[8] | 2 | #include "globals.h"
|
---|
| 3 | #include "reader-common.h"
|
---|
| 4 |
|
---|
| 5 | struct via_date {
|
---|
| 6 | ushort day_s : 5;
|
---|
| 7 | ushort month_s : 4;
|
---|
| 8 | ushort year_s : 7;
|
---|
| 9 |
|
---|
| 10 | ushort day_e : 5;
|
---|
| 11 | ushort month_e : 4;
|
---|
| 12 | ushort year_e : 7;
|
---|
| 13 | };
|
---|
| 14 |
|
---|
| 15 | static void parse_via_date(const uchar *buf, struct via_date *vd, int fend)
|
---|
| 16 | {
|
---|
| 17 | ushort date;
|
---|
| 18 |
|
---|
| 19 | date = (buf[0]<<8) | buf[1];
|
---|
| 20 | vd->day_s = date & 0x1f;
|
---|
| 21 | vd->month_s = (date>>5) & 0x0f;
|
---|
| 22 | vd->year_s = (date>>9) & 0x7f;
|
---|
| 23 |
|
---|
| 24 | if( fend )
|
---|
| 25 | {
|
---|
| 26 | date = (buf[2]<<8) | buf[3];
|
---|
| 27 | vd->day_e = date & 0x1f;
|
---|
| 28 | vd->month_e = (date>>5) & 0x0f;
|
---|
| 29 | vd->year_e = (date>>9) & 0x7f;
|
---|
| 30 | }
|
---|
| 31 | }
|
---|
| 32 |
|
---|
[1926] | 33 | static void show_class(struct s_reader * reader, const char *p, const uchar *b, int l)
|
---|
[8] | 34 | {
|
---|
| 35 | int i, j;
|
---|
| 36 |
|
---|
| 37 | // b -> via date (4 bytes)
|
---|
| 38 | b+=4;
|
---|
| 39 | l-=4;
|
---|
| 40 |
|
---|
| 41 | j=l-1;
|
---|
| 42 | for (; j>=0; j--)
|
---|
| 43 | for (i=0; i<8; i++)
|
---|
| 44 | if (b[j] & (1 << (i&7)))
|
---|
| 45 | {
|
---|
| 46 | uchar cls;
|
---|
| 47 | struct via_date vd;
|
---|
| 48 | parse_via_date(b-4, &vd, 1);
|
---|
| 49 | cls=(l-(j+1))*8+i;
|
---|
| 50 | if (p)
|
---|
[2328] | 51 | cs_log("%sclass: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", p, cls,
|
---|
[8] | 52 | vd.year_s+1980, vd.month_s, vd.day_s,
|
---|
[11] | 53 | vd.year_e+1980, vd.month_e, vd.day_e);
|
---|
[8] | 54 | else
|
---|
[2328] | 55 | cs_ri_log(reader, "class: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", cls,
|
---|
[8] | 56 | vd.year_s+1980, vd.month_s, vd.day_s,
|
---|
[11] | 57 | vd.year_e+1980, vd.month_e, vd.day_e);
|
---|
[8] | 58 | }
|
---|
| 59 | }
|
---|
| 60 |
|
---|
[1926] | 61 | static void show_subs(struct s_reader * reader, const uchar *emm)
|
---|
[2328] | 62 | {
|
---|
[8] | 63 | // emm -> A9, A6, B6
|
---|
| 64 |
|
---|
| 65 | switch( emm[0] )
|
---|
| 66 | {
|
---|
| 67 | case 0xA9:
|
---|
[1926] | 68 | show_class(reader, "nano A9: ", emm+2, emm[1]);
|
---|
[8] | 69 | break;
|
---|
| 70 | /*
|
---|
| 71 | {
|
---|
| 72 | int i, j, byts;
|
---|
| 73 | const uchar *oemm;
|
---|
| 74 |
|
---|
| 75 | oemm = emm;
|
---|
| 76 | byts = emm[1]-4;
|
---|
| 77 | emm+=6;
|
---|
| 78 |
|
---|
| 79 | j=byts-1;
|
---|
| 80 | for( ; j>=0; j-- )
|
---|
| 81 | for( i=0; i<8; i++ )
|
---|
| 82 | if( emm[j] & (1 << (i&7)) )
|
---|
| 83 | {
|
---|
| 84 | uchar cls;
|
---|
| 85 | struct via_date vd;
|
---|
| 86 | parse_via_date(emm-4, &vd, 1);
|
---|
| 87 | cls=(byts-(j+1))*8+i;
|
---|
[32] | 88 | cs_log("%sclass %02X: expiry date: %02d/%02d/%04d - %02d/%02d/%04d",
|
---|
[2328] | 89 | fnano?"nano A9: ":"", cls,
|
---|
| 90 | vd.day_s, vd.month_s, vd.year_s+1980,
|
---|
[8] | 91 | vd.day_e, vd.month_e, vd.year_e+1980);
|
---|
| 92 | }
|
---|
| 93 | break;
|
---|
| 94 | }
|
---|
| 95 | */
|
---|
| 96 | case 0xA6:
|
---|
| 97 | {
|
---|
| 98 | char szGeo[256];
|
---|
| 99 |
|
---|
| 100 | memset(szGeo, 0, 256);
|
---|
[13] | 101 | strncpy(szGeo, (char *)emm+2, emm[1]);
|
---|
[1399] | 102 | cs_log("[viaccess-reader] nano A6: geo %s", szGeo);
|
---|
[8] | 103 | break;
|
---|
| 104 | }
|
---|
| 105 | case 0xB6:
|
---|
| 106 | {
|
---|
| 107 | uchar m; // modexp
|
---|
| 108 | struct via_date vd;
|
---|
| 109 |
|
---|
| 110 | m=emm[emm[1]+1];
|
---|
| 111 | parse_via_date(emm+2, &vd, 0);
|
---|
[2328] | 112 | cs_log("[viaccess-reader] nano B6: modexp %d%d%d%d%d%d: %02d/%02d/%04d", (m&0x20)?1:0,
|
---|
[8] | 113 | (m&0x10)?1:0,(m&0x08)?1:0,(m&0x04)?1:0,(m&0x02)?1:0,(m&0x01)?1:0,
|
---|
| 114 | vd.day_s, vd.month_s, vd.year_s+1980);
|
---|
| 115 | break;
|
---|
| 116 | }
|
---|
| 117 | }
|
---|
| 118 | }
|
---|
| 119 |
|
---|
[1926] | 120 | static int chk_prov(struct s_reader * reader, uchar *id, uchar keynr)
|
---|
[8] | 121 | {
|
---|
| 122 | int i, j, rc;
|
---|
[1926] | 123 | for (rc=i=0; (!rc) && (i<reader->nprov); i++)
|
---|
| 124 | if(!memcmp(&reader->prid[i][1], id, 3))
|
---|
[8] | 125 | for (j=0; (!rc) && (j<16); j++)
|
---|
[1926] | 126 | if (reader->availkeys[i][j]==keynr)
|
---|
[8] | 127 | rc=1;
|
---|
| 128 | return(rc);
|
---|
| 129 | }
|
---|
| 130 |
|
---|
[1926] | 131 | int viaccess_card_init(struct s_reader * reader, ATR newatr)
|
---|
[8] | 132 | {
|
---|
[1951] | 133 | get_atr;
|
---|
| 134 | def_resp;
|
---|
[8] | 135 | int i;
|
---|
| 136 | uchar buf[256];
|
---|
[3120] | 137 | uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
|
---|
| 138 | uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
|
---|
| 139 | uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
|
---|
| 140 | uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
|
---|
[8] | 141 |
|
---|
[3120] | 142 | static const uchar insFAC[] = { 0x87, 0x02, 0x00, 0x00, 0x03 }; // init FAC
|
---|
| 143 | static const uchar FacDat[] = { 0x00, 0x00, 0x28 };
|
---|
[8] | 144 |
|
---|
[2533] | 145 | if ((atr[0]!=0x3f) || (atr[1]!=0x77) || ((atr[2]!=0x18) && (atr[2]!=0x11) && (atr[2]!=0x19)) || (atr[9]!=0x68)) return ERROR;
|
---|
[12] | 146 |
|
---|
[8] | 147 | write_cmd(insFAC, FacDat);
|
---|
| 148 | if( !(cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0) )
|
---|
[1389] | 149 | return ERROR;
|
---|
[8] | 150 |
|
---|
| 151 | // switch((atr[atrsize-4]<<8)|atr[atrsize-3])
|
---|
| 152 | // {
|
---|
| 153 | // case 0x6268: ver="2.3"; break;
|
---|
| 154 | // case 0x6668: ver="2.4(?)"; break;
|
---|
| 155 | // case 0xa268:
|
---|
| 156 | // default: ver="unknown"; break;
|
---|
| 157 | // }
|
---|
[2328] | 158 |
|
---|
[1926] | 159 | reader->caid[0]=0x500;
|
---|
| 160 | memset(reader->prid, 0xff, sizeof(reader->prid));
|
---|
[8] | 161 | insac[2]=0xa4; write_cmd(insac, NULL); // request unique id
|
---|
[1951] | 162 | insb8[4]=0x07; write_cmd(insb8, NULL); // read unique id
|
---|
[1926] | 163 | memcpy(reader->hexserial, cta_res+2, 5);
|
---|
[1399] | 164 | // cs_log("[viaccess-reader] type: Viaccess, ver: %s serial: %llu", ver, b2ll(5, cta_res+2));
|
---|
[1926] | 165 | cs_ri_log(reader, "type: Viaccess (%sstandard atr), caid: %04X, serial: %llu",
|
---|
| 166 | atr[9]==0x68?"":"non-",reader->caid[0], b2ll(5, cta_res+2));
|
---|
[8] | 167 |
|
---|
| 168 | i=0;
|
---|
| 169 | insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0
|
---|
| 170 | buf[0]=0;
|
---|
| 171 | while((cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0))
|
---|
| 172 | {
|
---|
[1951] | 173 | insc0[4]=0x1a; write_cmd(insc0, NULL); // show provider properties
|
---|
[8] | 174 | cta_res[2]&=0xF0;
|
---|
[1926] | 175 | reader->prid[i][0]=0;
|
---|
| 176 | memcpy(&reader->prid[i][1], cta_res, 3);
|
---|
| 177 | memcpy(&reader->availkeys[i][0], cta_res+10, 16);
|
---|
| 178 | sprintf((char *)buf+strlen((char *)buf), ",%06lX", b2i(3, &reader->prid[i][1]));
|
---|
[1399] | 179 | //cs_log("[viaccess-reader] buf: %s", buf);
|
---|
[8] | 180 |
|
---|
| 181 | insac[2]=0xa5; write_cmd(insac, NULL); // request sa
|
---|
[1951] | 182 | insb8[4]=0x06; write_cmd(insb8, NULL); // read sa
|
---|
[1926] | 183 | memcpy(&reader->sa[i][0], cta_res+2, 4);
|
---|
[8] | 184 |
|
---|
| 185 | /*
|
---|
| 186 | insac[2]=0xa7; write_cmd(insac, NULL); // request name
|
---|
[1951] | 187 | insb8[4]=0x02; write_cmd(insb8, NULL); // read name nano + len
|
---|
[8] | 188 | l=cta_res[1];
|
---|
[1951] | 189 | insb8[4]=l; write_cmd(insb8, NULL); // read name
|
---|
[8] | 190 | cta_res[l]=0;
|
---|
[1399] | 191 | cs_log("[viaccess-reader] name: %s", cta_res);
|
---|
[8] | 192 | */
|
---|
| 193 |
|
---|
| 194 | insa4[2]=0x02;
|
---|
| 195 | write_cmd(insa4, NULL); // select next issuer
|
---|
| 196 | i++;
|
---|
| 197 | }
|
---|
[1926] | 198 | reader->nprov=i;
|
---|
| 199 | cs_ri_log(reader, "providers: %d (%s)", reader->nprov, buf+1);
|
---|
[89] | 200 |
|
---|
| 201 | /* init the maybe existing aes key */
|
---|
[1926] | 202 | aes_set_key((char *)reader->aes_key);
|
---|
[89] | 203 |
|
---|
[115] | 204 | /* disabling parental lock. assuming pin "0000" */
|
---|
| 205 | if (cfg->ulparent) {
|
---|
[3120] | 206 | static const uchar inDPL[] = {0xca, 0x24, 0x02, 0x00, 0x09};
|
---|
| 207 | static const uchar cmDPL[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F};
|
---|
[115] | 208 | write_cmd(inDPL,cmDPL);
|
---|
| 209 | if( !(cta_res[cta_lr-2]==0x90 && cta_res[cta_lr-1]==0) )
|
---|
[1399] | 210 | cs_log("[viaccess-reader] Can't disable parental lock. Wrong PIN? I assumed 0000!");
|
---|
[115] | 211 | else
|
---|
[1399] | 212 | cs_log("[viaccess-reader] Parental lock disabled");
|
---|
[115] | 213 | }
|
---|
| 214 |
|
---|
[1399] | 215 | cs_log("[viaccess-reader] ready for requests");
|
---|
[2069] | 216 | memset(&reader->last_geo, 0, sizeof(reader->last_geo));
|
---|
[1389] | 217 | return OK;
|
---|
[8] | 218 | }
|
---|
| 219 |
|
---|
[2328] | 220 | int viaccess_do_ecm(struct s_reader * reader, ECM_REQUEST *er)
|
---|
| 221 | {
|
---|
| 222 | def_resp;
|
---|
[3120] | 223 | static const unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id
|
---|
| 224 | unsigned char ins88[] = { 0xca,0x88,0x00,0x00,0x00 }; // set ecm
|
---|
| 225 | unsigned char insf8[] = { 0xca,0xf8,0x00,0x00,0x00 }; // set geographic info
|
---|
| 226 | static const unsigned char insc0[] = { 0xca,0xc0,0x00,0x00,0x12 }; // read dcw
|
---|
[2328] | 227 |
|
---|
| 228 | const uchar *ecm88Data=er->ecm+4; //XXX what is the 4th byte for ??
|
---|
| 229 | int ecm88Len=SCT_LEN(er->ecm)-4;
|
---|
[2722] | 230 | ulong provid=0;
|
---|
[2328] | 231 | int rc=0;
|
---|
| 232 | int hasD2 = 0;
|
---|
[2331] | 233 | int curEcm88len=0;
|
---|
| 234 | int nanoLen=0;
|
---|
| 235 | const uchar *nextEcm;
|
---|
| 236 | uchar keyToUse=0;
|
---|
[2328] | 237 | uchar DE04[256];
|
---|
[2722] | 238 | int D2KeyID=0;
|
---|
[2328] | 239 | memset(DE04, 0, sizeof(DE04)); //fix dorcel de04 bug
|
---|
[2331] | 240 |
|
---|
| 241 | nextEcm=ecm88Data;
|
---|
[2329] | 242 |
|
---|
[2331] | 243 | while (ecm88Len && !rc) {
|
---|
| 244 |
|
---|
[2925] | 245 | if(ecm88Data[0] ==0x00 && ecm88Data[1] == 0x00) {
|
---|
| 246 | // nano 0x00 and len 0x00 aren't valid ... something is obviously wrong with this ecm.
|
---|
| 247 | cs_log("[viaccess-reader] ECM: Invalid ECM structure. Rejecting");
|
---|
| 248 | return ERROR;
|
---|
| 249 | }
|
---|
| 250 |
|
---|
[2331] | 251 | // 80 33 nano 80 (ecm) + len (33)
|
---|
| 252 | if(ecm88Data[0]==0x80) { // nano 80, give ecm len
|
---|
| 253 | curEcm88len=ecm88Data[1];
|
---|
| 254 | nextEcm=ecm88Data+curEcm88len+2;
|
---|
| 255 | ecm88Data += 2;
|
---|
| 256 | ecm88Len -= 2;
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | if(!curEcm88len) { //there was no nano 80 -> simple ecm
|
---|
| 260 | curEcm88len=ecm88Len;
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 | // d2 02 0d 02 -> D2 nano, len 2, select the AES key to be used
|
---|
[2328] | 264 | if(ecm88Data[0]==0xd2) {
|
---|
[2925] | 265 | // use the d2 arguments to get the key # to be used
|
---|
[2328] | 266 | int len = ecm88Data[1] + 2;
|
---|
[2722] | 267 | D2KeyID=ecm88Data[3];
|
---|
[2328] | 268 | ecm88Data += len;
|
---|
| 269 | ecm88Len -= len;
|
---|
[2331] | 270 | curEcm88len -=len;
|
---|
[2328] | 271 | hasD2 = 1;
|
---|
| 272 | }
|
---|
| 273 | else
|
---|
| 274 | hasD2 = 0;
|
---|
| 275 |
|
---|
[2331] | 276 | // 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here
|
---|
| 277 | // 09 -> use key #9
|
---|
| 278 | // 05 67 00
|
---|
[2328] | 279 | if ((ecm88Data[0]==0x90 || ecm88Data[0]==0x40) && (ecm88Data[1]==0x03 || ecm88Data[1]==0x07 ) )
|
---|
| 280 | {
|
---|
| 281 | uchar ident[3], keynr;
|
---|
| 282 | //uchar buff[256]; // MAX_LEN
|
---|
| 283 | uchar *ecmf8Data=0;
|
---|
| 284 | int ecmf8Len=0;
|
---|
[2331] | 285 |
|
---|
| 286 | nanoLen=ecm88Data[1] + 2;
|
---|
| 287 |
|
---|
[2328] | 288 | memcpy (ident, &ecm88Data[2], sizeof(ident));
|
---|
| 289 | provid = b2i(3, ident);
|
---|
| 290 | ident[2]&=0xF0;
|
---|
[2796] | 291 |
|
---|
[2815] | 292 | if(hasD2 && reader->aes_list) {
|
---|
[2796] | 293 | // check that we have the AES key to decode the CW
|
---|
| 294 | // if not there is no need to send the ecm to the card
|
---|
| 295 | if(!aes_present(reader->aes_list, 0x500, (uint32) provid, D2KeyID))
|
---|
| 296 | return ERROR;
|
---|
| 297 | }
|
---|
| 298 |
|
---|
[2331] | 299 | keynr=ecm88Data[4]&0x0F;
|
---|
| 300 | // 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here
|
---|
| 301 | // 09 -> use key #9
|
---|
| 302 | if(nanoLen>5) {
|
---|
| 303 | keyToUse=ecm88Data[5];
|
---|
| 304 | keynr=keyToUse;
|
---|
| 305 | cs_debug("keyToUse = %d",keyToUse);
|
---|
| 306 | }
|
---|
| 307 |
|
---|
[2328] | 308 | if (!chk_prov(reader, ident, keynr))
|
---|
| 309 | {
|
---|
| 310 | cs_debug("[viaccess-reader] ECM: provider or key not found on card");
|
---|
[2955] | 311 | snprintf( er->msglog, MSGLOGSIZE, "provider(%02x%02x%02x) or key(%d) not found on card", ident[0],ident[1],ident[2], keynr );
|
---|
[2328] | 312 | return ERROR;
|
---|
| 313 | }
|
---|
[2331] | 314 |
|
---|
| 315 | ecm88Data+=nanoLen;
|
---|
| 316 | ecm88Len-=nanoLen;
|
---|
| 317 | curEcm88len-=nanoLen;
|
---|
[2328] | 318 |
|
---|
| 319 | // DE04
|
---|
| 320 | if (ecm88Data[0]==0xDE && ecm88Data[1]==0x04)
|
---|
| 321 | {
|
---|
| 322 | memcpy (DE04, &ecm88Data[0], 6);
|
---|
| 323 | ecm88Data+=6;
|
---|
| 324 | }
|
---|
| 325 | //
|
---|
| 326 |
|
---|
| 327 | if( reader->last_geo.provid != provid )
|
---|
| 328 | {
|
---|
| 329 | reader->last_geo.provid = provid;
|
---|
| 330 | reader->last_geo.geo_len = 0;
|
---|
| 331 | reader->last_geo.geo[0] = 0;
|
---|
| 332 | write_cmd(insa4, ident); // set provider
|
---|
| 333 | }
|
---|
| 334 |
|
---|
| 335 | while(ecm88Len>0 && ecm88Data[0]<0xA0)
|
---|
| 336 | {
|
---|
| 337 | int nanoLen=ecm88Data[1]+2;
|
---|
| 338 | if (!ecmf8Data)
|
---|
| 339 | ecmf8Data=(uchar *)ecm88Data;
|
---|
| 340 | ecmf8Len+=nanoLen;
|
---|
| 341 | ecm88Len-=nanoLen;
|
---|
[2331] | 342 | curEcm88len-=nanoLen;
|
---|
[2328] | 343 | ecm88Data+=nanoLen;
|
---|
| 344 | }
|
---|
| 345 | if(ecmf8Len)
|
---|
| 346 | {
|
---|
| 347 | if( reader->last_geo.geo_len!=ecmf8Len ||
|
---|
| 348 | memcmp(reader->last_geo.geo, ecmf8Data, reader->last_geo.geo_len))
|
---|
| 349 | {
|
---|
| 350 | memcpy(reader->last_geo.geo, ecmf8Data, ecmf8Len);
|
---|
| 351 | reader->last_geo.geo_len= ecmf8Len;
|
---|
| 352 | insf8[3]=keynr;
|
---|
| 353 | insf8[4]=ecmf8Len;
|
---|
| 354 | write_cmd(insf8, ecmf8Data);
|
---|
| 355 | }
|
---|
| 356 | }
|
---|
| 357 | ins88[2]=ecmf8Len?1:0;
|
---|
| 358 | ins88[3]=keynr;
|
---|
[2331] | 359 | ins88[4]= curEcm88len;
|
---|
[2930] | 360 | //
|
---|
| 361 | // we should check the nano to make sure the ecm is valid
|
---|
| 362 | // we should look for at least 1 E3 nano, 1 EA nano and the F0 signature nano
|
---|
| 363 | //
|
---|
[2328] | 364 | // DE04
|
---|
| 365 | if (DE04[0]==0xDE)
|
---|
| 366 | {
|
---|
| 367 | memcpy(DE04+6, (uchar *)ecm88Data, curEcm88len-6);
|
---|
| 368 | write_cmd(ins88, DE04); // request dcw
|
---|
| 369 | }
|
---|
| 370 | else
|
---|
| 371 | {
|
---|
| 372 | write_cmd(ins88, (uchar *)ecm88Data); // request dcw
|
---|
| 373 | }
|
---|
| 374 | //
|
---|
[2331] | 375 | write_cmd(insc0, NULL); // read dcw
|
---|
[2328] | 376 | switch(cta_res[0])
|
---|
| 377 | {
|
---|
| 378 | case 0xe8: // even
|
---|
| 379 | if(cta_res[1]==8) { memcpy(er->cw,cta_res+2,8); rc=1; }
|
---|
| 380 | break;
|
---|
| 381 | case 0xe9: // odd
|
---|
| 382 | if(cta_res[1]==8) { memcpy(er->cw+8,cta_res+2,8); rc=1; }
|
---|
| 383 | break;
|
---|
| 384 | case 0xea: // complete
|
---|
| 385 | if(cta_res[1]==16) { memcpy(er->cw,cta_res+2,16); rc=1; }
|
---|
| 386 | break;
|
---|
[2331] | 387 | default :
|
---|
| 388 | ecm88Data=nextEcm;
|
---|
| 389 | ecm88Len-=curEcm88len;
|
---|
| 390 | cs_debug("[viaccess-reader] ECM: key to use is not the current one, trying next ECM");
|
---|
[2955] | 391 | snprintf( er->msglog, MSGLOGSIZE, "key to use is not the current one, trying next ECM" );
|
---|
[2328] | 392 | }
|
---|
| 393 | }
|
---|
[2396] | 394 | else {
|
---|
| 395 | ecm88Data=nextEcm;
|
---|
| 396 | ecm88Len-=curEcm88len;
|
---|
| 397 | cs_debug("[viaccess-reader] ECM: Unknown ECM type");
|
---|
[2955] | 398 | snprintf( er->msglog, MSGLOGSIZE, "Unknown ECM type" );
|
---|
[2396] | 399 | }
|
---|
[2331] | 400 | }
|
---|
[2328] | 401 |
|
---|
| 402 | if (hasD2) {
|
---|
[2722] | 403 | if(reader->aes_list) {
|
---|
[2729] | 404 | cs_debug("Decoding CW : using AES key id %d for provider %06x",D2KeyID,provid);
|
---|
| 405 | rc=aes_decrypt_from_list(reader->aes_list,0x500, (uint32) provid, D2KeyID,er->cw, 16);
|
---|
[2955] | 406 | if( rc == 0 )
|
---|
| 407 | snprintf( er->msglog, MSGLOGSIZE, "AES Decrypt : key id %d not found for CAID %04X , provider %06lx", D2KeyID, 0x500, provid );
|
---|
[2722] | 408 | }
|
---|
| 409 | else
|
---|
| 410 | aes_decrypt(er->cw, 16);
|
---|
[2328] | 411 | }
|
---|
[2331] | 412 |
|
---|
[2328] | 413 | return(rc?OK:ERROR);
|
---|
| 414 | }
|
---|
| 415 |
|
---|
[2331] | 416 | int viaccess_get_emm_type(EMM_PACKET *ep, struct s_reader * rdr)
|
---|
| 417 | {
|
---|
| 418 | cs_debug_mask(D_EMM, "Entered viaccess_get_emm_type ep->emm[0]=%02x",ep->emm[0]);
|
---|
| 419 |
|
---|
| 420 | switch (ep->emm[0]) {
|
---|
[2755] | 421 | case 0x88:
|
---|
[2331] | 422 | ep->type=UNIQUE;
|
---|
| 423 | memset(ep->hexserial, 0, 8);
|
---|
| 424 | memcpy(ep->hexserial, ep->emm + 3, 3);
|
---|
| 425 | cs_debug_mask(D_EMM, "VIACCESS EMM: UNIQUE");
|
---|
| 426 | return(!memcmp(rdr->hexserial + 1, ep->hexserial, 4));
|
---|
| 427 |
|
---|
[2755] | 428 | case 0x8A:
|
---|
| 429 | case 0x8B:
|
---|
[2331] | 430 | ep->type=GLOBAL;
|
---|
| 431 | cs_debug_mask(D_EMM, "VIACCESS EMM: GLOBAL");
|
---|
| 432 | return TRUE;
|
---|
| 433 |
|
---|
[2755] | 434 | case 0x8C:
|
---|
| 435 | case 0x8D:
|
---|
| 436 | ep->type=SHARED;
|
---|
| 437 | cs_debug_mask(D_EMM, "VIACCESS EMM: SHARED (part)");
|
---|
| 438 | return FALSE;
|
---|
| 439 |
|
---|
| 440 | case 0x8E:
|
---|
| 441 | ep->type=SHARED;
|
---|
| 442 | memset(ep->hexserial, 0, 8);
|
---|
| 443 | memcpy(ep->hexserial, ep->emm + 3, 3);
|
---|
| 444 | cs_debug_mask(D_EMM, "VIACCESS EMM: SHARED");
|
---|
| 445 | return(!memcmp(&rdr->sa[0][0], ep->hexserial, 3));
|
---|
| 446 |
|
---|
[2331] | 447 | default:
|
---|
| 448 | ep->type = UNKNOWN;
|
---|
| 449 | cs_debug_mask(D_EMM, "VIACCESS EMM: UNKNOWN");
|
---|
| 450 | return TRUE;
|
---|
| 451 | }
|
---|
| 452 | }
|
---|
| 453 |
|
---|
| 454 | void viaccess_get_emm_filter(struct s_reader * rdr, uchar *filter)
|
---|
| 455 | {
|
---|
| 456 | filter[0]=0xFF;
|
---|
[2755] | 457 | filter[1]=3;
|
---|
[2331] | 458 |
|
---|
| 459 | filter[2]=GLOBAL;
|
---|
| 460 | filter[3]=0;
|
---|
| 461 |
|
---|
| 462 | filter[4+0] = 0x8D;
|
---|
[2727] | 463 | filter[4+0+16] = 0xFE;
|
---|
| 464 | //filter[4+6] = 0xA0; // FIXME: dummy, flood client with EMM's
|
---|
| 465 | //filter[4+6+16] = 0xF0;
|
---|
[2331] | 466 |
|
---|
| 467 |
|
---|
| 468 | filter[36]=SHARED;
|
---|
| 469 | filter[37]=0;
|
---|
| 470 |
|
---|
| 471 | filter[38+0] = 0x8E;
|
---|
| 472 | filter[38+0+16] = 0xFF;
|
---|
| 473 | memcpy(filter+38+1, &rdr->sa[0][0], 3);
|
---|
| 474 | memset(filter+38+1+16, 0xFF, 3);
|
---|
| 475 |
|
---|
| 476 |
|
---|
| 477 | filter[70]=UNIQUE;
|
---|
| 478 | filter[71]=0;
|
---|
| 479 |
|
---|
[2755] | 480 | filter[72+0] = 0x88;
|
---|
[2331] | 481 | filter[72+0+16] = 0xFF;
|
---|
| 482 | memcpy(filter+72+1, rdr->hexserial + 1, 4);
|
---|
| 483 | memset(filter+72+1+16, 0xFF, 4);
|
---|
| 484 |
|
---|
| 485 | return;
|
---|
| 486 | }
|
---|
| 487 |
|
---|
[1926] | 488 | int viaccess_do_emm(struct s_reader * reader, EMM_PACKET *ep)
|
---|
[8] | 489 | {
|
---|
[1951] | 490 | def_resp;
|
---|
[3120] | 491 | static const unsigned char insa4[] = { 0xca,0xa4,0x04,0x00,0x03 }; // set provider id
|
---|
| 492 | unsigned char insf0[] = { 0xca,0xf0,0x00,0x01,0x22 }; // set adf
|
---|
| 493 | unsigned char insf4[] = { 0xca,0xf4,0x00,0x01,0x00 }; // set adf, encrypted
|
---|
| 494 | unsigned char ins18[] = { 0xca,0x18,0x01,0x01,0x00 }; // set subscription
|
---|
| 495 | unsigned char ins1c[] = { 0xca,0x1c,0x01,0x01,0x00 }; // set subscription, encrypted
|
---|
| 496 | static const unsigned char insc8[] = { 0xca,0xc8,0x00,0x00,0x02 }; // read extended status
|
---|
| 497 | static const unsigned char insc8Data[] = { 0x00,0x00 }; // data for read extended status
|
---|
[8] | 498 |
|
---|
| 499 | int emmLen=SCT_LEN(ep->emm)-7;
|
---|
| 500 | int rc=0;
|
---|
| 501 |
|
---|
[13] | 502 | ///cs_dump(ep->emm, emmLen+7, "RECEIVED EMM VIACCESS");
|
---|
[8] | 503 |
|
---|
[13] | 504 | int emmUpToEnd;
|
---|
| 505 | uchar *emmParsed = ep->emm+7;
|
---|
| 506 | int provider_ok = 0;
|
---|
| 507 | uchar keynr = 0;
|
---|
| 508 | int ins18Len = 0;
|
---|
| 509 | uchar ins18Data[512];
|
---|
| 510 | uchar insData[512];
|
---|
| 511 | uchar *nano81Data = 0;
|
---|
| 512 | uchar *nano91Data = 0;
|
---|
| 513 | uchar *nano92Data = 0;
|
---|
| 514 | uchar *nano9EData = 0;
|
---|
| 515 | uchar *nanoF0Data = 0;
|
---|
[8] | 516 |
|
---|
[13] | 517 | for (emmUpToEnd=emmLen; (emmParsed[1] != 0) && (emmUpToEnd > 0); emmUpToEnd -= (2 + emmParsed[1]), emmParsed += (2 + emmParsed[1])) {
|
---|
| 518 | ///cs_dump (emmParsed, emmParsed[1] + 2, "NANO");
|
---|
[8] | 519 |
|
---|
[13] | 520 | if (emmParsed[0]==0x90 && emmParsed[1]==0x03) {
|
---|
| 521 | /* identification of the service operator */
|
---|
[8] | 522 |
|
---|
[13] | 523 | uchar soid[3], ident[3], i;
|
---|
| 524 |
|
---|
| 525 | for (i=0; i<3; i++) {
|
---|
| 526 | soid[i]=ident[i]=emmParsed[2+i];
|
---|
| 527 | }
|
---|
| 528 | ident[2]&=0xF0;
|
---|
| 529 | keynr=soid[2]&0x0F;
|
---|
[1926] | 530 | if (chk_prov(reader, ident, keynr)) {
|
---|
[13] | 531 | provider_ok = 1;
|
---|
| 532 | } else {
|
---|
[1399] | 533 | cs_debug("[viaccess-reader] EMM: provider or key not found on card (%x, %x)", ident, keynr);
|
---|
[2955] | 534 | cs_log("[viaccess-reader] EMM: provider or key not found on card (%x, %x)", ident, keynr);
|
---|
[1389] | 535 | return ERROR;
|
---|
[13] | 536 | }
|
---|
| 537 |
|
---|
[2323] | 538 | // as we are maybe changing the used provider, clear the cache, so the next ecm will re-select the correct one
|
---|
[2208] | 539 | memset(&reader->last_geo, 0, sizeof(reader->last_geo));
|
---|
| 540 |
|
---|
[13] | 541 | // set provider
|
---|
[2328] | 542 | write_cmd(insa4, soid);
|
---|
[13] | 543 | if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
|
---|
| 544 | cs_dump(insa4, 5, "set provider cmd:");
|
---|
| 545 | cs_dump(soid, 3, "set provider data:");
|
---|
[1399] | 546 | cs_log("[viaccess-reader] update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
[1389] | 547 | return ERROR;
|
---|
[13] | 548 | }
|
---|
| 549 | } else if (emmParsed[0]==0x9e && emmParsed[1]==0x20) {
|
---|
| 550 | /* adf */
|
---|
| 551 |
|
---|
| 552 | if (!nano91Data) {
|
---|
| 553 | /* adf is not crypted, so test it */
|
---|
| 554 |
|
---|
| 555 | uchar custwp;
|
---|
| 556 | uchar *afd;
|
---|
| 557 |
|
---|
[1926] | 558 | custwp=reader->sa[0][3];
|
---|
[13] | 559 | afd=(uchar*)emmParsed+2;
|
---|
| 560 |
|
---|
| 561 | if( afd[31-custwp/8] & (1 << (custwp & 7)) )
|
---|
[1926] | 562 | cs_debug("[viaccess-reader] emm for our card %08X", b2i(4, &reader->sa[0][0]));
|
---|
[13] | 563 | else
|
---|
[1389] | 564 | return SKIPPED;
|
---|
[13] | 565 | }
|
---|
| 566 |
|
---|
| 567 | // memorize
|
---|
| 568 | nano9EData = emmParsed;
|
---|
| 569 |
|
---|
[26] | 570 | } else if (emmParsed[0]==0x81) {
|
---|
[13] | 571 | nano81Data = emmParsed;
|
---|
| 572 | } else if (emmParsed[0]==0x91 && emmParsed[1]==0x08) {
|
---|
| 573 | nano91Data = emmParsed;
|
---|
| 574 | } else if (emmParsed[0]==0x92 && emmParsed[1]==0x08) {
|
---|
| 575 | nano92Data = emmParsed;
|
---|
| 576 | } else if (emmParsed[0]==0xF0 && emmParsed[1]==0x08) {
|
---|
| 577 | nanoF0Data = emmParsed;
|
---|
| 578 | } else if (emmParsed[0]==0x1D && emmParsed[0]==0x01 && emmParsed[0]==0x01) {
|
---|
| 579 | /* from cccam... skip it... */
|
---|
| 580 | } else {
|
---|
| 581 | /* other nanos */
|
---|
[1926] | 582 | show_subs(reader, emmParsed);
|
---|
[2328] | 583 |
|
---|
[13] | 584 | memcpy(ins18Data+ins18Len, emmParsed, emmParsed[1] + 2);
|
---|
| 585 | ins18Len += emmParsed [1] + 2;
|
---|
[8] | 586 | }
|
---|
[13] | 587 | }
|
---|
[8] | 588 |
|
---|
[13] | 589 | if (!provider_ok) {
|
---|
[1399] | 590 | cs_debug("[viaccess-reader] provider not found in emm, continue anyway");
|
---|
[13] | 591 | // force key to 1...
|
---|
| 592 | keynr = 1;
|
---|
[1389] | 593 | ///return ERROR;
|
---|
[13] | 594 | }
|
---|
| 595 |
|
---|
[26] | 596 | if (!nanoF0Data) {
|
---|
| 597 | cs_dump(ep->emm, ep->l, "can't find 0xf0 in emm...");
|
---|
[1389] | 598 | return ERROR; // error
|
---|
[26] | 599 | }
|
---|
| 600 |
|
---|
[98] | 601 | if (nano9EData) {
|
---|
| 602 | if (!nano91Data) {
|
---|
| 603 | // set adf
|
---|
| 604 | insf0[3] = keynr; // key
|
---|
[2328] | 605 | write_cmd(insf0, nano9EData);
|
---|
[98] | 606 | if( cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
|
---|
| 607 | cs_dump(insf0, 5, "set adf cmd:");
|
---|
| 608 | cs_dump(nano9EData, 0x22, "set adf data:");
|
---|
[1399] | 609 | cs_log("[viaccess-reader] update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
[1389] | 610 | return ERROR;
|
---|
[98] | 611 | }
|
---|
| 612 | } else {
|
---|
| 613 | // set adf crypte
|
---|
| 614 | insf4[3] = keynr; // key
|
---|
| 615 | insf4[4] = nano91Data[1] + 2 + nano9EData[1] + 2;
|
---|
| 616 | memcpy (insData, nano91Data, nano91Data[1] + 2);
|
---|
| 617 | memcpy (insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2);
|
---|
[2328] | 618 | write_cmd(insf4, insData);
|
---|
[98] | 619 | if(( cta_res[cta_lr-2]!=0x90 && cta_res[cta_lr-2]!=0x91) || cta_res[cta_lr-1]!=0x00 ) {
|
---|
| 620 | cs_dump(insf4, 5, "set adf encrypted cmd:");
|
---|
| 621 | cs_dump(insData, insf4[4], "set adf encrypted data:");
|
---|
[1399] | 622 | cs_log("[viaccess-reader] update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
[1389] | 623 | return ERROR;
|
---|
[98] | 624 | }
|
---|
[8] | 625 | }
|
---|
[13] | 626 | }
|
---|
[8] | 627 |
|
---|
[13] | 628 | if (!nano92Data) {
|
---|
| 629 | // send subscription
|
---|
| 630 | ins18[4] = ins18Len + nanoF0Data[1] + 2;
|
---|
| 631 | memcpy (insData, ins18Data, ins18Len);
|
---|
| 632 | memcpy (insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2);
|
---|
| 633 | write_cmd(ins18, insData);
|
---|
[2760] | 634 | if( (cta_res[cta_lr-2]==0x90 || cta_res[cta_lr-2]==0x91) && cta_res[cta_lr-1]==0x00 ) {
|
---|
[1399] | 635 | cs_debug("[viaccess-reader] update successfully written");
|
---|
[8] | 636 | rc=1; // written
|
---|
| 637 | } else {
|
---|
| 638 | cs_dump(ins18, 5, "set subscription cmd:");
|
---|
[13] | 639 | cs_dump(insData, ins18[4], "set subscription data:");
|
---|
[1399] | 640 | cs_log("[viaccess-reader] update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
[8] | 641 | }
|
---|
[2328] | 642 |
|
---|
[13] | 643 | } else {
|
---|
| 644 | // send subscription encrypted
|
---|
[26] | 645 |
|
---|
| 646 | if (!nano81Data) {
|
---|
| 647 | cs_dump(ep->emm, ep->l, "0x92 found, but can't find 0x81 in emm...");
|
---|
[1389] | 648 | return ERROR; // error
|
---|
[26] | 649 | }
|
---|
| 650 |
|
---|
[13] | 651 | ins1c[3] = keynr; // key
|
---|
| 652 | ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2;
|
---|
| 653 | memcpy (insData, nano92Data, nano92Data[1] + 2);
|
---|
| 654 | memcpy (insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2);
|
---|
| 655 | memcpy (insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2);
|
---|
[2328] | 656 | write_cmd(ins1c, insData);
|
---|
[2760] | 657 | if( (cta_res[cta_lr-2]!=0x90 && cta_res[cta_lr-2]!=0x91) || cta_res[cta_lr-1]!=0x00 ) {
|
---|
[13] | 658 | /* maybe a 2nd level status, so read it */
|
---|
| 659 | ///cs_dump(ins1c, 5, "set subscription encrypted cmd:");
|
---|
| 660 | ///cs_dump(insData, ins1c[4], "set subscription encrypted data:");
|
---|
[1399] | 661 | ///cs_log("[viaccess-reader] update error: %02X %02X", cta_res[cta_lr-2], cta_res[cta_lr-1]);
|
---|
[13] | 662 |
|
---|
[2328] | 663 | write_cmd(insc8, insc8Data);
|
---|
[13] | 664 | if( cta_res[0] != 0x00 || cta_res[1] != 00 || cta_res[cta_lr-2]!=0x90 || cta_res[cta_lr-1]!=0x00 ) {
|
---|
[27] | 665 | ///cs_dump(cta_res, cta_lr, "extended status error:");
|
---|
[1389] | 666 | return ERROR;
|
---|
[13] | 667 | } else {
|
---|
[1399] | 668 | cs_debug("[viaccess-reader] update successfully written (with extended status OK)");
|
---|
[13] | 669 | rc=1; // written
|
---|
| 670 | }
|
---|
| 671 | } else {
|
---|
[1399] | 672 | cs_debug("[viaccess-reader] update successfully written");
|
---|
[13] | 673 | rc=1; // written
|
---|
| 674 | }
|
---|
[8] | 675 | }
|
---|
[13] | 676 |
|
---|
[8] | 677 | /*
|
---|
| 678 | Sub Main()
|
---|
| 679 | Sc.Write("CA A4 04 00 03")
|
---|
| 680 | RX
|
---|
| 681 | Sc.Write("02 07 11")
|
---|
| 682 | RX
|
---|
| 683 | Sc.Write("CA F0 00 01 22")
|
---|
| 684 | RX
|
---|
| 685 | Sc.Write("9E 20")
|
---|
| 686 | Sc.Write("10 10 08 8A 80 00 04 00 10 10 26 E8 54 80 1E 80")
|
---|
| 687 | Sc.Write("00 01 00 00 00 00 00 50 00 00 80 02 22 00 08 50")
|
---|
| 688 | RX
|
---|
| 689 | Sc.Write("CA 18 01 01 11")
|
---|
| 690 | RX
|
---|
| 691 | Sc.Write("A9 05 34 DE 34 FF 80")
|
---|
| 692 | Sc.Write("F0 08 1A 3E AF B5 2B EE E3 3B")
|
---|
| 693 | RX
|
---|
| 694 |
|
---|
| 695 | End Sub
|
---|
| 696 | */
|
---|
| 697 | return rc;
|
---|
| 698 | }
|
---|
| 699 |
|
---|
[1926] | 700 | int viaccess_card_info(struct s_reader * reader)
|
---|
[8] | 701 | {
|
---|
[1951] | 702 | def_resp;
|
---|
[8] | 703 | int i, l, scls, show_cls;
|
---|
[3120] | 704 | uchar insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
|
---|
| 705 | uchar insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
|
---|
| 706 | uchar insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
|
---|
| 707 | uchar insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
|
---|
| 708 | static const uchar ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin
|
---|
[8] | 709 |
|
---|
[3120] | 710 | static const uchar cls[] = { 0x00, 0x21, 0xff, 0x9f};
|
---|
| 711 | static const uchar pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
|
---|
[8] | 712 |
|
---|
[1926] | 713 | show_cls=reader->show_cls;
|
---|
[2069] | 714 | memset(&reader->last_geo, 0, sizeof(reader->last_geo));
|
---|
[8] | 715 |
|
---|
[2328] | 716 | cs_log("[viaccess-reader] card detected");
|
---|
| 717 |
|
---|
[8] | 718 | // set pin
|
---|
| 719 | write_cmd(ins24, pin);
|
---|
| 720 |
|
---|
| 721 | insac[2]=0xa4; write_cmd(insac, NULL); // request unique id
|
---|
[1951] | 722 | insb8[4]=0x07; write_cmd(insb8, NULL); // read unique id
|
---|
[1399] | 723 | cs_log("[viaccess-reader] serial: %llu", b2ll(5, cta_res+2));
|
---|
[8] | 724 |
|
---|
| 725 | scls=0;
|
---|
| 726 | insa4[2]=0x00; write_cmd(insa4, NULL); // select issuer 0
|
---|
| 727 | for (i=1; (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0); i++)
|
---|
| 728 | {
|
---|
| 729 | ulong l_provid, l_sa;
|
---|
| 730 | uchar l_name[64];
|
---|
[1951] | 731 | insc0[4]=0x1a; write_cmd(insc0, NULL); // show provider properties
|
---|
[8] | 732 | cta_res[2]&=0xF0;
|
---|
| 733 | l_provid=b2i(3, cta_res);
|
---|
| 734 |
|
---|
| 735 | insac[2]=0xa5; write_cmd(insac, NULL); // request sa
|
---|
[1951] | 736 | insb8[4]=0x06; write_cmd(insb8, NULL); // read sa
|
---|
[8] | 737 | l_sa=b2i(4, cta_res+2);
|
---|
| 738 |
|
---|
| 739 | insac[2]=0xa7; write_cmd(insac, NULL); // request name
|
---|
[1951] | 740 | insb8[4]=0x02; write_cmd(insb8, NULL); // read name nano + len
|
---|
[8] | 741 | l=cta_res[1];
|
---|
[1951] | 742 | insb8[4]=l; write_cmd(insb8, NULL); // read name
|
---|
[8] | 743 | cta_res[l]=0;
|
---|
[13] | 744 | trim((char *)cta_res);
|
---|
[8] | 745 | if (cta_res[0])
|
---|
[13] | 746 | snprintf((char *)l_name, sizeof(l_name), ", name: %s", cta_res);
|
---|
[8] | 747 | else
|
---|
| 748 | l_name[0]=0;
|
---|
| 749 |
|
---|
| 750 | // read GEO
|
---|
| 751 | insac[2]=0xa6; write_cmd(insac, NULL); // request GEO
|
---|
[1951] | 752 | insb8[4]=0x02; write_cmd(insb8, NULL); // read GEO nano + len
|
---|
[8] | 753 | l=cta_res[1];
|
---|
[1951] | 754 | insb8[4]=l; write_cmd(insb8, NULL); // read geo
|
---|
[1926] | 755 | cs_ri_log(reader, "provider: %d, id: %06X%s, sa: %08X, geo: %s",
|
---|
[8] | 756 | i, l_provid, l_name, l_sa, (l<4) ? "empty" : cs_hexdump(1, cta_res, l));
|
---|
| 757 |
|
---|
| 758 | // read classes subscription
|
---|
| 759 | insac[2]=0xa9; insac[4]=4;
|
---|
| 760 | write_cmd(insac, cls); // request class subs
|
---|
| 761 | scls=0;
|
---|
| 762 | while( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
|
---|
| 763 | {
|
---|
[1951] | 764 | insb8[4]=0x02; write_cmd(insb8, NULL); // read class subs nano + len
|
---|
[8] | 765 | if( (cta_res[cta_lr-2]==0x90) && (cta_res[cta_lr-1]==0) )
|
---|
| 766 | {
|
---|
| 767 | int fshow;
|
---|
| 768 | l=cta_res[1];
|
---|
| 769 | //fshow=(client[cs_idx].dbglvl==D_DUMP)?1:(scls < show_cls)?1:0;
|
---|
| 770 | fshow=(scls<show_cls);
|
---|
[1951] | 771 | insb8[4]=l; write_cmd(insb8, NULL); // read class subs
|
---|
[2328] | 772 | if( (cta_res[cta_lr-2]==0x90) && (fshow) &&
|
---|
[8] | 773 | (cta_res[cta_lr-1]==0x00 || cta_res[cta_lr-1]==0x08) )
|
---|
| 774 | {
|
---|
[1926] | 775 | show_class(reader, NULL, cta_res, cta_lr-2);
|
---|
[8] | 776 | scls++;
|
---|
| 777 | }
|
---|
| 778 | }
|
---|
| 779 | }
|
---|
| 780 |
|
---|
| 781 | insac[4]=0;
|
---|
[2328] | 782 | insa4[2]=0x02;
|
---|
[8] | 783 | write_cmd(insa4, NULL); // select next provider
|
---|
| 784 | }
|
---|
[1389] | 785 | //return ERROR;
|
---|
| 786 | return OK;
|
---|
[8] | 787 | }
|
---|
[3168] | 788 |
|
---|
| 789 | void reader_viaccess(struct s_cardsystem *ph)
|
---|
| 790 | {
|
---|
| 791 | ph->do_emm=viaccess_do_emm;
|
---|
| 792 | ph->do_ecm=viaccess_do_ecm;
|
---|
| 793 | ph->card_info=viaccess_card_info;
|
---|
| 794 | ph->card_init=viaccess_card_init;
|
---|
| 795 | ph->get_emm_type=viaccess_get_emm_type;
|
---|
| 796 | ph->caids[0]=0x05;
|
---|
| 797 | }
|
---|