- fix for ticker #4787
[oscam.git] / reader-videoguard-common.c
blobe43671ea9c433c48ace8da99299cd6aeb3b66efd
1 //
2 // Common videoguard functions.
3 //
5 #include "globals.h"
6 #ifdef READER_VIDEOGUARD
7 #include "reader-common.h"
8 #include "reader-videoguard-common.h"
10 #define VG_EMMTYPE_MASK 0xC0
11 #define VG_EMMTYPE_G 0
12 #define VG_EMMTYPE_U 1
13 #define VG_EMMTYPE_S 2
15 typedef struct mailmsg_s
17 uint16_t caid;
18 uint32_t serial;
19 uint16_t date;
20 uint16_t id;
21 uint8_t nsubs;
22 uint16_t len;
23 uint8_t mask;
24 uint8_t written;
25 char *message;
26 char *subject;
27 } MAILMSG;
29 static LLIST *vg_msgs;
31 void set_known_card_info(struct s_reader *reader, const uint8_t *atr, const uint32_t *atr_size)
33 struct videoguard_data *csystem_data = reader->csystem_data;
34 /* Set to sensible default values */
35 csystem_data->card_baseyear = 1997;
36 csystem_data->card_tierstart = 0;
37 csystem_data->card_system_version = NDSUNKNOWN;
38 csystem_data->card_desc = "VideoGuard Unknown Card";
40 static const NDS_ATR_ENTRY nds_atr_table[] = // {atr}, atr len, base year, tier start, nds version, description
42 /* known NDS1 atrs */
43 { { 0x3F, 0x78, 0x13, 0x25, 0x04, 0x40, 0xB0, 0x09, 0x4A, 0x50, 0x01, 0x4E, 0x5A },
44 13, 1992, 0, NDS1, "VideoGuard Sky New Zealand (0969)" }, // 160E
46 { { 0x3F, 0x78, 0x12, 0x25, 0x01, 0x40, 0xB0, 0x14, 0x4A, 0x50, 0x01, 0x53, 0x44 },
47 13, 1997, 0, NDS1, "VideoGuard StarTV India (caid unknown)" }, // 105.5E
49 /* known NDS1+ atrs */
50 { { 0x3F, 0x7F, 0x13, 0x25, 0x04, 0x33, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xE0, 0x00, 0x00, 0x54, 0x42, 0x00, 0x00, 0x00 },
51 20, 1997, 0, NDS12, "VideoGuard China (0988)" },
53 { { 0x3F, 0x78, 0x13, 0x25, 0x03, 0x40, 0xB0, 0x20, 0xFF, 0xFF, 0x4A, 0x50, 0x00 },
54 13, 1997, 0, NDS12, "VideoGuard DirecTV" },
56 /* known NDS2 atrs */
57 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x08, 0xFF, 0xFF, 0x4A, 0x50, 0x90, 0x00, 0x00, 0x47, 0x4C, 0x01 },
58 21, 2004, 0, NDS2, "VideoGuard Sky Brasil GL39 (0907)" },
60 { { 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x46, 0x44, 0x01, 0x00, 0x00 },
61 20, 2000, 0, NDS2, "VideoGuard Foxtel Australia (090B)" }, // 156E
63 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x0E, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x49, 0x54, 0x02, 0x00, 0x00 },
64 22, 1997, 0, NDS2, "VideoGuard Sky Italia (0919)" },
66 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4A, 0x01, 0x00, 0x00 },
67 22, 2004, 0, NDS2, "VideoGuard Dolce Romania (092F)" },
69 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4B, 0x01, 0x00, 0x00 },
70 22, 2004, 0, NDS2, "VideoGuard Viasat Ukraine (0931)" },
72 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x55, 0x01, 0x00, 0x00 },
73 22, 1997, 0, NDS2, "VideoGuard OnoCable Espana (093A)" },
75 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x13, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x49, 0x54, 0x03 },
76 21, 1997, 0, NDS2, "VideoGuard Sky Italia (093B)" },
78 { { 0x3F, 0x7D, 0x11, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56, 0x54, 0x03 },
79 18, 2000, 0, NDS2, "VideoGuard Viasat (093E)" },
81 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56, 0x54, 0x03 },
82 21, 2000, 0, NDS2, "VideoGuard Viasat (0940)" },
84 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x5A, 0x45, 0x03},
85 21, 2004, 0, NDS2, "VideoGuard Get Norway (0941)" },
87 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x05 },
88 23, 2009, 0, NDS2, "VideoGuard Sky Brasil GL54 (0943)" },
90 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x4E, 0x5A, 0x03 },
91 21, 1997, 0, NDS2, "VideoGuard Sky NZ (0958)" },
93 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0 },
94 23, 2004, 0, NDS2, "VideoGuard Sky Mexico (095B)" },
96 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, 0x05 },
97 23, 2004, 0, NDS2, "VideoGuard Sky Mexico (095B)" },
99 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x16, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x53, 0x59, 0x03 },
100 21, 2009, 0, NDS2, "VideoGuard BSkyB (0960)" },
102 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x00, 0x00, 0x53, 0x59, 0x02 },
103 21, 2009, 0, NDS2, "VideoGuard BSkyB (0963)" },
105 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x4E, 0x5A, 0x01, 0x00, 0x00 },
106 22, 1992, 0, NDS2, "VideoGuard Sky New Zealand (096A)" }, // 160E
108 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x46, 0x44, 0x03 },
109 21, 2000, 0, NDS2, "VideoGuard Foxtel Australia (096C)" }, // 156E
111 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
112 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910)" },
114 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
115 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910)" },
117 { { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x11 },
118 22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC)" },
120 { { 0x3F, 0xFF, 0x12, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x12 },
121 22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC) FastMode" },
123 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x13 },
124 22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC) FastMode" },
126 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x14 },
127 22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC) FastMode" },
129 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x15 },
130 22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC) FastMode" },
132 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x34, 0x01, 0x00, 0x14 },
133 22, 1997, 0, NDS2, "VideoGuard Cingal Philippines (09B4)" },
135 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
136 22, 2004, 0, NDS2, "VideoGuard Teleclub (09B6)" },
138 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
139 22, 2004, 0, NDS2, "VideoGuard Teleclub (09B6) FastMode" },
141 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
142 22, 2004, 0, NDS2, "VideoGuard Teleclub (09B6) FastMode" },
144 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x38, 0x01, 0x00, 0x14 },
145 22, 1997, 0, NDS2, "VideoGuard TopTV (09B8)" },
147 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x04, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x49, 0x54, 0x03 },
148 21, 1997, 0, NDS2, "VideoGuard Sky Italia (09CD)" },
150 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00, 0x00, 0x47, 0x54, 0x01, 0x00, 0x00 },
151 22, 1997, 0, NDS2, "VideoGuard YES DBS Israel" },
153 { { 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x56, 0x54, 0x01, 0x00, 0x00 },
154 20, 2000, 0, NDS2, "VideoGuard Viasat Scandinavia" },
156 { { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x11 },
157 22, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (09C4)" },
159 { { 0x3F, 0xFF, 0x12, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x12 },
160 22, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
162 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x13 },
163 22, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
165 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x14 },
166 22, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
168 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x15 },
169 22, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
171 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
172 21, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (098C)" },
174 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
175 21, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (098C) FastMode" },
177 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
178 21, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (098C) FastMode" },
180 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
181 21, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (098D)" },
183 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
184 21, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (098D) FastMode" },
186 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
187 21, 2004, 0, NDS2, "VideoGuard Sky Austria/Germany (098D) FastMode" },
189 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x48, 0x01, 0x00, 0x00 },
190 22, 2004, 0, NDS2, "VideoGuard DSMART Turkey" },
192 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x4B, 0x57, 0x01, 0x00, 0x00 },
193 22, 2004, 0, NDS2, "VideoGuard Kabel BW (098E)" },
195 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x43, 0x01, 0x00, 0x00 },
196 22, 2004, 0, NDS2, "VideoGuard totalTV Serbia (091F)" },
198 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x45, 0x01, 0x00, 0x00 },
199 22, 2004, 0, NDS2, "VideoGuard Get Kabel Norway" },
201 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x14 },
202 22, 2004, 0, NDS2, "VideoGuard Teleclub (09B6)" },
204 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
205 21, 2004, 0, NDS2, "VideoGuard Kabel Deutschland G02/G09 (09C7)" },
207 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
208 21, 2004, 0, NDS2, "VideoGuard Kabel Deutschland G02/G09 (09C7) FastMode" },
210 { { 0x3F, 0x7D, 0x13, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x54, 0x37, 0x03 },
211 18, 2004, 0, NDS2, "VideoGuard Telecolumbus (09AF)" },
213 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x49, 0x01, 0x00, 0x00 },
214 22, 2004, 0, NDS2, "VideoGuard Cyprus (092E)" },
216 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x45, 0x01, 0x00, 0x14 },
217 22, 2004, 0, NDS2, "VideoGuard OTE TV Sat (09BE)" },
219 // NDS Version Unknown as Yet
220 { { 0x3F, 0x7F, 0x13, 0x25, 0x02, 0x40, 0xB0, 0x12, 0x69, 0xFF, 0x4A, 0x50, 0x90, 0x41, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00 },
221 20, 1997, 0, NDSUNKNOWN, "VideoGuard OnoCable Espana (0915)" },
223 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x44, 0x01, 0x00, 0x14 },
224 22, 1997, 0, NDSUNKNOWN, "VideoGuard Sky Vivacom (09BD)" }, // 45E
226 { { 0x3F, 0x7F, 0x13, 0x25, 0x05, 0x40, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x00, 0x00, 0x00, 0x48, 0x4B, 0x00, 0x01, 0x00 },
227 20, 1997, 0, NDSUNKNOWN, "VideoGuard StarTV India (caid unknown)" }, // 105.5E
229 { { 0x3F, 0x7F, 0x13, 0x25, 0x03, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00, 0x00, 0x49, 0x56, 0x01, 0x00, 0x00 },
230 22, 2004, 50, NDS2, "VideoGuard Indovision (09C1)" },
232 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x4A, 0x32, 0x03, 0x00, 0x00 },
233 22, 1997, 0, NDS2, "VideoGuard Otau TV (09D2)" },
235 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x42, 0x52, 0x01, 0x00, 0x00 },
236 22, 2004, 0, NDS2, "VideoGuard Cignal India (09AA)" },
238 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x53, 0x56, 0x01, 0x00, 0x00 },
239 22, 2000, 0, NDS2, "Tata Sky India (0944)" }, // 83.5 East
241 { { 0 },
242 0, 0, 0, 0, NULL}
245 int32_t i = 0;
246 ATR atrdata;
247 ATR *newatr = &atrdata;
248 ATR_InitFromArray(newatr, atr, *atr_size);
249 get_hist;
251 ATR tableatr;
252 uint8_t table_hist[ATR_MAX_HISTORICAL];
253 uint32_t table_hist_size;
255 while(nds_atr_table[i].desc)
257 ATR_InitFromArray(&tableatr, nds_atr_table[i].atr, nds_atr_table[i].atr_len);
258 ATR_GetHistoricalBytes(&tableatr, table_hist, &table_hist_size);
260 if((hist_size == table_hist_size) && (memcmp(hist, table_hist, hist_size) == 0))
262 csystem_data->card_baseyear = nds_atr_table[i].base_year;
263 csystem_data->card_tierstart = nds_atr_table[i].tier_start;
264 csystem_data->card_system_version = nds_atr_table[i].nds_version;
265 csystem_data->card_desc = nds_atr_table[i].desc;
266 break;
268 i++;
272 static void cCamCryptVG_LongMult(uint16_t *pData, uint16_t *pLen, uint32_t mult, uint32_t carry);
273 static void cCamCryptVG_PartialMod(uint16_t val, uint32_t count, uint16_t *outkey, const uint16_t *inkey);
274 static void cCamCryptVG_RotateRightAndHash(uint8_t *p);
275 static void cCamCryptVG_Reorder16A(uint8_t *dest, const uint8_t *src);
276 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader *reader, uint8_t *p);
277 static void cCamCryptVG_Process_D0(struct s_reader *reader, const uint8_t *ins, uint8_t *data);
278 static void cCamCryptVG_Process_D1(struct s_reader *reader, const uint8_t *ins, uint8_t *data, const uint8_t *status);
279 static void cCamCryptVG_Decrypt_D3(struct s_reader *reader, uint8_t *ins, uint8_t *data, const uint8_t *status);
280 static void cCamCryptVG_PostProcess_Decrypt(struct s_reader *reader, uint8_t *rxbuff);
281 static int32_t cAES_Encrypt(struct s_reader *reader, const uint8_t *data, int32_t len, uint8_t *crypted);
282 static void swap_lb(uint8_t *buff, int32_t len);
284 // returns 1 if cw_is_valid, returns 0 if cw is all zeros
285 int32_t cw_is_valid(uint8_t *cw)
287 int32_t i;
289 for(i = 0; i < 8; i++)
291 if(cw[i] != 0) // test if cw = 00
293 return OK;
296 return ERROR;
299 void cAES_SetKey(struct s_reader *reader, const uint8_t *key)
301 struct videoguard_data *csystem_data = reader->csystem_data;
302 AES_set_encrypt_key(key, 128, &(csystem_data->ekey));
305 int32_t cAES_Encrypt(struct s_reader *reader, const uint8_t *data, int32_t len, uint8_t *crypted)
307 struct videoguard_data *csystem_data = reader->csystem_data;
308 len = (len + 15) & (~15); // pad up to a multiple of 16
309 int32_t i;
310 for(i = 0; i < len; i += 16) { AES_encrypt(data + i, crypted + i, &(csystem_data->ekey)); }
311 return len;
314 static void swap_lb(uint8_t *buff, int32_t len)
316 #if __BYTE_ORDER != __BIG_ENDIAN
317 return;
318 #endif
319 int32_t i;
320 uint8_t tmp;
322 for(i = 0; i < len / 2; i++)
324 tmp = buff[i * 2];
325 buff[i * 2] = buff[(i * 2) + 1];
326 buff[(i * 2) + 1] = tmp;
330 void __xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2)
332 uint32_t i;
333 switch(len)
335 case 16:
336 for(i = 0; i < 16; ++i)
338 data[i] = v1[i] ^ v2[i];
340 break;
342 case 8:
343 for(i = 0; i < 8; ++i)
345 data[i] = v1[i] ^ v2[i];
347 break;
349 case 4:
350 for(i = 0; i < 4; ++i)
352 data[i] = v1[i] ^ v2[i];
354 break;
356 default:
357 while(len--) { *data++ = *v1++ ^ *v2++; }
361 void cCamCryptVG_SetSeed(struct s_reader *reader)
363 #if __BYTE_ORDER != __BIG_ENDIAN
364 static const uint8_t key1[] =
366 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd5, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61, 0xd6,
367 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd6, 0x09, 0xd7, 0x15, 0xd7, 0x21, 0xd7,
368 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd7, 0x11, 0xd8, 0x23, 0xd8,
369 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7, 0xd8
371 static const uint8_t key2[] =
373 0x01, 0x00, 0xcf, 0x13, 0xe0, 0x60, 0x54, 0xac, 0xab, 0x99, 0xe6, 0x0c, 0x9f, 0x5b, 0x91, 0xb9,
374 0x72, 0x72, 0x4d, 0x5b, 0x5f, 0xd3, 0xb7, 0x5b, 0x01, 0x4d, 0xef, 0x9e, 0x6b, 0x8a, 0xb9, 0xd1,
375 0xc9, 0x9f, 0xa1, 0x2a, 0x8d, 0x86, 0xb6, 0xd6, 0x39, 0xb4, 0x64, 0x65, 0x13, 0x77, 0xa1, 0x0a,
376 0x0c, 0xcf, 0xb4, 0x2b, 0x3a, 0x2f, 0xd2, 0x09, 0x92, 0x15, 0x40, 0x47, 0x66, 0x5c, 0xda, 0xc9
378 #else
379 static const uint8_t key1[] =
381 0xd5, 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd6, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61,
382 0xd6, 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd7, 0x09, 0xd7, 0x15, 0xd7, 0x21,
383 0xd7, 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd8, 0x11, 0xd8, 0x23,
384 0xd8, 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7
386 static const uint8_t key2[] =
388 0x00, 0x01, 0x13, 0xcf, 0x60, 0xe0, 0xac, 0x54, 0x99, 0xab, 0x0c, 0xe6, 0x5b, 0x9f, 0xb9, 0x91,
389 0x72, 0x72, 0x5b, 0x4d, 0xd3, 0x5f, 0x5b, 0xb7, 0x4d, 0x01, 0x9e, 0xef, 0x8a, 0x6b, 0xd1, 0xb9,
390 0x9f, 0xc9, 0x2a, 0xa1, 0x86, 0x8d, 0xd6, 0xb6, 0xb4, 0x39, 0x65, 0x64, 0x77, 0x13, 0x0a, 0xa1,
391 0xcf, 0x0c, 0x2b, 0xb4, 0x2f, 0x3a, 0x09, 0xd2, 0x15, 0x92, 0x47, 0x40, 0x5c, 0x66, 0xc9, 0xda
393 #endif
394 struct videoguard_data *csystem_data = reader->csystem_data;
395 memcpy(csystem_data->cardkeys[1], key1, sizeof(csystem_data->cardkeys[1]));
396 memcpy(csystem_data->cardkeys[2], key2, sizeof(csystem_data->cardkeys[2]));
399 void cCamCryptVG_GetCamKey(struct s_reader *reader, uint16_t *tb2)
401 struct videoguard_data *csystem_data = reader->csystem_data;
402 uint16_t c = 1;
403 memset(tb2, 0, 64);
404 tb2[0] = 1;
405 int32_t i;
407 for(i = 0; i < 32; i++)
409 cCamCryptVG_LongMult(tb2, &c, csystem_data->cardkeys[1][i], 0);
411 swap_lb((uint8_t *)tb2, 64);
414 static void cCamCryptVG_PostProcess_Decrypt(struct s_reader *reader, uint8_t *rxbuff)
416 switch(rxbuff[0])
418 case 0xD0:
419 cCamCryptVG_Process_D0(reader, rxbuff, rxbuff + 5);
420 break;
422 case 0xD1:
423 cCamCryptVG_Process_D1(reader, rxbuff, rxbuff + 5, rxbuff + rxbuff[4] + 5);
424 break;
426 case 0xD3:
427 cCamCryptVG_Decrypt_D3(reader, rxbuff, rxbuff + 5, rxbuff + rxbuff[4] + 5);
428 break;
432 static void cCamCryptVG_Process_D0(struct s_reader *reader, const uint8_t *ins, uint8_t *data)
434 struct videoguard_data *csystem_data = reader->csystem_data;
436 switch(ins[1])
438 case 0xb4:
439 swap_lb(data, 64);
440 memcpy(csystem_data->cardkeys[0], data, sizeof(csystem_data->cardkeys[0]));
441 break;
443 case 0xbc:
445 swap_lb(data, 64);
446 const uint16_t *key1 = (const uint16_t *)csystem_data->cardkeys[1];
447 uint16_t key2[32];
448 memcpy(key2, csystem_data->cardkeys[2], sizeof(key2));
449 int32_t count2;
450 uint16_t iidata[32];
451 memcpy((uint8_t *)&iidata, data, 64);
453 for(count2 = 0; count2 < 32; count2++)
455 uint32_t rem = 0, divisor = key1[count2];
456 int8_t i;
458 for(i = 31; i >= 0; i--)
460 uint32_t x = iidata[i] | (rem << 16);
461 rem = (x % divisor) & 0xffff;
464 uint32_t carry = 1, t = val_by2on3(divisor) | 1;
466 while(t)
468 if(t & 1) { carry = ((carry * rem) % divisor) & 0xffff; }
469 rem = ((rem * rem) % divisor) & 0xffff;
470 t >>= 1;
472 cCamCryptVG_PartialMod(carry, count2, key2, key1);
475 uint16_t idatacount = 0;
476 int32_t i;
478 for(i = 31; i >= 0; i--)
480 cCamCryptVG_LongMult(iidata, &idatacount, key1[i], key2[i]);
483 memcpy(data, iidata, 64);
484 swap_lb(data, 64);
485 uint8_t stateD1[16];
486 cCamCryptVG_Reorder16A(stateD1, data);
487 cAES_SetKey(reader, stateD1);
488 break;
493 static void cCamCryptVG_Process_D1(struct s_reader *reader, const uint8_t *ins, uint8_t *data, const uint8_t *status)
495 struct videoguard_data *csystem_data = reader->csystem_data;
496 uint8_t iter[16], tmp[16];
498 memset(iter, 0, sizeof(iter));
499 memcpy(iter, ins, 5);
500 xor16(iter, csystem_data->stateD3A, iter);
501 memcpy(csystem_data->stateD3A, iter, sizeof(iter));
503 int32_t datalen = status - data;
504 int32_t datalen1 = datalen;
506 if(datalen < 0)
508 datalen1 += 15;
511 int32_t blocklen = datalen1 >> 4;
512 int32_t i;
513 int32_t iblock;
515 for(i = 0, iblock = 0; i < blocklen + 2; i++, iblock += 16)
517 uint8_t in[16];
518 int32_t docalc = 1;
520 if(blocklen == i && (docalc = datalen & 0xf))
522 memset(in, 0, sizeof(in));
523 memcpy(in, &data[iblock], datalen - (datalen1 & ~0xf));
525 else if(blocklen + 1 == i)
527 memset(in, 0, sizeof(in));
528 memcpy(&in[5], status, 2);
530 else
532 memcpy(in, &data[iblock], sizeof(in));
535 if(docalc)
537 xor16(iter, in, tmp);
538 cCamCryptVG_ReorderAndEncrypt(reader, tmp);
539 xor16(tmp, csystem_data->stateD3A, iter);
542 memcpy(csystem_data->stateD3A, tmp, 16);
545 static void cCamCryptVG_Decrypt_D3(struct s_reader *reader, uint8_t *ins, uint8_t *data, const uint8_t *status)
547 struct videoguard_data *csystem_data = reader->csystem_data;
549 if(ins[4] > 16)
551 ins[4] -= 16;
554 if(ins[1] == 0xbe)
556 memset(csystem_data->stateD3A, 0, sizeof(csystem_data->stateD3A));
559 uint8_t tmp[16];
560 memset(tmp, 0, sizeof(tmp));
561 memcpy(tmp, ins, 5);
562 xor16(tmp, csystem_data->stateD3A, csystem_data->stateD3A);
564 int32_t len1 = ins[4];
565 int32_t blocklen = len1 >> 4;
567 if(ins[1] != 0xbe)
569 blocklen++;
572 uint8_t iter[16], states[16][16];
573 memset(iter, 0, sizeof(iter));
575 int32_t blockindex;
576 for(blockindex = 0; blockindex < blocklen; blockindex++)
578 iter[0] += blockindex;
579 xor16(iter, csystem_data->stateD3A, iter);
580 cCamCryptVG_ReorderAndEncrypt(reader, iter);
581 xor16(iter, &data[blockindex * 16], states[blockindex]);
583 if(blockindex == (len1 >> 4))
585 int32_t c = len1 - (blockindex * 16);
586 if(c < 16)
588 memset(&states[blockindex][c], 0, 16 - c);
591 xor16(states[blockindex], csystem_data->stateD3A, csystem_data->stateD3A);
592 cCamCryptVG_RotateRightAndHash(csystem_data->stateD3A);
595 memset(tmp, 0, sizeof(tmp));
596 memcpy(tmp + 5, status, 2);
597 xor16(tmp, csystem_data->stateD3A, csystem_data->stateD3A);
598 cCamCryptVG_ReorderAndEncrypt(reader, csystem_data->stateD3A);
600 memcpy(csystem_data->stateD3A, status - 16, sizeof(csystem_data->stateD3A));
601 cCamCryptVG_ReorderAndEncrypt(reader, csystem_data->stateD3A);
603 memcpy(data, states[0], len1);
605 if(ins[1] == 0xbe)
607 cCamCryptVG_Reorder16A(tmp, states[0]);
608 cAES_SetKey(reader, tmp);
612 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader *reader, uint8_t *p)
614 uint8_t tmp[16];
615 cCamCryptVG_Reorder16A(tmp, p);
616 cAES_Encrypt(reader, tmp, 16, tmp);
617 cCamCryptVG_Reorder16A(p, tmp);
620 // reorder AAAABBBBCCCCDDDD to ABCDABCDABCDABCD
621 static void cCamCryptVG_Reorder16A(uint8_t *dest, const uint8_t *src)
623 int32_t i;
624 int32_t j;
625 int32_t k;
626 for(i = 0, k = 0; i < 4; i++)
628 for(j = i; j < 16; j += 4, k++)
630 dest[k] = src[j];
635 static void cCamCryptVG_LongMult(uint16_t *pData, uint16_t *pLen, uint32_t mult, uint32_t carry)
637 int32_t i;
638 for(i = 0; i < *pLen; i++)
640 carry += pData[i] * mult;
641 pData[i] = (uint16_t)carry;
642 carry >>= 16;
645 if(carry) { pData[(*pLen)++] = carry; }
648 static void cCamCryptVG_PartialMod(uint16_t val, uint32_t count, uint16_t *outkey, const uint16_t *inkey)
650 if(count)
652 uint32_t mod = inkey[count];
653 uint16_t mult = (inkey[count] - outkey[count - 1]) & 0xffff;
654 uint32_t i;
655 uint32_t ib1;
657 for(i = 0, ib1 = count - 2; i < count - 1; i++, ib1--)
659 uint32_t t = (inkey[ib1] * mult) % mod;
660 mult = t - outkey[ib1];
662 if(mult > t)
664 mult += mod;
667 mult += val;
669 if((val > mult) || (mod < mult))
671 mult -= mod;
673 outkey[count] = (outkey[count] * mult) % mod;
675 else
677 outkey[0] = val;
681 static void cCamCryptVG_RotateRightAndHash(uint8_t *p)
683 static const uint8_t table1[256] =
685 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
686 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
687 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
688 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
689 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
690 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
691 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
692 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
693 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
694 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
695 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
696 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
697 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
698 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
699 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
700 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
703 uint8_t t1 = p[15];
704 int32_t i;
706 for(i = 0; i < 16; i++)
708 uint8_t t2 = t1;
709 t1 = p[i];
710 p[i] = table1[(t1 >> 1) | ((t2 & 1) << 7)];
714 int32_t status_ok(const uint8_t *status)
716 //rdr_log(reader, "check status %02x%02x", status[0],status[1]);
717 return (status[0] == 0x90 || status[0] == 0x91) &&
718 (status[1] == 0x00 || status[1] == 0x01 || status[1] == 0x20 || status[1] == 0x21 ||
719 status[1] == 0x80 || status[1] == 0x81 || status[1] == 0xa0 || status[1] == 0xa1);
722 /*checksum for precam datas*/
723 int32_t checksum_ok(const uint8_t *ird_payload)
725 int32_t b, check = 0;
727 for (b = 0; b <= ird_payload[1]; b++)
729 check = (check + ird_payload[b]) & 0xFF;
732 if (ird_payload[ird_payload[1] + 1] == check)
734 return 1;
736 else
738 return 0; // Checksum error
742 void memorize_cmd_table(struct s_reader *reader, const uint8_t *mem, int32_t size)
744 struct videoguard_data *csystem_data = reader->csystem_data;
745 NULLFREE(csystem_data->cmd_table);
746 if(cs_malloc(&csystem_data->cmd_table, size))
748 memcpy(csystem_data->cmd_table, mem, size);
752 int32_t cmd_table_get_info(struct s_reader *reader, const uint8_t *cmd, uint8_t *rlen, uint8_t *rmode)
754 struct videoguard_data *csystem_data = reader->csystem_data;
755 struct s_CmdTabEntry *pcte = csystem_data->cmd_table->e;
756 int32_t i;
758 for(i = 0; i < csystem_data->cmd_table->Nentries; i++, pcte++)
760 if(cmd[1] == pcte->cmd)
762 *rlen = pcte->len;
763 *rmode = pcte->mode;
764 return 1;
767 return 0;
770 int32_t cmd_exists(struct s_reader *reader, const uint8_t *cmd)
772 struct videoguard_data *csystem_data = reader->csystem_data;
773 struct s_CmdTabEntry *pcte = csystem_data->cmd_table->e;
774 int32_t i;
776 for(i = 0; i < csystem_data->cmd_table->Nentries; i++, pcte++)
778 if(cmd[1] == pcte->cmd)
780 return 1;
783 return 0;
786 int32_t read_cmd_len(struct s_reader *reader, const uint8_t *cmd)
788 def_resp;
789 uint8_t cmd2[5];
790 memcpy(cmd2, cmd, 5);
792 if(cmd2[0] == 0xD3) // use classD1 for length request of classD3
794 cmd2[0] = 0xD1;
796 cmd2[3] |= 0x80;
797 cmd2[4] = 1;
799 uint8_t rxbuff[8];
800 memcpy(rxbuff, cmd2, 5);
802 // some card reply with L 91 00 (L being the command length).
803 if(!write_cmd_vg(cmd2, NULL) || !status_ok(cta_res + 1) || cta_res[0] == 0)
805 if(cta_res[0] == 0) // some cards reply len=0x00 for not supported ins
807 rdr_log_dbg(reader, D_READER, "failed to read %02x%02x cmd length (%02x %02x)",
808 cmd[1], cmd[2], cta_res[1], cta_res[2]);
810 else // others reply only status byte
812 rdr_log_dbg(reader, D_READER, "failed to read %02x%02x cmd length (%02x %02x)",
813 cmd[1], cmd[2], cta_res[0], cta_res[1]);
816 memcpy(rxbuff + 5, cta_res, 3);
817 cCamCryptVG_PostProcess_Decrypt(reader, rxbuff);
819 return -1;
822 memcpy(rxbuff + 5, cta_res, 3);
823 cCamCryptVG_PostProcess_Decrypt(reader, rxbuff);
825 return cta_res[0];
828 int32_t do_cmd(struct s_reader *reader, const uint8_t *ins, const uint8_t *txbuff, uint8_t *rxbuff, uint8_t *cta_res)
830 uint16_t cta_lr;
831 uint8_t ins2[5];
832 memcpy(ins2, ins, 5);
833 uint8_t len = 0, mode = 0;
835 if(cmd_table_get_info(reader, ins2, &len, &mode))
837 if(len == 0xFF && mode == 2)
839 if(ins2[4] == 0)
841 ins2[4] = len = read_cmd_len(reader, ins2);
842 if(len == 0xFF)
844 return -1;
848 else if((mode != 0) && ((ins2[3] != 0x7f) && (ins2[4] != 0x02)))
850 ins2[4] = len;
854 if(ins2[0] == 0xd3)
856 if(ins2[4] == 0)
858 return 0;
860 ins2[4] += 16;
863 len = ins2[4];
864 uint8_t tmp[264];
866 if(rxbuff == NULL)
868 rxbuff = tmp;
871 if(mode > 1)
873 if(!write_cmd_vg(ins2, NULL) || !status_ok(cta_res + len))
875 return -1;
878 memcpy(rxbuff, ins2, 5);
879 memcpy(rxbuff + 5, cta_res, len);
880 memcpy(rxbuff + 5 + len, cta_res + len, 2);
882 else
884 if(!write_cmd_vg(ins2, txbuff) || !status_ok(cta_res))
886 return -2;
889 memcpy(rxbuff, ins2, 5);
890 memcpy(rxbuff + 5, txbuff, len);
891 memcpy(rxbuff + 5 + len, cta_res, 2);
893 cCamCryptVG_PostProcess_Decrypt(reader, rxbuff);
895 if(ins2[0] == 0xd3)
897 rdr_log_dump_dbg(reader, D_READER, rxbuff + 5, rxbuff[4], "Decrypted payload");
900 return len;
903 void rev_date_calc_tm(const uint8_t *Date, struct tm *timeinfo , int32_t base_year)
905 timeinfo->tm_year = Date[0] / 12 + base_year - 1900; // tm year starts at 1900
906 timeinfo->tm_mon = Date[0] % 12; // tm month starts with 0
907 timeinfo->tm_mday = Date[1] & 0x1f;
908 timeinfo->tm_hour = Date[2] / 8;
909 timeinfo->tm_min = (0x100 * (Date[2] - timeinfo->tm_hour * 8) + Date[3]) / 32;
910 timeinfo->tm_sec = (Date[3] - timeinfo->tm_min * 32) * 2;
913 int32_t videoguard_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
915 int32_t i;
916 int32_t serial_count = ((ep->emm[3] >> 4) & 3) + 1;
917 int32_t serial_len = (ep->emm[3] & 0x80) ? 3 : 4;
918 uint8_t emmtype = (ep->emm[3] & VG_EMMTYPE_MASK) >> 6;
920 switch(emmtype)
922 case VG_EMMTYPE_G:
923 rdr_log_dbg(rdr, D_EMM, "GLOBAL");
924 ep->type = GLOBAL;
925 return 1;
927 case VG_EMMTYPE_U:
928 case VG_EMMTYPE_S:
929 rdr_log_dbg(rdr, D_EMM, "%s", (emmtype == VG_EMMTYPE_U) ? "UNIQUE" : "SHARED");
930 ep->type = emmtype;
931 if(ep->emm[1] == 0) // detected UNIQUE EMM from cccam (there is no serial)
933 rdr_log_dbg(rdr, D_EMM, "CCCam unique EMM detected, no serial available, skipping filter check");
934 ep->skip_filter_check = 1;
935 return 1;
937 for(i = 0; i < serial_count; i++)
939 if(!memcmp(&ep->emm[i * 4 + 4], rdr->hexserial + 2, serial_len))
941 memcpy(ep->hexserial, &ep->emm[i * 4 + 4], serial_len);
942 return 1;
945 return 0; // if UNIQUE or SHARED but no serial match return FALSE
947 default:
948 // remote emm without serial
949 rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
950 ep->type = UNKNOWN;
951 return 1;
955 int32_t videoguard_do_emm(struct s_reader *reader, EMM_PACKET *ep, uint8_t CLA, void (*read_tiers)(struct s_reader *),
956 int32_t (*docmd)(struct s_reader *, const uint8_t *ins, const uint8_t *txbuff, uint8_t *rxbuff, uint8_t *cta_res))
958 uint8_t cta_res[CTA_RES_LEN];
959 uint8_t ins42[5] = { CLA, 0x42, 0x00, 0x00, 0xFF };
960 uint8_t *EmmIrdHeader;
961 int32_t rc = SKIPPED;
962 int32_t nsubs = ((ep->emm[3] & 0x30) >> 4) + 1;
963 int32_t offs = 4;
964 int32_t emmv2 = 0;
965 int32_t position, ua_position = -1;
966 int32_t serial_len = (ep->type == SHARED) ? 3 : 4;
967 int32_t vdrsc_fix = 0;
969 if(ep->type == UNIQUE || ep->type == SHARED)
971 if(ep->emm[1] == 0x00) // cccam sends emm-u without UA
973 nsubs = 1;
974 ua_position = 0;
976 else
978 int32_t i;
979 for(i = 0; i < nsubs; ++i)
981 if(memcmp(&ep->emm[4 + i * 4], &reader->hexserial[2], serial_len) == 0)
983 ua_position = i;
984 break;
987 offs += nsubs * 4;
990 if(ua_position == -1)
992 return ERROR;
996 if(ep->emm[offs] == 0x00 && (ep->emm[offs + 1] == 0x00 || ep->emm[offs + 1] == 0x01)) // unmodified emm from dvbapi
998 emmv2 = ep->emm[offs + 1];
999 offs += 2 + 1 + emmv2; // skip sub-emm len (2 bytes sub-emm len if 0x01);
1002 for(position = 0; position < nsubs && offs + 2 < ep->emmlen; ++position)
1004 if(ep->emm[offs] > 0x07) // workaround for mgcamd and emmv2
1006 ++offs;
1009 if(ep->emm[offs] == 0x02 || ep->emm[offs] == 0x03 || ep->emm[offs] == 0x07)
1011 if(ep->emm[offs+1] != 0) // Checksum test for sub-packets emm:
1013 EmmIrdHeader = ep->emm + offs; // example:
1014 int32_t chk; // 827097300000
1015 chk = checksum_ok(EmmIrdHeader); // D002 0602C317ABA02F 1690144004A6... chk=2F
1016 if (chk != 1) // D607 0E03A3010325070102810002000778 1B90154004A9... chk=78
1017 { // D607 0E03A301032507010281000200097A 1B9015400441... chk=7A
1018 return rc;
1022 if(ep->emm[offs] == 0x03)
1024 if(position == ua_position || vdrsc_fix)
1026 videoguard_mail_msg(reader, &ep->emm[offs + 2]);
1027 return rc;
1029 else
1031 offs += ep->emm[offs + 1] + 2;
1032 if(!(offs + 1 < ep->emmlen))
1034 return rc;
1037 if(ep->emm[offs] == 0x00 && (ep->emm[offs + 1] == 0x00 || ep->emm[offs + 1] == 0x01))
1039 offs += 2 + 1 + emmv2;
1041 continue;
1045 offs += ep->emm[offs + 1] + 2;
1046 if(!(offs + 1 < ep->emmlen))
1048 return rc;
1051 if(ep->emm[offs] != 0)
1053 if(ep->type == GLOBAL || vdrsc_fix || position == ua_position)
1055 ins42[4] = ep->emm[offs];
1056 int32_t l = (*docmd)(reader, ins42, &ep->emm[offs + 1], NULL, cta_res);
1057 rc = (l > 0 && status_ok(cta_res)) ? OK : ERROR;
1058 rdr_log_dbg(reader, D_EMM, "request return code : %02X%02X", cta_res[0], cta_res[1]);
1060 if(status_ok(cta_res) && (cta_res[1] & 0x01))
1062 (*read_tiers)(reader);
1066 offs += ep->emm[offs] + 1;
1067 if(offs < ep->emmlen && ep->emm[offs] == 0x00)
1069 ++offs;
1073 offs += 1 + emmv2;
1074 if(vdrsc_fix)
1076 --position;
1079 else
1081 return rc;
1084 return rc;
1087 uint8_t videoguard_get_emm_filter_address_byte(uint8_t isUnique, uint32_t n)
1089 uint8_t ret;
1090 switch(n)
1092 default:
1093 case 0:
1094 // do not filter by sub-emm count
1095 ret = 0;
1096 break;
1098 case 1:
1099 // unused
1100 // here we would need two filters,
1101 // one with sub-emm count 1x, and one with 01
1102 ret = 0x10;
1103 break;
1105 case 2:
1106 // filter sub-emm count with 1x
1107 ret = 0x20;
1108 break;
1110 case 3:
1111 // filter sub-emm count with 11
1112 ret = 0x30;
1113 break;
1116 if(isUnique)
1118 ret |= 0x40;
1120 else //shared
1122 ret |= 0x80;
1125 return ret;
1128 uint8_t videoguard_get_emm_filter_address_mask(uint32_t n)
1130 uint8_t ret = 0xC0;
1131 switch(n)
1133 default:
1134 case 0:
1135 // at least 1 sub-emm is always present, so we do not care
1136 break;
1138 case 1:
1139 // must have 2 sub-emms or more (01, 10, 11, but not 00)
1140 // we could create a 1x and 01 filter here,
1141 // but atm we do not care, to keep the filter number low
1142 break;
1144 case 2:
1145 // must have 3 sub-emms or more (10, 11, but not 00, 01)
1146 ret |= 0x20;
1147 break;
1149 case 3:
1150 // must have 4 sub-emms (11)
1151 ret |= 0x30;
1152 break;
1155 return ret;
1158 int32_t videoguard_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
1160 if(*emm_filters == NULL)
1162 const unsigned int max_filter_count = 7;
1163 if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
1165 return ERROR;
1168 struct s_csystem_emm_filter *filters = *emm_filters;
1169 *filter_count = 0;
1170 int32_t idx = 0;
1171 uint32_t n;
1173 for(n = 0; n < 3; ++n)
1175 filters[idx].type = EMM_UNIQUE;
1176 filters[idx].enabled = 1;
1177 filters[idx].filter[0] = 0x82;
1178 filters[idx].mask[0] = 0xFF;
1179 filters[idx].filter[1] = videoguard_get_emm_filter_address_byte(1, n);
1180 filters[idx].mask[1] = videoguard_get_emm_filter_address_mask(n);
1181 memcpy(&filters[idx].filter[2 + 4 * n], rdr->hexserial + 2, 4);
1182 memset(&filters[idx].mask[2 + 4 * n], 0xFF, 4);
1183 idx++;
1186 // fourth serial position does not fit within the 16bytes demux filter
1187 for(n = 0; n < 3; ++n)
1189 filters[idx].type = EMM_SHARED;
1190 filters[idx].enabled = 1;
1191 filters[idx].filter[0] = 0x82;
1192 filters[idx].mask[0] = 0xFF;
1193 filters[idx].filter[1] = videoguard_get_emm_filter_address_byte(0, n);
1194 filters[idx].mask[1] = videoguard_get_emm_filter_address_mask(n);
1195 memcpy(&filters[idx].filter[2 + 4 * n], rdr->hexserial + 2, 3);
1196 memset(&filters[idx].mask[2 + 4 * n], 0xFF, 3);
1197 idx++;
1200 // fourth serial position does not fit within the 16bytes demux filter
1201 filters[idx].type = EMM_GLOBAL;
1202 filters[idx].enabled = 1;
1203 filters[idx].filter[0] = 0x82;
1204 filters[idx].mask[0] = 0xFF;
1205 filters[idx].filter[1] = 0x00;
1206 filters[idx].mask[1] = 0xC0;
1207 idx++;
1208 *filter_count = idx;
1210 return OK;
1213 static MAILMSG *find_msg(uint16_t caid, uint32_t serial, uint16_t date, uint16_t msg_id)
1215 MAILMSG *msg;
1216 LL_ITER it = ll_iter_create(vg_msgs);
1217 while((msg = (MAILMSG *)ll_iter_next(&it)))
1219 if(msg->caid == caid && msg->serial == serial && msg->date == date && msg->id == msg_id)
1221 return msg;
1224 return 0;
1227 static void write_msg(struct s_reader *reader, MAILMSG *msg, uint32_t baseyear)
1229 FILE *fp = fopen(cfg.mailfile, "a");
1230 if(fp == 0)
1232 rdr_log(reader, "Cannot open mailfile %s", cfg.mailfile);
1233 return;
1236 uint16_t i;
1237 for(i = 0; i < msg->len - 1; ++i)
1239 if(msg->message[i] == 0x00 && msg->message[i + 1] == 0x32)
1241 msg->subject = &msg->message[i + 3];
1242 break;
1246 int32_t year = (msg->date >> 8) / 12 + baseyear;
1247 int32_t mon = (msg->date >> 8) % 12 + 1;
1248 int32_t day = msg->date & 0x1f;
1250 fprintf(fp, "%04X:%08X:%02d/%02d/%04d:%04X:\"%s\":\"%s\"\n",
1251 msg->caid,
1252 msg->serial,
1253 day,
1254 mon,
1255 year,
1256 msg->id,
1257 msg->subject,
1258 msg->message);
1260 fclose(fp);
1261 NULLFREE(msg->message);
1262 msg->message = msg->subject = 0;
1263 msg->written = 1;
1266 static void msgs_init(uint32_t baseyear)
1268 vg_msgs = ll_create("vg_msgs");
1269 FILE *fp = fopen(cfg.mailfile, "r");
1270 if(fp == 0)
1272 return;
1275 int32_t year, mon, day;
1276 char buffer[2048];
1278 while(fgets(buffer, sizeof(buffer), fp))
1280 MAILMSG *msg;
1281 if(!cs_malloc(&msg, sizeof(MAILMSG)))
1283 fclose(fp);
1284 return;
1287 sscanf(buffer, "%04hX:%08X:%02d/%02d/%04d:%04hX", &msg->caid, &msg->serial, &day, &mon, &year, &msg->id);
1288 year -= baseyear;
1289 msg->date = ((year * 12) + mon - 1) << 8 | day;
1290 msg->message = msg->subject = 0;
1291 msg->written = 1;
1292 ll_append(vg_msgs, msg);
1294 fclose(fp);
1297 void videoguard_mail_msg(struct s_reader *rdr, uint8_t *data)
1299 if(cfg.disablemail)
1301 return;
1304 struct videoguard_data *csystem_data = rdr->csystem_data;
1306 if(vg_msgs == 0)
1308 msgs_init(csystem_data->card_baseyear);
1311 if(data[0] != 0xFF || data[1] != 0xFF)
1313 return;
1316 uint16_t msg_id = (data[2] << 8) | data[3];
1317 uint8_t idx = data[4] & 0x0F;
1318 int32_t msg_size = data[5] * 10 + 2;
1319 uint16_t date = (data[9] << 8) | data[10];
1320 int32_t submsg_len = data[12] - 2;
1321 uint16_t submsg_idx = (data[13] << 8) | data[14];
1322 uint32_t serial = (rdr->hexserial[2] << 24) | (rdr->hexserial[3] << 16) | (rdr->hexserial[4] << 8) | rdr->hexserial[5];
1323 MAILMSG *msg = find_msg(rdr->caid, serial, date, msg_id);
1325 if(msg == 0)
1327 if(!cs_malloc(&msg, sizeof(MAILMSG)))
1329 return;
1331 msg->caid = rdr->caid;
1332 msg->serial = serial;
1333 msg->date = date;
1334 msg->id = msg_id;
1335 msg->nsubs = (data[4] & 0xF0) >> 4;
1336 msg->mask = 1 << idx;
1337 msg->written = 0;
1338 msg->len = submsg_len;
1340 if(!cs_malloc(&msg->message, msg_size))
1342 NULLFREE(msg);
1343 return;
1346 memset(msg->message, 0, msg_size);
1347 memcpy(&msg->message[submsg_idx], &data[15], submsg_len);
1348 msg->subject = 0;
1349 ll_append(vg_msgs, msg);
1351 else
1353 if(msg->written == 1 || msg->mask & (1 << idx))
1355 return;
1358 msg->mask |= 1 << idx;
1359 msg->len += submsg_len;
1360 memcpy(&msg->message[submsg_idx], &data[15], submsg_len);
1363 if(msg->mask == (1 << msg->nsubs) - 1)
1365 write_msg(rdr, msg, csystem_data->card_baseyear);
1368 #endif