|
@@ -24,20 +24,16 @@
|
24
|
24
|
#include <netinet/tcp.h>
|
25
|
25
|
#include <arpa/inet.h>
|
26
|
26
|
|
27
|
|
-#include <openssl/aes.h>
|
28
|
|
-#include <openssl/md5.h>
|
29
|
|
-
|
30
|
27
|
#include <dvbcsa/dvbcsa.h>
|
31
|
28
|
|
32
|
29
|
#include "libfuncs/libfuncs.h"
|
33
|
|
-#include "libtsfuncs/tsfuncs.h"
|
34
|
30
|
|
35
|
31
|
#include "data.h"
|
36
|
32
|
#include "util.h"
|
37
|
33
|
#include "camd.h"
|
38
|
34
|
#include "notify.h"
|
39
|
35
|
|
40
|
|
-static int connect_to(struct in_addr ip, int port) {
|
|
36
|
+int camd_tcp_connect(struct in_addr ip, int port) {
|
41
|
37
|
ts_LOGf("CAM | Connecting to server %s:%d\n", inet_ntoa(ip), port);
|
42
|
38
|
|
43
|
39
|
int fd = socket(PF_INET, SOCK_STREAM, 0);
|
|
@@ -64,112 +60,22 @@ static int connect_to(struct in_addr ip, int port) {
|
64
|
60
|
return fd;
|
65
|
61
|
}
|
66
|
62
|
|
67
|
|
-static void camd35_init_auth(struct ts *ts) {
|
68
|
|
- struct camd35 *c = &ts->camd35;
|
69
|
|
- unsigned char dump[16];
|
70
|
|
-
|
71
|
|
- if (c->auth_token)
|
72
|
|
- return;
|
73
|
|
-
|
74
|
|
- c->auth_token = crc32(0L, MD5((unsigned char *)c->user, strlen(c->user), dump), 16);
|
75
|
|
-
|
76
|
|
- MD5((unsigned char *)c->pass, strlen(c->pass), dump);
|
77
|
|
-
|
78
|
|
- AES_set_encrypt_key(dump, 128, &c->aes_encrypt_key);
|
79
|
|
- AES_set_decrypt_key(dump, 128, &c->aes_decrypt_key);
|
80
|
|
-}
|
81
|
|
-
|
82
|
|
-static int camd35_connect(struct ts *ts) {
|
83
|
|
- struct camd35 *c = &ts->camd35;
|
84
|
|
- if (c->server_fd < 0)
|
85
|
|
- c->server_fd = connect_to(c->server_addr, c->server_port);
|
86
|
|
- return c->server_fd;
|
87
|
|
-}
|
88
|
|
-
|
89
|
|
-static void camd35_disconnect(struct ts *ts) {
|
90
|
|
- struct camd35 *c = &ts->camd35;
|
91
|
|
- shutdown_fd(&c->server_fd);
|
92
|
|
-}
|
93
|
|
-
|
94
|
|
-static int camd35_reconnect(struct ts *ts) {
|
95
|
|
- camd35_disconnect(ts);
|
96
|
|
- return camd35_connect(ts);
|
97
|
|
-}
|
98
|
|
-
|
99
|
|
-static int camd35_recv(struct camd35 *c, uint8_t *data, int *data_len) {
|
100
|
|
- int i;
|
101
|
|
-
|
102
|
|
- // Read AUTH token
|
103
|
|
- ssize_t r = fdread(c->server_fd, (char *)data, 4);
|
104
|
|
- if (r < 4)
|
105
|
|
- return -1;
|
106
|
|
- uint32_t auth_token = (((data[0] << 24) | (data[1] << 16) | (data[2]<<8) | data[3]) & 0xffffffffL);
|
107
|
|
- if (auth_token != c->auth_token)
|
108
|
|
- ts_LOGf("WARN: recv auth 0x%08x != camd35_auth 0x%08x\n", auth_token, c->auth_token);
|
109
|
|
-
|
110
|
|
- *data_len = 256;
|
111
|
|
- for (i = 0; i < *data_len; i += 16) { // Read and decrypt payload
|
112
|
|
- fdread(c->server_fd, (char *)data + i, 16);
|
113
|
|
- AES_decrypt(data + i, data + i, &c->aes_decrypt_key);
|
114
|
|
- if (i == 0)
|
115
|
|
- *data_len = boundary(4, data[1] + 20); // Initialize real data length
|
116
|
|
- }
|
117
|
|
- return *data_len;
|
118
|
|
-}
|
119
|
|
-
|
120
|
63
|
static int camd35_recv_cw(struct ts *ts) {
|
121
|
64
|
struct camd35 *c = &ts->camd35;
|
122
|
65
|
struct timeval tv1, tv2, last_ts_keyset;
|
123
|
66
|
static uint8_t invalid_cw[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
124
|
|
- uint8_t *data = c->buf;
|
125
|
|
- int data_len = 0;
|
126
|
|
- int ret = 0;
|
|
67
|
+ uint16_t ca_id = 0;
|
|
68
|
+ uint16_t idx = 0;
|
|
69
|
+ int ret;
|
127
|
70
|
|
128
|
71
|
gettimeofday(&tv1, NULL);
|
129
|
|
-READ:
|
130
|
|
- ret = camd35_recv(c, data, &data_len);
|
131
|
|
- if (ret < 0) {
|
132
|
|
- ts_LOGf("ERR | No code word has been received (ret = %d)\n", ret);
|
133
|
|
- camd35_reconnect(ts);
|
|
72
|
+ ret = c->ops.get_cw(c, &ca_id, &idx, c->key->cw);
|
|
73
|
+ if (ret <= 0)
|
134
|
74
|
return ret;
|
135
|
|
- }
|
136
|
|
-
|
137
|
|
- // EMM request, ignore it. Sometimes OSCAM sends two EMM requests after CW
|
138
|
|
- if (data[0] == 0x05)
|
139
|
|
- goto READ;
|
140
|
|
-
|
141
|
|
- if (data[0] != 0x01) {
|
142
|
|
- ts_LOGf("ERR | Unexpected server response on code word request (ret data[0] == 0x%02x /%s/)\n",
|
143
|
|
- data[0],
|
144
|
|
- data[0] == 0x08 ? "No card" :
|
145
|
|
- data[0] == 0x44 ? "No code word found" : "Unknown err");
|
146
|
|
- c->ecm_recv_errors++;
|
147
|
|
- usleep(10000);
|
148
|
|
- if (c->ecm_recv_errors >= ECM_RECV_ERRORS_LIMIT) {
|
149
|
|
- c->key->is_valid_cw = 0;
|
150
|
|
- memcpy(c->key->cw, invalid_cw, 16);
|
151
|
|
- }
|
152
|
|
- return 0;
|
153
|
|
- }
|
154
|
|
-
|
155
|
|
- if (data_len < 48) {
|
156
|
|
- ts_LOGf("ERR | Code word data_len (%d) mismatch != 48\n", data_len);
|
157
|
|
- return 0;
|
158
|
|
- }
|
159
|
|
-
|
160
|
|
- if (data[1] < 0x10) {
|
161
|
|
- ts_LOGf("ERR | Code word len (%d) mismatch != 16\n", data[1]);
|
162
|
|
- return 0;
|
163
|
|
- }
|
164
|
75
|
gettimeofday(&tv2, NULL);
|
165
|
76
|
|
166
|
|
- uint16_t ca_id = (data[10] << 8) | data[11];
|
167
|
|
- uint16_t idx = (data[16] << 8) | data[17];
|
168
|
|
- uint8_t *cw = data + 20;
|
169
|
|
- memcpy(c->key->cw, cw, 16);
|
170
|
|
-
|
171
|
77
|
char cw_dump[16 * 6];
|
172
|
|
- ts_hex_dump_buf(cw_dump, 16 * 6, cw, 16, 0);
|
|
78
|
+ ts_hex_dump_buf(cw_dump, 16 * 6, c->key->cw, 16, 0);
|
173
|
79
|
|
174
|
80
|
int valid_cw = memcmp(c->key->cw, invalid_cw, 16) != 0;
|
175
|
81
|
if (!c->key->is_valid_cw && valid_cw) {
|
|
@@ -209,52 +115,13 @@ READ:
|
209
|
115
|
|
210
|
116
|
#undef ERR
|
211
|
117
|
|
212
|
|
-
|
213
|
|
-static int camd35_send_buf(struct ts *ts, int data_len) {
|
214
|
|
- struct camd35 *c = &ts->camd35;
|
215
|
|
- int i;
|
216
|
|
- uint8_t *bdata = c->buf + 4; // Leave space for auth token
|
217
|
|
-
|
218
|
|
- camd35_connect(ts);
|
219
|
|
- camd35_init_auth(ts);
|
220
|
|
-
|
221
|
|
- memmove(bdata, c->buf, data_len); // Move data
|
222
|
|
- init_4b(c->auth_token, c->buf); // Put authentication token
|
223
|
|
-
|
224
|
|
- for (i = 0; i < data_len; i += 16) // Encrypt payload
|
225
|
|
- AES_encrypt(bdata + i, bdata + i, &c->aes_encrypt_key);
|
226
|
|
-
|
227
|
|
- return fdwrite(c->server_fd, (char *)c->buf, data_len + 4);
|
228
|
|
-}
|
229
|
|
-
|
230
|
|
-static void camd35_buf_init(struct camd35 *c, uint8_t *data, int data_len) {
|
231
|
|
- memset(c->buf, 0, CAMD35_HDR_LEN); // Reset header
|
232
|
|
- memset(c->buf + CAMD35_HDR_LEN, 0xff, CAMD35_BUF_LEN - CAMD35_HDR_LEN); // Reset data
|
233
|
|
- c->buf[1] = data_len; // Data length
|
234
|
|
- init_4b(crc32(0L, data, data_len), c->buf + 4); // Data CRC is at buf[4]
|
235
|
|
- memcpy(c->buf + CAMD35_HDR_LEN, data, data_len); // Copy data to buf
|
236
|
|
-}
|
237
|
|
-
|
238
|
118
|
static int camd35_send_ecm(struct ts *ts, uint16_t ca_id, uint16_t service_id, uint16_t idx, uint8_t *data, uint8_t data_len) {
|
239
|
119
|
struct camd35 *c = &ts->camd35;
|
240
|
|
- uint32_t provider_id = 0;
|
241
|
|
- int to_send = boundary(4, CAMD35_HDR_LEN + data_len);
|
242
|
|
-
|
243
|
|
- camd35_buf_init(c, data, (int)data_len);
|
244
|
|
-
|
245
|
|
- c->buf[0] = 0x00; // CMD ECM request
|
246
|
|
- init_2b(service_id , c->buf + 8);
|
247
|
|
- init_2b(ca_id , c->buf + 10);
|
248
|
|
- init_4b(provider_id, c->buf + 12);
|
249
|
|
- init_2b(idx , c->buf + 16);
|
250
|
|
- c->buf[18] = 0xff;
|
251
|
|
- c->buf[19] = 0xff;
|
252
|
|
-
|
253
|
|
- int ret = camd35_send_buf(ts, to_send);
|
|
120
|
+ int ret = c->ops.do_ecm(c, ca_id, service_id, idx, data, data_len);
|
254
|
121
|
if (ret <= 0) {
|
255
|
122
|
ts_LOGf("ERR | Error sending ecm packet, reconnecting to camd.\n");
|
256
|
123
|
ts->is_cw_error = 1;
|
257
|
|
- camd35_reconnect(ts);
|
|
124
|
+ c->ops.reconnect(c);
|
258
|
125
|
return ret;
|
259
|
126
|
}
|
260
|
127
|
|
|
@@ -275,21 +142,12 @@ static int camd35_send_ecm(struct ts *ts, uint16_t ca_id, uint16_t service_id, u
|
275
|
142
|
|
276
|
143
|
static int camd35_send_emm(struct ts *ts, uint16_t ca_id, uint8_t *data, uint8_t data_len) {
|
277
|
144
|
struct camd35 *c = &ts->camd35;
|
278
|
|
- uint32_t prov_id = 0;
|
279
|
|
- int to_send = boundary(4, CAMD35_HDR_LEN + data_len);
|
280
|
|
-
|
281
|
|
- camd35_buf_init(c, data, (int)data_len);
|
282
|
|
-
|
283
|
|
- c->buf[0] = 0x06; // CMD incomming EMM
|
284
|
|
- init_2b(ca_id , c->buf + 10);
|
285
|
|
- init_4b(prov_id, c->buf + 12);
|
286
|
|
-
|
287
|
|
- int ret = camd35_send_buf(ts, to_send);
|
|
145
|
+ int ret = c->ops.do_emm(c, ca_id, data, data_len);
|
288
|
146
|
if (ret < 0) {
|
289
|
147
|
c->emm_recv_errors++;
|
290
|
148
|
if (c->emm_recv_errors >= EMM_RECV_ERRORS_LIMIT) {
|
291
|
149
|
ts_LOGf("ERR | Error sending emm packet, reconnecting to camd.\n");
|
292
|
|
- camd35_reconnect(ts);
|
|
150
|
+ c->ops.reconnect(c);
|
293
|
151
|
c->emm_recv_errors = 0;
|
294
|
152
|
}
|
295
|
153
|
} else {
|
|
@@ -374,25 +232,27 @@ void camd_msg_process(struct ts *ts, struct camd_msg *msg) {
|
374
|
232
|
}
|
375
|
233
|
|
376
|
234
|
void camd_start(struct ts *ts) {
|
377
|
|
- camd35_connect(ts);
|
|
235
|
+ struct camd35 *c = &ts->camd35;
|
|
236
|
+ c->ops.connect(c);
|
378
|
237
|
// The input is not file, process messages using async thread
|
379
|
238
|
if (!(ts->input.type == FILE_IO && ts->input.fd != 0)) {
|
380
|
|
- ts->camd35.req_queue = queue_new();
|
381
|
|
- ts->camd35.ecm_queue = queue_new();
|
382
|
|
- ts->camd35.emm_queue = queue_new();
|
383
|
|
- pthread_create(&ts->camd35.thread, NULL , &camd_thread, ts);
|
|
239
|
+ c->req_queue = queue_new();
|
|
240
|
+ c->ecm_queue = queue_new();
|
|
241
|
+ c->emm_queue = queue_new();
|
|
242
|
+ pthread_create(&c->thread, NULL , &camd_thread, ts);
|
384
|
243
|
}
|
385
|
244
|
}
|
386
|
245
|
|
387
|
246
|
void camd_stop(struct ts *ts) {
|
|
247
|
+ struct camd35 *c = &ts->camd35;
|
388
|
248
|
ts->camd_stop = 1;
|
389
|
|
- if (ts->camd35.thread) {
|
390
|
|
- queue_wakeup(ts->camd35.req_queue);
|
391
|
|
- pthread_join(ts->camd35.thread, NULL);
|
392
|
|
- queue_free(&ts->camd35.req_queue);
|
393
|
|
- queue_free(&ts->camd35.ecm_queue);
|
394
|
|
- queue_free(&ts->camd35.emm_queue);
|
395
|
|
- ts->camd35.thread = 0;
|
|
249
|
+ if (c->thread) {
|
|
250
|
+ queue_wakeup(c->req_queue);
|
|
251
|
+ pthread_join(c->thread, NULL);
|
|
252
|
+ queue_free(&c->req_queue);
|
|
253
|
+ queue_free(&c->ecm_queue);
|
|
254
|
+ queue_free(&c->emm_queue);
|
|
255
|
+ c->thread = 0;
|
396
|
256
|
}
|
397
|
|
- camd35_disconnect(ts);
|
|
257
|
+ c->ops.disconnect(c);
|
398
|
258
|
}
|