source: trunk/reader-videoguard2.c @ 9568

Last change on this file since 9568 was 9568, checked in by blaky, 5 years ago

added Patch from pfanne
to get more feedback from other VG2 Card Owners
see: http://www.streamboard.tv/wbb2/thread.php?threadid=40471

-Added some info on entitlements page's
-Fix ins4c longer than 9 byte (like v14)
-Fix wrong order of some ins at boot
-Added possibility to send ins2e06 (like italian stb*)
-Added (experimental!) unlock parental control (it reads the pin from card and sends it with ins2e04, we don't need to write it in the config) set it on config>global

  • seems that the actual value for sky_it is BFFFFFFF

if your provider uses it, add ins2e06 = BFFFFFFF (or similar) in config or webif

  • Property svn:eol-style set to LF
File size: 31.0 KB
Line 
1#include "globals.h"
2#ifdef READER_VIDEOGUARD
3#include "cscrypt/md5.h"
4#include "oscam-work.h"
5#include "reader-common.h"
6#include "reader-videoguard-common.h"
7
8static void dimeno_PostProcess_Decrypt(struct s_reader *reader, unsigned char *rxbuff, unsigned char *cw)
9{
10    struct videoguard_data *csystem_data = reader->csystem_data;
11    unsigned char tag, len, len2;
12    bool valid_0x55 = 0;
13    unsigned char *body;
14    unsigned char buffer[0x10];
15    int32_t a = 0x13;
16    len2 = rxbuff[4];
17    while(a < len2 + 5 - 9)  //  +5 for 5 ins bytes, -9 (body=8 len=1) to prevent memcpy(buffer+8,body,8) from reading past rxbuff
18    {
19        tag = rxbuff[a];
20        len = rxbuff[a + 1];
21        body = rxbuff + a + 2;
22        switch(tag)
23        {
24        case 0x55:
25        {
26            if(body[0] == 0x84)     //Tag 0x56 has valid data...
27            {
28                valid_0x55 = 1;
29            }
30        }
31        break;
32        case 0x56:
33        {
34            memcpy(buffer + 8, body, 8);
35        }
36        break;
37        }
38        a += len + 2;
39    }
40    if(valid_0x55)
41    {
42        memcpy(buffer, rxbuff + 5, 8);
43        AES_decrypt(buffer, buffer, &(csystem_data->astrokey));
44        memcpy(cw + 0, buffer, 8);  // copy calculated CW in right place
45    }
46}
47
48static void do_post_dw_hash(struct s_reader *reader, unsigned char *cw, const unsigned char *ecm_header_data)
49{
50    int32_t i, ecmi, ecm_header_count;
51    unsigned char buffer[0x85]; //original 0x80 but with 0x7D mask applied +8 bytes cw it was still to small
52    unsigned char md5tmp[MD5_DIGEST_LENGTH];
53    static const uint16_t Hash3[] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0xF861, 0xCB52};
54    static const unsigned char Hash4[] = {0x0B, 0x04, 0x07, 0x08, 0x05, 0x09, 0x0B, 0x0A, 0x07, 0x02, 0x0A, 0x05, 0x04, 0x08, 0x0D, 0x0F};
55    static const uint16_t NdTabB001[0x15][0x20] =
56    {
57        {
58            0xEAF1, 0x0237, 0x29D0, 0xBAD2, 0xE9D3, 0x8BAE, 0x2D6D, 0xCD1B,
59            0x538D, 0xDE6B, 0xA634, 0xF81A, 0x18B5, 0x5087, 0x14EA, 0x672E,
60            0xF0FC, 0x055E, 0x62E5, 0xB78F, 0x5D09, 0x0003, 0xE4E8, 0x2DCE,
61            0x6BE0, 0xAC4E, 0xF485, 0x6967, 0xF28C, 0x97A0, 0x01EF, 0x0100
62        },
63        {
64            0xC539, 0xF5B9, 0x9099, 0x013A, 0xD4B9, 0x6AB5, 0xEA67, 0x7EB4,
65            0x6C30, 0x4BF0, 0xB810, 0xB0B5, 0xB76D, 0xA751, 0x1AE7, 0x14CA,
66            0x4F4F, 0x1586, 0x2608, 0x10B1, 0xE7E1, 0x48BE, 0x7DDD, 0x5ECB,
67            0xCFBF, 0x323B, 0x8B31, 0xB131, 0x0F1A, 0x664B, 0x0140, 0x0100
68        },
69        {
70            0x3C7D, 0xBDC4, 0xFEC7, 0x26A6, 0xB0A0, 0x6E55, 0xF710, 0xF9BF,
71            0x0023, 0xE81F, 0x41CA, 0xBE32, 0xB461, 0xE92D, 0xF1AF, 0x409F,
72            0xFC85, 0xFE5B, 0x7FCE, 0x17F5, 0x01AB, 0x4A46, 0xEB05, 0xA251,
73            0xDC6F, 0xF0C0, 0x10F0, 0x1D51, 0xEFAA, 0xE9BF, 0x0100, 0x0100
74        },
75        {
76            0x1819, 0x0CAA, 0x9067, 0x607A, 0x7576, 0x1CBC, 0xE51D, 0xBF77,
77            0x7EC6, 0x839E, 0xB695, 0xF096, 0xDC10, 0xCB69, 0x4654, 0x8E68,
78            0xD62D, 0x4F1A, 0x4227, 0x92AC, 0x9064, 0x6BD1, 0x1E75, 0x2747,
79            0x00DA, 0xA6A6, 0x6CF1, 0xD151, 0xBE56, 0x3E33, 0x0128, 0x0100
80        },
81        {
82            0x4091, 0x09ED, 0xD494, 0x6054, 0x1869, 0x71D5, 0xB572, 0x7BF1,
83            0xE925, 0xEE2D, 0xEEDE, 0xA13C, 0x6613, 0x9BAB, 0x122D, 0x7AE4,
84            0x5268, 0xE6C9, 0x50CB, 0x79A1, 0xF212, 0xA062, 0x6B48, 0x70B3,
85            0xF6B0, 0x06D5, 0xF8AB, 0xECF5, 0x6255, 0xEDD8, 0x79D2, 0x290A
86        },
87        {
88            0xD3CF, 0x014E, 0xACB3, 0x8F6B, 0x0F2C, 0xA5D8, 0xE8E0, 0x863D,
89            0x80D5, 0x5705, 0x658A, 0x8BC2, 0xEE46, 0xD3AE, 0x0199, 0x0100,
90            0x4A35, 0xABE4, 0xF976, 0x935A, 0xA8A5, 0xBAE9, 0x24D0, 0x71AA,
91            0xB3FE, 0x095E, 0xAB06, 0x4CD5, 0x2F0D, 0x1ACB, 0x59F3, 0x4C50
92        },
93        {
94            0xFD27, 0x0F8E, 0x191A, 0xEEE7, 0x2F49, 0x3A05, 0x3267, 0x4F88,
95            0x38AE, 0xFCE9, 0x9476, 0x18C6, 0xF961, 0x4EF0, 0x39D0, 0x42E6,
96            0xB747, 0xE625, 0xB68E, 0x5100, 0xF92A, 0x86FE, 0xE79B, 0xEE91,
97            0x21D5, 0x4C3C, 0x683D, 0x5AD1, 0x1B49, 0xF407, 0x0194, 0x0100
98        },
99        {
100            0x4BF9, 0xDC0D, 0x9478, 0x5174, 0xCB4A, 0x8A89, 0x4D6A, 0xFED8,
101            0xF123, 0xA8CD, 0xEEE7, 0xA6D1, 0xB763, 0xF5E2, 0xE085, 0x01EF,
102            0xE466, 0x9FA3, 0x2F68, 0x2190, 0x423F, 0x287F, 0x7F3F, 0x09F6,
103            0x2111, 0xA963, 0xD0BB, 0x674A, 0xBA72, 0x45F9, 0xF186, 0xB8F5
104        },
105        {
106            0x0010, 0xD1B9, 0xB164, 0x9E87, 0x1F49, 0x6950, 0x2DBF, 0x38D3,
107            0x2EB0, 0x3E8E, 0x91E6, 0xF688, 0x7E41, 0x566E, 0x01B0, 0x0100,
108            0x24A1, 0x73D8, 0xA0C3, 0xF71B, 0xA0A5, 0x2A06, 0xBA46, 0xFEC3,
109            0xDD4C, 0x52CC, 0xF9BC, 0x3B7E, 0x3812, 0x0666, 0xB74B, 0x40F8
110        },
111        {
112            0x28F2, 0x7C81, 0xFC92, 0x6FBD, 0x53D6, 0x72A3, 0xBBDF, 0xB6FC,
113            0x9CE5, 0x2331, 0xD4F6, 0xC5BB, 0xE8BB, 0x6676, 0x02D9, 0x2F0E,
114            0xD009, 0xD136, 0xCD09, 0x7551, 0x1826, 0x9D9B, 0x63EA, 0xFC63,
115            0x68CD, 0x3672, 0xCB95, 0xD28E, 0xF1CD, 0x20CA, 0x014C, 0x0100
116        },
117        {
118            0xE539, 0x55B7, 0x989D, 0x21C4, 0x463A, 0xE68F, 0xF8B5, 0xE5C5,
119            0x662B, 0x35BF, 0x3C50, 0x0131, 0xF4BF, 0x38B2, 0x41BC, 0xB829,
120            0x02B7, 0x6B8F, 0xA25C, 0xAFD2, 0xD84A, 0x2243, 0x53EB, 0xC6C9,
121            0x2E14, 0x181F, 0x8F96, 0xDF0E, 0x0D4C, 0x30F6, 0xFFE1, 0x9DDA
122        },
123        {
124            0x30B6, 0x777E, 0xDA3D, 0xAF77, 0x205E, 0xC90B, 0x856B, 0xB451,
125            0x3BCC, 0x76C2, 0x8ACF, 0xDCB1, 0xA5E5, 0xDD64, 0x0197, 0x0100,
126            0xE751, 0xB661, 0x0404, 0xDB4A, 0xE9DD, 0xA400, 0xAF26, 0x3F5E,
127            0x904B, 0xA924, 0x09E0, 0xE72B, 0x825B, 0x2C50, 0x6FD0, 0x0D52
128        },
129        {
130            0x2730, 0xC2BA, 0x9E44, 0x5815, 0xFC47, 0xB21D, 0x67B8, 0xF8B9,
131            0x047D, 0xB0AF, 0x9F14, 0x741B, 0x4668, 0xBE54, 0xDE16, 0xDB14,
132            0x7CB7, 0xF2B8, 0x0683, 0x762C, 0x09A0, 0x9507, 0x7F92, 0x022C,
133            0xBA6A, 0x7D52, 0x0AF4, 0x1BC3, 0xB46A, 0xC4FD, 0x01C2, 0x0100
134        },
135        {
136            0x7611, 0x66F3, 0xEE87, 0xEDD3, 0xC559, 0xEFD4, 0xDC59, 0xF86B,
137            0x6D1C, 0x1C85, 0x9BB1, 0x3373, 0x763F, 0x4EBE, 0x1BF3, 0x99B5,
138            0xD721, 0x978F, 0xCF5C, 0xAC51, 0x0984, 0x7462, 0x8F0C, 0x2817,
139            0x4AD9, 0xFD41, 0x6678, 0x7C85, 0xD330, 0xC9F8, 0x1D9A, 0xC622
140        },
141        {
142            0x5AE4, 0xE16A, 0x60F6, 0xFD45, 0x668C, 0x29D6, 0x0285, 0x6B92,
143            0x92C2, 0x21DE, 0x45E0, 0xEF3D, 0x8B0D, 0x02CD, 0x0198, 0x0100,
144            0x9E6D, 0x4D38, 0xDEF9, 0xE6F2, 0xF72E, 0xB313, 0x14F2, 0x390A,
145            0x2D67, 0xC71E, 0xCB69, 0x7F66, 0xD3CF, 0x7F8A, 0x81D9, 0x9DDE
146        },
147        {
148            0x85E3, 0x8F29, 0x36EB, 0xC968, 0x3696, 0x59F6, 0x7832, 0xA78B,
149            0xA1D8, 0xF5CF, 0xAB64, 0x646D, 0x7A2A, 0xBAF8, 0xAA87, 0x41C7,
150            0x5120, 0xDE78, 0x738D, 0xDC1A, 0x268D, 0x5DF8, 0xED69, 0x1C8A,
151            0xBC85, 0x3DCD, 0xAE30, 0x0F8D, 0xEC89, 0x3ABD, 0x0166, 0x0100
152        },
153        {
154            0xB8BD, 0x643B, 0x748E, 0xBD63, 0xEC6F, 0xE23A, 0x9493, 0xDD76,
155            0x0A62, 0x774F, 0xCD68, 0xA67A, 0x9A23, 0xC8A8, 0xBDE5, 0x9D1B,
156            0x2B86, 0x8B36, 0x5428, 0x1DFB, 0xCD1D, 0x0713, 0x29C2, 0x8E8E,
157            0x5207, 0xA13F, 0x6005, 0x4F5E, 0x52E0, 0xE7C8, 0x6D1C, 0x3E34
158        },
159        {
160            0x581D, 0x2BFA, 0x5E1D, 0xA891, 0x1069, 0x1DA4, 0x39A0, 0xBE45,
161            0x5B9A, 0x7333, 0x6F3E, 0x8637, 0xA550, 0xC9E9, 0x5C6C, 0x42BA,
162            0xA712, 0xC3EA, 0x3808, 0x0910, 0xAA4D, 0x5B25, 0xABCD, 0xE680,
163            0x96AD, 0x2CEC, 0x8EBB, 0xA47D, 0x1690, 0xE8FB, 0x01C8, 0x0100
164        },
165        {
166            0x73B9, 0x82BC, 0x9EBC, 0xB130, 0x0DA5, 0x8617, 0x9F7B, 0x9766,
167            0x205D, 0x752D, 0xB05C, 0x2A17, 0xA75C, 0x18EF, 0x8339, 0xFD34,
168            0x8DA2, 0x7970, 0xD0B4, 0x70F1, 0x3765, 0x7380, 0x7CAF, 0x570E,
169            0x6440, 0xBC44, 0x0743, 0x2D02, 0x0419, 0xA240, 0x2113, 0x1AD4
170        },
171        {
172            0x1EB5, 0xBBFF, 0x39B1, 0x3209, 0x705F, 0x15F4, 0xD7AD, 0x340B,
173            0xC2A6, 0x25CA, 0xF412, 0x9570, 0x0F4F, 0xE4D5, 0x1614, 0xE464,
174            0x911A, 0x0F0E, 0x07DA, 0xA929, 0x2379, 0xD988, 0x0AA6, 0x3B57,
175            0xBF63, 0x71FB, 0x72D5, 0x26CE, 0xB0AF, 0xCF45, 0x011B, 0x0100
176        },
177        {
178            0x9999, 0x98FE, 0xA108, 0x6588, 0xF90B, 0x4554, 0xFF38, 0x4642,
179            0x8F5F, 0x6CC3, 0x4E8E, 0xFF7E, 0x64C2, 0x50CA, 0x0E7F, 0xAD7D,
180            0x6AAB, 0x33C1, 0xE1F4, 0x6165, 0x7894, 0x83B9, 0x0A0C, 0x38AF,
181            0x5803, 0x18C0, 0xFA36, 0x592C, 0x4548, 0xABB8, 0x1527, 0xAEE9
182        }
183    };
184
185
186    //ecm_header_data = 01 03 b0 01 01
187    if(!cw_is_valid(cw))          //if cw is all zero, keep it that way
188    {
189        return;
190    }
191    ecm_header_count = ecm_header_data[0];
192    for(i = 0, ecmi = 1; i < ecm_header_count; i++)
193    {
194        if(ecm_header_data[ecmi + 1] != 0xb0)
195        {
196            ecmi += ecm_header_data[ecmi] + 1;
197        }
198        else
199        {
200            switch(ecm_header_data[ecmi + 2])
201            {
202                //b0 01
203            case 1:
204            {
205                uint16_t hk[8], r, j, m = 0;
206                for(r = 0; r < 6; r++)
207                    { hk[2 + r] = Hash3[r]; }
208                for(r = 0; r < 2; r++)
209                {
210                    for(j = 0; j < 0x48; j += 2)
211                    {
212                        if(r)
213                        {
214                            hk[0] = ((hk[3] & hk[5]) | ((~hk[5]) & hk[4]));
215                        }
216                        else
217                        {
218                            hk[0] = ((hk[3] & hk[4]) | ((~hk[3]) & hk[5]));
219                        }
220                        if(j < 8)
221                        {
222                            hk[0] = (hk[0] + ((cw[j + 1] << 8) | cw[j]));
223                        }
224                        if(j == 8)
225                        {
226                            hk[0] = (hk[0] + 0x80);
227                        }
228                        hk[0] = (hk[0] + hk[2] + (0xFF & NdTabB001[ecm_header_data[ecmi + 3]][m >> 1] >> ((m & 1) << 3)));
229                        hk[1] = hk[2];
230                        hk[2] = hk[3];
231                        hk[3] = hk[4];
232                        hk[4] = hk[5];
233                        hk[5] = hk[6];
234                        hk[6] = hk[7];
235                        hk[7] = hk[2] + (((hk[0] << Hash4[m & 0xF]) | (hk[0] >> (0x10 - Hash4[m & 0xF]))));
236                        m = (m + 1) & 0x3F;
237                    }
238                }
239                for(r = 0; r < 6; r++)
240                {
241                    hk[2 + r] += Hash3[r];
242                }
243                for(r = 0; r < 7; r++)
244                {
245                    cw[r] = hk[2 + (r >> 1)] >> ((r & 1) << 3);
246                }
247                cw[3] = (cw[0] + cw[1] + cw[2]) & 0xFF;
248                cw[7] = (cw[4] + cw[5] + cw[6]) & 0xFF;
249                rdr_ddump_mask(reader, D_READER, cw, 8, "Postprocessed Case 1 DW:");
250                break;
251            }
252            case 3:
253            {
254                memset(buffer, 0, sizeof(buffer));
255                memcpy(buffer, cw, 8);
256                memcpy(buffer + 8, &ecm_header_data[ecmi + 3], ecm_header_data[ecmi] & 0x7D);
257                MD5(buffer, 8 + (ecm_header_data[ecmi] & 0x7D), md5tmp);
258                memcpy(cw, md5tmp, 8);
259                rdr_ddump_mask(reader, D_READER, cw, 8, "Postprocessed Case 3 DW:");
260                break;
261            }
262            case 2:
263            {
264                /* Method 2 left out */
265                //memcpy(DW_OUTPUT, DW_INPUT, 8);
266                break;
267            }
268            }
269        }
270    }
271}
272
273
274static void vg2_read_tiers(struct s_reader *reader)
275{
276    def_resp;
277    int32_t l;
278
279    /* ins2a is not needed and causes an error on some cards eg Sky Italy 09CD
280       check if ins2a is in command table before running it
281    */
282    static const unsigned char ins2a[5] = { 0xD0, 0x2a, 0x00, 0x00, 0x00 };
283    if(cmd_exists(reader, ins2a))
284    {
285        l = do_cmd(reader, ins2a, NULL, NULL, cta_res);
286        if(l < 0 || !status_ok(cta_res + l))
287        {
288            rdr_log(reader, "classD0 ins2a: failed");
289            return;
290        }
291    }
292
293    static const unsigned char ins76007f[5] = { 0xD0, 0x76, 0x00, 0x7f, 0x02 };
294    if(!write_cmd_vg(ins76007f, NULL) || !status_ok(cta_res + 2))
295    {
296        rdr_log(reader, "classD0 ins76007f: failed");
297        return;
298    }
299    int32_t num = cta_res[1];
300
301    int32_t i;
302    unsigned char ins76[5] = { 0xD0, 0x76, 0x00, 0x00, 0x00 };
303    struct videoguard_data *csystem_data = reader->csystem_data;
304
305    // some cards start real tiers info in middle of tier info
306    // and have blank tiers between old tiers and real tiers eg 09AC
307    int32_t starttier = csystem_data->card_tierstart;
308    bool stopemptytier = 1;
309    if(!starttier)
310        { stopemptytier = 0; }
311
312    // check to see if specified start tier is blank and if blank, start at 0 and ignore blank tiers
313    ins76[2] = starttier;
314    l = do_cmd(reader, ins76, NULL, NULL, cta_res);
315    if(l < 0 || !status_ok(cta_res + l)) { return; }
316    if(cta_res[2] == 0 && cta_res[3] == 0)
317    {
318        stopemptytier = 0;
319        starttier = 0;
320    }
321
322    cs_clear_entitlement(reader); // reset the entitlements
323
324    for(i = starttier; i < num; i++)
325    {
326        ins76[2] = i;
327        l = do_cmd(reader, ins76, NULL, NULL, cta_res);
328        if(l < 0 || !status_ok(cta_res + l)) { return; }
329        if(cta_res[2] == 0 && cta_res[3] == 0 && stopemptytier) { return; }
330        if(cta_res[2] != 0 || cta_res[3] != 0)
331        {
332            char tiername[83];
333            uint16_t tier_id = (cta_res[2] << 8) | cta_res[3];
334            // add entitlements to list
335            struct tm timeinfo;
336            memset(&timeinfo, 0, sizeof(struct tm));
337            rev_date_calc_tm(&cta_res[4], &timeinfo, csystem_data->card_baseyear);
338            cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), tier_id, 0, 0, mktime(&timeinfo), 4);
339
340            if(!stopemptytier)
341            {
342                rdr_debug_mask(reader, D_READER, "tier: %04x, tier-number: 0x%02x", tier_id, i);
343            }
344            rdr_log(reader, "tier: %04x, expiry date: %04d/%02d/%02d-%02d:%02d:%02d %s", tier_id, timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, get_tiername(tier_id, reader->caid, tiername));
345        }
346    }
347}
348
349static int32_t videoguard2_card_init(struct s_reader *reader, ATR *newatr)
350{
351    get_hist;
352    if((hist_size < 7) || (hist[1] != 0xB0) || (hist[4] != 0xFF) || (hist[5] != 0x4A) || (hist[6] != 0x50))
353    {
354        rdr_debug_mask(reader, D_READER, "failed history check");
355        return ERROR;
356    }
357    rdr_debug_mask(reader, D_READER, "passed history check");
358
359    get_atr;
360    def_resp;
361
362    if(!cs_malloc(&reader->csystem_data, sizeof(struct videoguard_data)))
363        { return ERROR; }
364    struct videoguard_data *csystem_data = reader->csystem_data;
365
366    /* set information on the card stored in reader-videoguard-common.c */
367    set_known_card_info(reader, atr, &atr_size);
368
369    if((reader->ndsversion != NDS2) &&
370            (((csystem_data->card_system_version != NDS2) && (csystem_data->card_system_version != NDSUNKNOWN)) ||
371             (reader->ndsversion != NDSAUTO)))
372    {
373        /* known ATR and not NDS2
374           or known NDS2 ATR and forced to another NDS version */
375        return ERROR;
376    }
377
378    rdr_debug_mask(reader, D_READER, "type: %s, baseyear: %i", csystem_data->card_desc, csystem_data->card_baseyear);
379    if(reader->ndsversion == NDS2)
380    {
381        rdr_debug_mask(reader, D_READER, "forced to NDS2");
382    }
383
384    //a non videoguard2/NDS2 card will fail on read_cmd_len(ins7401)
385    //this way unknown videoguard2/NDS2 cards will also pass this check
386
387    unsigned char ins7401[5] = { 0xD0, 0x74, 0x01, 0x00, 0x00 };
388    int32_t l;
389    if((l = read_cmd_len(reader, ins7401)) < 0)  //not a videoguard2/NDS card or communication error
390    {
391        return ERROR;
392    }
393    ins7401[4] = l;
394    if(!write_cmd_vg(ins7401, NULL) || !status_ok(cta_res + l))
395    {
396        rdr_log(reader, "classD0 ins7401: failed - cmd list not read");
397        return ERROR;
398    }
399
400    memorize_cmd_table(reader, cta_res, l);
401
402    unsigned char buff[256];
403
404    static const unsigned char ins02[5] = { 0xD0, 0x02, 0x00, 0x00, 0x08 };
405    // D0 02 command is not always present in command table but should be supported
406    // on most cards so do not use do_cmd()
407    if(!write_cmd_vg(ins02, NULL) || !status_ok(cta_res + 8))
408    {
409        rdr_log(reader, "Unable to get NDS ROM version.");
410    }
411    else
412    {
413        int i;
414        for(i = 0; i < 8; i++)
415        {
416            if(cta_res[i] <= 0x09)
417            {
418                cta_res[i] = cta_res[i] + 0x30;
419            }
420            else if(!isalnum(cta_res[i]))
421            {
422                cta_res[i] = '*';
423            }
424        }
425        memset(reader->rom, 0, sizeof(reader->rom));
426        memcpy(reader->rom, cta_res, 4);
427        reader->rom[4] = '-';
428        memcpy(reader->rom + 5, cta_res + 4, 4);
429
430        rdr_log(reader, "Card type:   %c%c%c%c", reader->rom[0], reader->rom[1], reader->rom[2], reader->rom[3]);
431        rdr_log(reader, "Rom version: %c%c%c%c", reader->rom[5], reader->rom[6], reader->rom[7], reader->rom[8]);
432    }
433
434    /* get Vg credit on card */
435    unsigned char ins7404[5] = { 0xD0, 0x74, 0x04, 0x00, 0x00 };
436    l = read_cmd_len(reader, ins7404);     //get command len for ins7404
437    ins7404[4] = l;
438    if(!write_cmd_vg(ins7404, NULL) || !status_ok(cta_res + l))
439    {
440        rdr_log(reader, "Unable to get smartcard credit");
441    }
442    else
443    {
444        if (cta_res[0] == 0x15)
445        {
446            reader->VgCredit = ((cta_res[8] << 8) + cta_res[9]) / 100;
447            rdr_log(reader, "Credit available on card: %i €", reader->VgCredit);
448        }
449    }
450
451    if(reader->ins7E11[0x01])
452    {
453        unsigned char ins742b[5] = { 0xD0, 0x74, 0x2b, 0x00, 0x00 };
454
455        l = read_cmd_len(reader, ins742b);  //get command len for ins742b
456
457        if(l < 2)
458        {
459            rdr_log(reader, "No TA1 change for this card is possible by ins7E11");
460        }
461        else
462        {
463            ins742b[4] = l;
464            bool ta1ok = 0;
465
466            if(!write_cmd_vg(ins742b, NULL) || !status_ok(cta_res + ins742b[4]))  //get supported TA1 bytes
467            {
468                rdr_log(reader, "classD0 ins742b: failed");
469                return ERROR;
470            }
471            else
472            {
473                int32_t i;
474
475                for(i = 2; i < l; i++)
476                {
477                    if(cta_res[i] == reader->ins7E11[0x00])
478                    {
479                        ta1ok = 1;
480                        break;
481                    }
482                }
483            }
484            if(ta1ok == 0)
485            {
486                rdr_log(reader, "The value %02X of ins7E11 is not supported,try one between %02X and %02X", reader->ins7E11[0x00], cta_res[2], cta_res[ins742b[4] - 1]);
487            }
488            else
489            {
490                static const uint8_t ins7E11[5] = { 0xD0, 0x7E, 0x11, 0x00, 0x01 };
491
492                reader->ins7e11_fast_reset = 0;
493
494                l = do_cmd(reader, ins7E11, reader->ins7E11, NULL, cta_res);
495
496                if(l < 0 || !status_ok(cta_res))
497                {
498                    rdr_log(reader, "classD0 ins7E11: failed");
499                    return ERROR;
500                }
501                else
502                {
503                    unsigned char TA1;
504
505                    if(ATR_GetInterfaceByte(newatr, 1, ATR_INTERFACE_BYTE_TA, &TA1) == ATR_OK)
506                    {
507                        if(TA1 != reader->ins7E11[0x00])
508                        {
509                            rdr_log(reader, "classD0 ins7E11: Scheduling card reset for TA1 change from %02X to %02X", TA1, reader->ins7E11[0x00]);
510                            reader->ins7e11_fast_reset = 1;
511#ifdef WITH_COOLAPI
512                            if(reader->typ == R_MOUSE || reader->typ == R_SC8in1 || reader->typ == R_SMART || reader->typ == R_INTERNAL)
513                            {
514#else
515                            if(reader->typ == R_MOUSE || reader->typ == R_SC8in1 || reader->typ == R_SMART)
516                            {
517#endif
518                                add_job(reader->client, ACTION_READER_RESET_FAST, NULL, 0);
519                            }
520                            else
521                            {
522                                add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
523                            }
524                            return OK; // Skip the rest of the init since the card will be reset anyway
525                        }
526                    }
527                }
528            }
529        }
530    }
531    static const unsigned char ins7416[5] = { 0xD0, 0x74, 0x16, 0x00, 0x00 };
532
533    if(do_cmd(reader, ins7416, NULL, NULL, cta_res) < 0)
534    {
535        rdr_log(reader, "classD0 ins7416: failed");
536        return ERROR;
537    }
538    unsigned char boxID [4];
539
540    if(reader->boxid > 0)
541    {
542        /* the boxid is specified in the config */
543        int32_t i;
544        for(i = 0; i < 4; i++)
545        {
546            boxID[i] = (reader->boxid >> (8 * (3 - i))) % 0x100;
547        }
548    }
549    else
550    {
551        unsigned char ins36[5] = { 0xD0, 0x36, 0x00, 0x00, 0x00 };
552        static const unsigned char ins5e[5] = { 0xD0, 0x5E, 0x00, 0x0C, 0x02 };
553
554        /* we can try to get the boxid from the card */
555        int32_t boxidOK = 0;
556        l = read_cmd_len(reader, ins36);
557        if(l > 0)
558        {
559            ins36[4] = l;
560        }
561        else if(cmd_exists(reader, ins5e))
562        {
563            if(!write_cmd_vg(ins5e, NULL) || !status_ok(cta_res + 2))
564            {
565                rdr_log(reader, "classD0 ins5e: failed");
566            }
567            else
568            {
569                ins36[3] = cta_res[0];
570                ins36[4] = cta_res[1];
571            }
572        }
573        l = ins36[4];
574        if(!write_cmd_vg(ins36, NULL) || !status_ok(cta_res + l))
575        {
576            rdr_log(reader, "classD0 ins36: failed");
577            return ERROR;
578        }
579        memcpy(buff, ins36, 5);
580        memcpy(buff + 5, cta_res, l);
581        memcpy(buff + 5 + l, cta_res + l, 2);
582        if(l < 13)
583            { rdr_log(reader, "classD0 ins36: answer too int16"); }
584        else if(buff[7] > 0x0F)
585            { rdr_log(reader, "classD0 ins36: encrypted - can't parse"); }
586        else
587        {
588            /* skipping the initial fixed fields: cmdecho (4) + length (1) + encr/rev++ (4) */
589            int32_t i = 9;
590            int32_t gotUA = 0;
591            while(i < l)
592            {
593                if(!gotUA && buff[i] < 0xF0)  /* then we guess that the next 4 bytes is the UA */
594                {
595                    gotUA = 1;
596                    i += 4;
597                }
598                else switch(buff[i])      /* object length vary depending on type */
599                    {
600                    case 0x00: /* padding */
601                        i += 1;
602                        break;
603                    case 0xEF: /* card status */
604                        i += 3;
605                        break;
606                    case 0xD1:
607                        i += 4;
608                        break;
609                    case 0xDF: /* next server contact */
610                        i += 5;
611                        break;
612                    case 0xF3: /* boxID */
613                        memcpy(boxID, buff + i + 1, sizeof(boxID));
614                        boxidOK = 1;
615                        i += 5;
616                        break;
617                    case 0xF6:
618                        i += 6;
619                        break;
620                    case 0x01: /* date & time */
621                        i += 7;
622                        break;
623                    case 0xFA:
624                        i += 9;
625                        break;
626                    case 0x5E:
627                    case 0x67: /* signature */
628                    case 0xDE:
629                    case 0xE2:
630                    case 0xE9: /* tier dates */
631                    case 0xF8: /* Old PPV Event Record */
632                    case 0xFD:
633                        i += buff[i + 1] + 2; /* skip length + 2 bytes (type and length) */
634                        break;
635                    default: /* default to assume a length byte */
636                        rdr_log(reader, "classD0 ins36: returned unknown type=0x%02X - parsing may fail", buff[i]);
637                        i += buff[i + 1] + 2;
638                    }
639            }
640        }
641
642        if(!boxidOK)
643        {
644            rdr_log(reader, "no boxID available");
645            return ERROR;
646        }
647    }
648
649    unsigned char ins4C[5] = { 0xD0, 0x4C, 0x00, 0x00, 0x09 };
650    unsigned char len4c = 0, mode = 0;
651    unsigned char payload4C[0xF] = { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
652    if(cmd_table_get_info(reader, ins4C, &len4c, &mode))
653    {
654        ins4C[4] = len4c;               //don't mind if payload is > of ins len, it will be cutted after write_cmd_vg()
655        if(len4c > 9)
656        {
657            payload4C[8] = 0x44;        //value taken from v14 boot log
658            rdr_log(reader, "Extended 4C detected");
659        }
660    }
661
662    memcpy(payload4C, boxID, 4);
663    if(!write_cmd_vg(ins4C, payload4C) || !status_ok(cta_res ))
664    {
665        rdr_log(reader, "classD0 ins4C: failed - sending boxid failed");
666        return ERROR;
667    }
668
669    //int16_t int32_t SWIRDstatus = cta_res[1];
670    static const unsigned char ins58[5] = { 0xD0, 0x58, 0x00, 0x00, 0x00 };
671    l = do_cmd(reader, ins58, NULL, NULL, cta_res);
672    if(l < 0)
673    {
674        rdr_log(reader, "classD0 ins58: failed");
675        return ERROR;
676    }
677    memset(reader->hexserial, 0, 8);
678    memcpy(reader->hexserial + 2, cta_res + 3, 4);
679    memcpy(reader->sa, cta_res + 3, 3);
680    reader->caid = cta_res[24] * 0x100 + cta_res[25];
681    memset(reader->VgRegionC, 0, 8);
682    memcpy(reader->VgRegionC, cta_res + 60, 8);
683    rdr_log(reader, "Region Code: %c%c%c%c%c%c%c%c", reader->VgRegionC[0], reader->VgRegionC[1], reader->VgRegionC[2], reader->VgRegionC[3], reader->VgRegionC[4], reader->VgRegionC[5], reader->VgRegionC[6], reader->VgRegionC[7]);
684
685    /* we have one provider, 0x0000 */
686    reader->nprov = 1;
687    memset(reader->prid, 0x00, sizeof(reader->prid));
688
689    /*
690    rdr_log(reader, "INS58 : Fuse byte=0x%02X, IRDStatus=0x%02X", cta_res[2],SWIRDstatus);
691    if (SWIRDstatus==4)  {
692    // If swMarriage=4, not married then exchange for BC Key
693    rdr_log(reader, "Card not married, exchange for BC Keys");
694     */
695
696    cCamCryptVG_SetSeed(reader);
697
698    static const unsigned char insB4[5] = { 0xD0, 0xB4, 0x00, 0x00, 0x40 };
699    unsigned char tbuff[64];
700    cCamCryptVG_GetCamKey(reader, tbuff);
701    l = do_cmd(reader, insB4, tbuff, NULL, cta_res);
702    if(l < 0 || !status_ok(cta_res))
703    {
704        rdr_log(reader, "classD0 insB4: failed");
705        return ERROR;
706    }
707
708    static const unsigned char insBC[5] = { 0xD0, 0xBC, 0x00, 0x00, 0x00 };
709    l = do_cmd(reader, insBC, NULL, NULL, cta_res);
710    if(l < 0)
711    {
712        rdr_log(reader, "classD0 insBC: failed");
713        return ERROR;
714    }
715
716    // Class D1/D3 instructions only work after this point
717
718    static const unsigned char insBE[5] = { 0xD3, 0xBE, 0x00, 0x00, 0x00 };
719    l = do_cmd(reader, insBE, NULL, NULL, cta_res);
720    if(l < 0)
721    {
722        rdr_log(reader, "classD3 insBE: failed");
723        return ERROR;
724    }
725
726    static const unsigned char ins58a[5] = { 0xD1, 0x58, 0x00, 0x00, 0x00 };
727    l = do_cmd(reader, ins58a, NULL, NULL, cta_res);
728    if(l < 0)
729    {
730        rdr_log(reader, "classD1 ins58: failed");
731        return ERROR;
732    }
733    /*new ins74 present at boot*/
734
735    static const unsigned char ins7423[5] = { 0xD1, 0x74, 0x23, 0x00, 0x00 };
736    if(do_cmd(reader, ins7423, NULL, NULL, cta_res) < 0)
737    {
738        rdr_log(reader, "classD1 ins7423: failed");
739    }
740
741    static const unsigned char ins742A[5] = { 0xD1, 0x74, 0x2A, 0x00, 0x00 };
742    if(do_cmd(reader, ins742A, NULL, NULL, cta_res) < 0)
743    {
744        rdr_log(reader, "classD1 ins742A: failed");
745    }
746
747    static const unsigned char ins741B[5] = { 0xD1, 0x74, 0x1B, 0x00, 0x00 };
748    if(do_cmd(reader, ins741B, NULL, NULL, cta_res) < 0)
749    {
750        rdr_log(reader, "classD1 ins741B: failed");
751    }
752
753    static const unsigned char ins4Ca[5] = { 0xD1, 0x4C, 0x00, 0x00, 0x00 };
754    unsigned char ins741C[5] = { 0xD1, 0x74, 0x1C, 0x00, 0x00 };
755    if(len4c > 9)
756        {
757            if((l = read_cmd_len(reader, ins741C)) < 0)  // We need to know the exact len
758            {
759                return ERROR;
760            }
761            ins741C[4] = l;
762            if(do_cmd(reader, ins741C, NULL, NULL, cta_res) < 0)    //from log this payload is copied on 4c
763            {
764                rdr_log(reader, "classD1 ins741C: failed");
765            }
766            else
767            {
768                if(l > 8)   //if payload4c is length 0xF, we can't copy over more than 8 bytes in the next memcopy
769                {
770                    l = 8;
771                }
772                memcpy(payload4C + 8, cta_res, l);
773            }
774        }
775    l = do_cmd(reader, ins4Ca, payload4C, NULL, cta_res);
776    if(l < 0 || !status_ok(cta_res))
777    {
778        rdr_log(reader, "classD1 ins4Ca: failed");
779        return ERROR;
780    }
781
782    if(reader->ins7E[0x1A])
783    {
784        static const uint8_t ins7E[5] = { 0xD1, 0x7E, 0x10, 0x00, 0x1A };
785        l = do_cmd(reader, ins7E, reader->ins7E, NULL, cta_res);
786        if(l < 0 || !status_ok(cta_res))
787        {
788            rdr_log(reader, "classD1 ins7E: failed");
789            return ERROR;
790        }
791    }
792    /* get PIN settings */
793    static const unsigned char ins7411[5] = { 0xD1, 0x74, 0x11, 0x00, 0x00 };
794    unsigned char payload2e4[4];
795    if(do_cmd(reader, ins7411, NULL, NULL, cta_res) < 0)
796    {
797        rdr_log(reader, "classD1 ins7411: unable to get PIN");
798        return ERROR;
799    }
800    else
801    {
802        memset(payload2e4, 0, 4);
803        memcpy(payload2e4, cta_res + 2, 4);
804        reader->VgPin = (cta_res[4] << 8) + cta_res[5];
805        rdr_log(reader, "Pincode read: %i", reader->VgPin);
806    }
807
808    /* get PCB(content rating) settings */
809    static const unsigned char ins74e[5] = {0xD1, 0x74, 0x0E, 0x00, 0x00};
810    if(do_cmd(reader, ins74e, NULL, NULL, cta_res) < 0)
811    {
812        rdr_log(reader, "classD1 ins74e: failed to get PCB settings");
813    }
814    else
815    {
816        rdr_log(reader, "PCB settings: %X %X %X %X", cta_res[2], cta_res[3], cta_res[4], cta_res[5]);
817    }
818
819    /* send PIN */
820    static const unsigned char ins2epin[5] = {0xD1, 0x2E, 0x04, 0x00, 0x04};
821    if(cfg.ulparent)
822    {
823        l = do_cmd(reader, ins2epin, payload2e4, NULL, cta_res);
824        if(l < 0 || !status_ok(cta_res))
825        {
826            rdr_log(reader, "classD1 ins2E: failed");
827            rdr_log(reader, "Cannot disable parental control");
828            return ERROR;
829        }
830        else
831        {
832            rdr_log(reader, "Parental control disabled");
833        }
834    }
835    /* send check control for pin, needed on some cards */
836    /* the presence and the value of payloads is provider's dependent*/
837        if(reader->ins2e06[4])
838    {
839        static const unsigned char ins2e06[5] = { 0xD1, 0x2E, 0x06, 0x00, 0x04 };
840        l = do_cmd(reader, ins2e06, reader->ins2e06, NULL, cta_res);
841        if(l < 0 || !status_ok(cta_res))
842        {
843            rdr_log(reader, "classD1 ins2E: failed");
844            return ERROR;
845        }
846    }
847
848    // fix for 09ac cards
849    unsigned char dimeno_magic[0x10] = {0xF9, 0xFB, 0xCD, 0x5A, 0x76, 0xB5, 0xC4, 0x5C, 0xC8, 0x2E, 0x1D, 0xE1, 0xCC, 0x5B, 0x6B, 0x02};
850    int32_t a;
851    for(a = 0; a < 4; a++)
852        { dimeno_magic[a] = dimeno_magic[a] ^ boxID[a]; }
853    AES_set_decrypt_key(dimeno_magic, 128, &(csystem_data->astrokey));
854
855    rdr_log(reader, "type: %s, caid: %04X",
856            csystem_data->card_desc,
857            reader->caid);
858    rdr_log_sensitive(reader, "serial: {%02X%02X%02X%02X}, BoxID: {%02X%02X%02X%02X}, baseyear: %i",
859                      reader->hexserial[2], reader->hexserial[3], reader->hexserial[4], reader->hexserial[5],
860                      boxID[0], boxID[1], boxID[2], boxID[3],
861                      csystem_data->card_baseyear);
862    rdr_log(reader, "ready for requests");
863
864    return OK;
865}
866
867static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
868{
869    unsigned char cta_res[CTA_RES_LEN];
870    static const char valid_ecm[] = { 0x00, 0x00, 0x01 };
871    unsigned char ins40[5] = { 0xD1, 0x40, 0x00, 0x80, 0xFF };
872    static const unsigned char ins54[5] = { 0xD3, 0x54, 0x00, 0x00, 0x00};
873    int32_t posECMpart2 = er->ecm[6] + 7;
874    int32_t lenECMpart2 = er->ecm[posECMpart2] + 1;
875    unsigned char tbuff[264], rbuff[264];
876    tbuff[0] = 0;
877
878    memset(ea->cw + 0, 0, 16); //set cw to 0 so client will know it is invalid unless it is overwritten with a valid cw
879
880    if(memcmp(&(er->ecm[3]), valid_ecm, sizeof(valid_ecm) != 0))
881    {
882        rdr_log(reader, "Not a valid ecm");
883        return ERROR;
884    }
885
886    memcpy(tbuff + 1, er->ecm + posECMpart2 + 1, lenECMpart2 - 1);
887
888    /*
889      //log parental lock byte
890      int32_t j;
891      for (j = posECMpart2+1; j < lenECMpart2+posECMpart2+1-4; j++){
892        if (er->ecm[j] == 0x02 && er->ecm[j+3] == 0x02) {
893          rdr_log(reader, "channel parental lock mask: %02X%02X, channel parental lock byte: %02X",er->ecm[j+1],er->ecm[j+2],er->ecm[j+4]);
894          break;
895        }
896      }
897
898      //log tiers
899      int32_t k;
900      char tiername[83];
901      for (k = posECMpart2+1; k < lenECMpart2+posECMpart2+1-4; k++){
902        if (er->ecm[k] == 0x03 && er->ecm[k+3] == 0x80) {
903          uint16_t vtier_id = (er->ecm[k+1] << 8) | er->ecm[k+2];
904          get_tiername(vtier_id, reader->caid, tiername);
905          rdr_log(reader, "valid tier: %04x %s",vtier_id, tiername);
906        }
907      }
908    */
909
910    int32_t new_len = lenECMpart2;
911    if(reader->fix_9993 && reader->caid == 0x919 && tbuff[1] == 0x7F)
912    {
913        tbuff[1] = 0x47;
914        tbuff[2] = 0x08;
915        memmove(tbuff + 11, tbuff + 13, new_len - 11);
916        new_len -= 2;
917    }
918    ins40[4] = new_len;
919    int32_t l;
920
921    l = do_cmd(reader, ins40, tbuff, NULL, cta_res);
922    if(l < 0 || !status_ok(cta_res))
923    {
924        rdr_log(reader, "classD1 ins40: (%d) status not ok %02x %02x", l, cta_res[0], cta_res[1]);
925        rdr_log(reader, "The card is not answering correctly! Restarting reader for safety");
926        add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
927        return ERROR;
928    }
929    else
930    {
931        l = do_cmd(reader, ins54, NULL, rbuff, cta_res);
932        if(l < 0 || !status_ok(cta_res + l))
933        {
934            rdr_log(reader, "classD3 ins54: (%d) status not ok %02x %02x", l, cta_res[0], cta_res[1]);
935            rdr_log(reader, "The card is not answering correctly! Restarting reader for safety");
936            add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
937            return ERROR;
938        }
939        else
940        {
941
942            // Log decrypted INS54
943            rdr_ddump_mask(reader, D_READER, rbuff, 5, "INS54:");
944            rdr_ddump_mask(reader, D_READER, rbuff + 5, rbuff[4], "Decrypted payload");
945
946            if(!cw_is_valid(rbuff + 5))  //sky cards report 90 00 = ok but send cw = 00 when channel not subscribed
947            {
948                rdr_log(reader, "classD3 ins54: status 90 00 = ok but cw=00 -> channel not subscribed ");
949                return ERROR;
950            }
951
952            // copy cw1 in place
953            memcpy(ea->cw + 0, rbuff + 5, 8);
954
955            // process cw2
956            unsigned char *payload = rbuff + 5;
957            int32_t payloadLen = rbuff[4];
958            int32_t ind = 8 + 6; // +8 for CW1, +6 for counter(?)
959
960            while(ind < payloadLen)
961            {
962                switch(payload[ind])
963                {
964                case 0x25:  // CW2
965                    //cs_dump (payload + ind, payload[ind+1]+2, "INS54 - CW2");
966                    memcpy(ea->cw + 8, &payload[ind + 3], 8);
967                    ind += payload[ind + 1] + 2;
968                    break;
969
970                default:
971                    //cs_dump (payload + ind, payload[ind+1]+2, "INS54");
972                    ind += payload[ind + 1] + 2;
973                    break;
974                }
975            }
976
977            if(new_len != lenECMpart2)
978            {
979                memcpy(ea->cw, ea->cw + 8, 8);
980                memset(ea->cw + 8, 0, 8);
981            }
982            // fix for 09ac cards
983            dimeno_PostProcess_Decrypt(reader, rbuff, ea->cw);
984
985            //test for postprocessing marker
986            int32_t posB0 = -1;
987            int32_t i;
988            for(i = 6; i < posECMpart2; i++)
989            {
990                if(er->ecm[i - 3] == 0x80 && er->ecm[i] == 0xB0 && ((er->ecm[i + 1] == 0x01) || (er->ecm[i + 1] == 0x02) || (er->ecm[i + 1] == 0x03)))
991                {
992                    posB0 = i;
993                    break;
994                }
995            }
996            if(posB0 != -1)
997            {
998                do_post_dw_hash(reader, ea->cw + 0, &er->ecm[posB0 - 2]);
999                do_post_dw_hash(reader, ea->cw + 8, &er->ecm[posB0 - 2]);
1000            }
1001
1002            if(reader->caid == 0x0907)    //quickfix: cw2 is not a valid cw, something went wrong before
1003            {
1004                memset(ea->cw + 8, 0, 8);
1005                if(er->ecm[0] & 1)
1006                {
1007                    memcpy(ea->cw + 8, ea->cw, 8);
1008                    memset(ea->cw, 0, 8);
1009                }
1010            }
1011            else
1012            {
1013                if(er->ecm[0] & 1)
1014                {
1015                    unsigned char tmpcw[8];
1016                    memcpy(tmpcw, ea->cw + 8, 8);
1017                    memcpy(ea->cw + 8, ea->cw + 0, 8);
1018                    memcpy(ea->cw + 0, tmpcw, 8);
1019                }
1020            }
1021
1022            return OK;
1023        }
1024    }
1025}
1026
1027static int32_t videoguard2_do_emm(struct s_reader *reader, EMM_PACKET *ep)
1028{
1029    return videoguard_do_emm(reader, ep, 0xD1, vg2_read_tiers, do_cmd);
1030}
1031
1032static int32_t videoguard2_card_info(struct s_reader *reader)
1033{
1034    /* info is displayed in init, or when processing info */
1035    struct videoguard_data *csystem_data = reader->csystem_data;
1036    rdr_log(reader, "card detected");
1037    rdr_log(reader, "type: %s", csystem_data->card_desc);
1038    if(reader->ins7e11_fast_reset != 1)
1039    {
1040        vg2_read_tiers(reader);
1041    }
1042    return OK;
1043}
1044
1045void reader_videoguard2(struct s_cardsystem *ph)
1046{
1047    ph->do_emm = videoguard2_do_emm;
1048    ph->do_ecm = videoguard2_do_ecm;
1049    ph->card_info = videoguard2_card_info;
1050    ph->card_init = videoguard2_card_init;
1051    ph->get_emm_type = videoguard_get_emm_type;
1052    ph->get_emm_filter = videoguard_get_emm_filter;
1053    ph->caids[0] = 0x09;
1054    ph->desc = "videoguard2";
1055}
1056#endif
1057
Note: See TracBrowser for help on using the repository browser.