source: trunk/module-cccam-cacheex.c@ 11518

Last change on this file since 11518 was 11518, checked in by Gorgone Impertinence, 4 years ago

DVBAPI:
Fixed bug in dvbapi not releasing used descramblers in stapi, coolapi and gxapi boxes
Increased MAX_STREAM_INDICES back to 32 (it must be equal to MAX_STREAM_PIDS)
Modified the get_emm_filter_adv() function to accept more arguments

OTHER:
Cosmetics to module-cccam.c and module-cccam-cacheex.x
Removed some emu specific code not needed anymore

File size: 10.9 KB
Line 
1#define MODULE_LOG_PREFIX "cccam"
2
3#include "globals.h"
4#include "oscam-array.h"
5
6#if defined(CS_CACHEEX) && defined(MODULE_CCCAM)
7
8#include "module-cacheex.h"
9#include "module-cccam-data.h"
10#include "module-cccam-cacheex.h"
11#include "oscam-cache.h"
12#include "oscam-client.h"
13#include "oscam-ecm.h"
14#include "oscam-string.h"
15#include "oscam-chk.h"
16#include "oscam-reader.h"
17
18#define CSP_HASH_SWAP(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
19 ((((uint32_t)(n) & 0xFF00)) << 8) | \
20 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
21 ((((uint32_t)(n) & 0xFF000000)) >> 24))
22
23extern int32_t cc_cli_connect(struct s_client *cl);
24extern int32_t cc_cmd_send(struct s_client *cl, uint8_t *buf, int32_t len, cc_msg_type_t cmd);
25
26void cc_cacheex_filter_out(struct s_client *cl)
27{
28 struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
29 int i = 0, j;
30 CECSPVALUETAB *filter;
31 int32_t size = 482; // minimal size, keep it <= 512 for max UDP packet size without fragmentation
32 uint8_t buf[482];
33 memset(buf, 0, sizeof(buf));
34
35 if(rdr && rdr->cacheex.mode == 2) // mode == 2 send filters from rdr
36 {
37 filter = &rdr->cacheex.filter_caidtab;
38 }
39 else if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3) // mode == 3 send filters from acc
40 {
41 filter = &cl->account->cacheex.filter_caidtab;
42 }
43 else
44 {
45 return;
46 }
47
48 i2b_buf(2, filter->cevnum, buf + i);
49 i += 2;
50
51 int32_t max_filters = 30;
52 for(j = 0; j < max_filters; j++)
53 {
54 if(filter->cevnum > j)
55 {
56 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
57 i2b_buf(4, d->caid, buf + i);
58 }
59 i += 4;
60 }
61
62 for(j = 0; j < max_filters; j++)
63 {
64 if(filter->cevnum > j)
65 {
66 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
67 i2b_buf(4, d->cmask, buf + i);
68 }
69 i += 4;
70 }
71
72 for(j = 0; j < max_filters; j++)
73 {
74 if(filter->cevnum > j)
75 {
76 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
77 i2b_buf(4, d->prid, buf + i);
78 }
79 i += 4;
80 }
81
82 for(j = 0; j < max_filters; j++)
83 {
84 if(filter->cevnum > j)
85 {
86 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
87 i2b_buf(4, d->srvid, buf + i);
88 }
89 i += 4;
90 }
91
92 cs_log_dbg(D_CACHEEX, "cacheex: sending push filter request to %s", username(cl));
93 cc_cmd_send(cl, buf, size, MSG_CACHE_FILTER);
94}
95
96void cc_cacheex_filter_in(struct s_client *cl, uint8_t *buf)
97{
98 struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
99 int i = 0, j;
100 int32_t caid, cmask, provid, srvid;
101 CECSPVALUETAB *filter;
102
103 // mode == 2 write filters to acc
104 if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 2 && cl->account->cacheex.allow_filter == 1)
105 {
106 filter = &cl->account->cacheex.filter_caidtab;
107 }
108 else if(rdr && rdr->cacheex.mode == 3 && rdr->cacheex.allow_filter == 1) // mode == 3 write filters to rdr
109 {
110 filter = &rdr->cacheex.filter_caidtab;
111 }
112 else
113 {
114 return;
115 }
116
117 cecspvaluetab_clear(filter);
118 i += 2;
119
120 int32_t max_filters = 30;
121 for(j = 0; j < max_filters; j++)
122 {
123 caid = b2i(4, buf + i);
124 if(caid > 0)
125 {
126 CECSPVALUETAB_DATA d;
127 memset(&d, 0, sizeof(d));
128 d.caid = b2i(4, buf + i);
129 cecspvaluetab_add(filter, &d);
130 }
131 i += 4;
132 }
133
134 for(j = 0; j < max_filters; j++)
135 {
136 cmask = b2i(4, buf + i);
137 if(j < filter->cevnum)
138 {
139 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
140 d->cmask = cmask;
141 }
142 i += 4;
143 }
144
145 for(j = 0; j < max_filters; j++)
146 {
147 provid = b2i(4, buf + i);
148 if(j < filter->cevnum)
149 {
150 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
151 d->prid = provid;
152 }
153 i += 4;
154 }
155
156 for(j = 0; j < max_filters; j++)
157 {
158 srvid = b2i(4, buf + i);
159 if(j < filter->cevnum)
160 {
161 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
162 d->srvid = srvid;
163 }
164 i += 4;
165 }
166
167 cs_log_dbg(D_CACHEEX, "cacheex: received push filter request from %s", username(cl));
168}
169
170static int32_t cc_cacheex_push_chk(struct s_client *cl, struct ecm_request_t *er)
171{
172 struct cc_data *cc = cl->cc;
173 if(chk_is_null_nodeid(cc->peer_node_id,8))
174 {
175 cs_log_dbg(D_CACHEEX, "cacheex: NO peer_node_id got yet, skip!");
176 return 0;
177 }
178
179 if(ll_count(er->csp_lastnodes) >= cacheex_maxhop(cl)) // check max 10 nodes to push
180 {
181 cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl));
182 return 0;
183 }
184
185 uint8_t *remote_node = cc->peer_node_id;
186
187 // search existing peer nodes
188 LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
189 uint8_t *node;
190 while((node = ll_li_next(li)))
191 {
192 cs_log_dbg(D_CACHEEX, "cacheex: check node %" PRIu64 "X == %" PRIu64 "X ?",
193 cacheex_node_id(node), cacheex_node_id(remote_node));
194
195 if(memcmp(node, remote_node, 8) == 0)
196 {
197 break;
198 }
199 }
200 ll_li_destroy(li);
201
202 // node found, so we got it from there, do not push
203 if(node)
204 {
205 cs_log_dbg(D_CACHEEX, "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node));
206 return 0;
207 }
208
209 if(!cl->cc)
210 {
211 if(cl->reader && !cl->reader->tcp_connected)
212 {
213 cc_cli_connect(cl);
214 }
215 }
216
217 if(!cc || !cl->udp_fd)
218 {
219 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
220 return 0;
221 }
222
223 // check if cw is already pushed
224 if(check_is_pushed(er->cw_cache, cl))
225 {
226 return 0;
227 }
228
229 return 1;
230}
231
232static int32_t cc_cacheex_push_out(struct s_client *cl, struct ecm_request_t *er)
233{
234 int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc;
235
236 if(rc != E_FOUND && rc != E_UNHANDLED)
237 {
238 return -1; // Maybe later we could support other rcs
239 }
240
241 if(cl->reader)
242 {
243 if(!cl->reader->tcp_connected)
244 {
245 cc_cli_connect(cl);
246 }
247 }
248
249 struct cc_data *cc = cl->cc;
250 if(!cc || !cl->udp_fd)
251 {
252 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
253 return (-1);
254 }
255
256 uint32_t size = sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw) + sizeof(uint8_t) +
257 (ll_count(er->csp_lastnodes) + 1) * 8;
258
259 uint8_t *buf;
260 if(!cs_malloc(&buf, size + 20)) // camd35_send() adds +20
261 {
262 return -1;
263 }
264
265 // build ecm message
266 //buf[0] = er->caid >> 8;
267 //buf[1] = er->caid & 0xff;
268 //buf[2] = er->prid >> 24;
269 //buf[3] = er->prid >> 16;
270 //buf[4] = er->prid >> 8;
271 //buf[5] = er->prid & 0xff;
272 //buf[10] = er->srvid >> 8;
273 //buf[11] = er->srvid & 0xff;
274 buf[12] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) & 0xff;
275 buf[13] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) >> 8;
276 //buf[12] = 0;
277 //buf[13] = 0;
278 buf[14] = rc;
279
280 i2b_buf(2, er->caid, buf + 0);
281 i2b_buf(4, er->prid, buf + 2);
282 i2b_buf(2, er->srvid, buf + 10);
283
284 if(er->cwc_cycletime && er->cwc_next_cw_cycle < 2)
285 {
286 buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime
287
288 if(er->cwc_next_cw_cycle == 1)
289 {
290 buf[18] = (buf[18] | 0x80); // set bit 8 to high
291 }
292
293 if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode)
294 {
295 cl->account->cwc_info++;
296 }
297 else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode))
298 {
299 cl->cwc_info++;
300 }
301
302 cs_log_dbg(D_CWC, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X",
303 username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid);
304 }
305
306 buf[19] = er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0];
307
308 uint8_t *ofs = buf + 20;
309
310 // write oscam ecmd5
311 memcpy(ofs, er->ecmd5, sizeof(er->ecmd5)); // 16
312 ofs += sizeof(er->ecmd5);
313
314 // write csp hashcode
315 i2b_buf(4, CSP_HASH_SWAP(er->csp_hash), ofs);
316 ofs += 4;
317
318 // write cw
319 memcpy(ofs, er->cw, sizeof(er->cw)); // 16
320 ofs += sizeof(er->cw);
321
322 // write node count
323 *ofs = ll_count(er->csp_lastnodes) + 1;
324 ofs++;
325
326 // write own node
327 memcpy(ofs, cc->node_id, 8);
328 ofs += 8;
329
330 // write other nodes
331 LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
332 uint8_t *node;
333 while((node = ll_li_next(li)))
334 {
335 memcpy(ofs, node, 8);
336 ofs += 8;
337 }
338 ll_li_destroy(li);
339
340 int32_t res = cc_cmd_send(cl, buf, size + 20, MSG_CACHE_PUSH);
341 if(res > 0) // cache-ex is pushing out, so no receive but last_g should be updated otherwise disconnect!
342 {
343 if(cl->reader)
344 {
345 cl->reader->last_s = cl->reader->last_g = time((time_t *)0); // correct
346 }
347
348 if(cl)
349 {
350 cl->last = time(NULL);
351 }
352 }
353
354 NULLFREE(buf);
355 return res;
356}
357
358void cc_cacheex_push_in(struct s_client *cl, uint8_t *buf)
359{
360 struct cc_data *cc = cl->cc;
361 ECM_REQUEST *er;
362
363 if(!cc)
364 {
365 return;
366 }
367
368 if(cl->reader)
369 {
370 cl->reader->last_s = cl->reader->last_g = time((time_t *)0);
371 }
372
373 if(cl)
374 {
375 cl->last = time(NULL);
376 }
377
378 int8_t rc = buf[14];
379 if(rc != E_FOUND && rc != E_UNHANDLED) // Maybe later we could support other rcs
380 {
381 return;
382 }
383
384 uint16_t size = buf[12] | (buf[13] << 8);
385 if(size != sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw))
386 {
387 cs_log_dbg(D_CACHEEX, "cacheex: %s received old cash-push format! data ignored!", username(cl));
388 return;
389 }
390
391 if(!(er = get_ecmtask()))
392 {
393 return;
394 }
395
396 er->caid = b2i(2, buf + 0);
397 er->prid = b2i(4, buf + 2);
398 er->srvid = b2i(2, buf + 10);
399 er->ecm[0] = buf[19] != 0x80 && buf[19] != 0x81 ? 0 : buf[19]; // odd/even byte, usefull to send it over CSP and to check cw for swapping
400 er->rc = rc;
401
402 er->ecmlen = 0;
403
404 if(buf[18])
405 {
406 if(buf[18] & (0x01 << 7))
407 {
408 er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime
409 er->cwc_next_cw_cycle = 1;
410 }
411 else
412 {
413 er->cwc_cycletime = buf[18];
414 er->cwc_next_cw_cycle = 0;
415 }
416 }
417
418 if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2)
419 {
420 if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode)
421 {
422 cl->account->cwc_info++;
423 }
424 else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode))
425 {
426 cl->cwc_info++;
427 }
428
429 cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X",
430 username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid);
431 }
432
433 uint8_t *ofs = buf + 20;
434
435 // Read ecmd5
436 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); // 16
437 ofs += sizeof(er->ecmd5);
438
439 if(!check_cacheex_filter(cl, er))
440 {
441 return;
442 }
443
444 // Read csp_hash
445 er->csp_hash = CSP_HASH_SWAP(b2i(4, ofs));
446 ofs += 4;
447
448 // Read cw
449 memcpy(er->cw, ofs, sizeof(er->cw)); // 16
450 ofs += sizeof(er->cw);
451
452 // Read lastnode count
453 uint8_t count = *ofs;
454 ofs++;
455
456 // check max nodes
457 if(count > cacheex_maxhop(cl))
458 {
459 cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s",
460 (int32_t)count, cacheex_maxhop(cl), username(cl));
461
462 NULLFREE(er);
463 return;
464 }
465
466 cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl));
467
468 // Read lastnodes
469 uint8_t *data;
470 if (er)
471 {
472 er->csp_lastnodes = ll_create("csp_lastnodes");
473 }
474
475 while(count)
476 {
477 if(!cs_malloc(&data, 8))
478 {
479 break;
480 }
481
482 memcpy(data, ofs, 8);
483 ofs += 8;
484 ll_append(er->csp_lastnodes, data);
485 count--;
486
487 cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl));
488 }
489
490 // for compatibility: add peer node if no node received
491 if(!ll_count(er->csp_lastnodes))
492 {
493 if(!cs_malloc(&data, 8))
494 {
495 return;
496 }
497
498 memcpy(data, cc->peer_node_id, 8);
499 ll_append(er->csp_lastnodes, data);
500 cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data));
501 }
502
503 cacheex_add_to_cache(cl, er);
504}
505
506void cc_cacheex_module_init(struct s_module *ph)
507{
508 ph->c_cache_push = cc_cacheex_push_out;
509 ph->c_cache_push_chk = cc_cacheex_push_chk;
510}
511
512#endif
Note: See TracBrowser for help on using the repository browser.