1 #define MODULE_LOG_PREFIX "camd35"
4 #include "oscam-array.h"
6 #if defined(CS_CACHEEX) && (defined(MODULE_CAMD35) || defined(MODULE_CAMD35_TCP))
8 #include "module-cacheex.h"
9 #include "module-camd35.h"
10 #include "module-camd35-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-reader.h"
17 uint8_t camd35_node_id
[8];
19 #define CSP_HASH_SWAP(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
20 ((((uint32_t)(n) & 0xFF00)) << 8) | \
21 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
22 ((((uint32_t)(n) & 0xFF000000)) >> 24))
27 void camd35_cacheex_send_push_filter(struct s_client
*cl
, uint8_t mode
)
29 struct s_reader
*rdr
= cl
->reader
;
31 CECSPVALUETAB
*filter
;
32 //maximum size: 20+255
34 memset(buf
, 0, sizeof(buf
));
38 //mode==2 send filters from rdr
41 filter
= &rdr
->cacheex
.filter_caidtab
;
43 //mode==3 send filters from acc
44 else if(mode
== 3 && cl
->typ
== 'c' && cl
->account
)
46 filter
= &cl
->account
->cacheex
.filter_caidtab
;
52 i2b_buf(2, filter
->cevnum
, buf
+ i
);
55 int32_t max_filters
= 15;
56 for(j
=0; j
<max_filters
; j
++)
58 if(filter
->cevnum
> j
){
59 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
60 i2b_buf(4, d
->caid
, buf
+ i
);
65 for(j
=0; j
<max_filters
; j
++)
67 if(filter
->cevnum
> j
){
68 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
69 i2b_buf(4, d
->cmask
, buf
+ i
);
74 for(j
=0; j
<max_filters
; j
++)
76 if(filter
->cevnum
> j
){
77 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
78 i2b_buf(4, d
->prid
, buf
+ i
);
83 for(j
=0; j
<max_filters
; j
++)
85 if(filter
->cevnum
> j
){
86 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
87 i2b_buf(4, d
->srvid
, buf
+ i
);
92 cs_log_dbg(D_CACHEEX
, "cacheex: sending push filter request to %s", username(cl
));
93 camd35_send_without_timeout(cl
, buf
, 242); //send adds +20
97 * store received push filter
99 static void camd35_cacheex_push_filter(struct s_client
*cl
, uint8_t *buf
, uint8_t mode
)
101 struct s_reader
*rdr
= cl
->reader
;
103 int32_t caid
, cmask
, provid
, srvid
;
104 CECSPVALUETAB
*filter
;
106 //mode==2 write filters to acc
107 if(mode
== 2 && cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
== 2
108 && cl
->account
->cacheex
.allow_filter
== 1)
110 filter
= &cl
->account
->cacheex
.filter_caidtab
;
112 //mode==3 write filters to rdr
113 else if(mode
== 3 && rdr
&& rdr
->cacheex
.allow_filter
== 1)
115 filter
= &rdr
->cacheex
.filter_caidtab
;
121 cecspvaluetab_clear(filter
);
124 int32_t max_filters
= 15;
125 for(j
=0; j
<max_filters
; j
++)
127 caid
= b2i(4, buf
+ i
);
129 CECSPVALUETAB_DATA d
;
130 memset(&d
, 0, sizeof(d
));
131 d
.caid
= b2i(4, buf
+ i
);
132 cecspvaluetab_add(filter
, &d
);
137 for(j
=0; j
<max_filters
; j
++)
139 cmask
= b2i(4, buf
+ i
);
140 if(j
<filter
->cevnum
){
141 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
147 for(j
=0; j
<max_filters
; j
++)
149 provid
= b2i(4, buf
+ i
);
150 if(j
<filter
->cevnum
){
151 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
157 for(j
=0; j
<max_filters
; j
++)
159 srvid
= b2i(4, buf
+ i
);
160 if(j
<filter
->cevnum
){
161 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
167 cs_log_dbg(D_CACHEEX
, "cacheex: received push filter request from %s", username(cl
));
170 static int32_t camd35_cacheex_push_chk(struct s_client
*cl
, ECM_REQUEST
*er
)
172 if(ll_count(er
->csp_lastnodes
) >= cacheex_maxhop(cl
)) //check max 10 nodes to push:
174 cs_log_dbg(D_CACHEEX
, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl
));
180 if(!cl
->reader
->tcp_connected
)
182 cs_log_dbg(D_CACHEEX
, "cacheex: not connected %s -> no push", username(cl
));
187 //if(chk_is_null_nodeid(remote_node,8)){
190 cs_log_dbg(D_CACHEEX
, "cacheex: NO peer_node_id got yet, skip!");
194 uint8_t *remote_node
= cl
->ncd_skey
; //it is sended by reader(mode 2) or client (mode 3) each 30s using keepalive msgs
196 //search existing peer nodes:
197 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
199 while((node
= ll_li_next(li
)))
201 cs_log_dbg(D_CACHEEX
, "cacheex: check node %" PRIu64
"X == %" PRIu64
"X ?", cacheex_node_id(node
), cacheex_node_id(remote_node
));
202 if(memcmp(node
, remote_node
, 8) == 0)
209 //node found, so we got it from there, do not push:
212 cs_log_dbg(D_CACHEEX
,
213 "cacheex: node %" PRIu64
"X found in list => skip push!", cacheex_node_id(node
));
217 //check if cw is already pushed
218 if(check_is_pushed(er
->cw_cache
, cl
))
221 cs_log_dbg(D_CACHEEX
, "cacheex: push ok %" PRIu64
"X to %" PRIu64
"X %s", cacheex_node_id(camd35_node_id
), cacheex_node_id(remote_node
), username(cl
));
226 static int32_t camd35_cacheex_push_out(struct s_client
*cl
, struct ecm_request_t
*er
)
228 int8_t rc
= (er
->rc
< E_NOTFOUND
) ? E_FOUND
: er
->rc
;
229 if(rc
!= E_FOUND
&& rc
!= E_UNHANDLED
) { return -1; } //Maybe later we could support other rcs
231 //E_FOUND : we have the CW,
232 //E_UNHANDLED : incoming ECM request
236 if(!camd35_tcp_connect(cl
))
238 cs_log_dbg(D_CACHEEX
, "cacheex: not connected %s -> no push", username(cl
));
243 uint32_t size
= sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
) + sizeof(uint8_t) +
244 (ll_count(er
->csp_lastnodes
) + 1) * 8;
246 if(!cs_malloc(&buf
, size
+ 20)) //camd35_send() adds +20
249 buf
[0] = 0x3f; //New Command: Cache-push
250 buf
[1] = size
& 0xff;
254 i2b_buf(2, er
->srvid
, buf
+ 8);
255 i2b_buf(2, er
->caid
, buf
+ 10);
256 i2b_buf(4, er
->prid
, buf
+ 12);
257 //i2b_buf(2, er->idx, buf + 16); // Not relevant...?
259 if(er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2)
261 buf
[18] = er
->cwc_cycletime
; // contains cwc stage3 cycletime
262 if(er
->cwc_next_cw_cycle
== 1)
263 { buf
[18] = (buf
[18] | 0x80); } // set bit 8 to high
265 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
266 { cl
->account
->cwc_info
++; }
267 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
270 cs_log_dbg(D_CWC
, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl
), er
->cwc_cycletime
, er
->cwc_next_cw_cycle
, er
->caid
, er
->prid
, er
->srvid
);
273 buf
[19] = er
->ecm
[0] != 0x80 && er
->ecm
[0] != 0x81 ? 0 : er
->ecm
[0];
275 uint8_t *ofs
= buf
+ 20;
278 memcpy(ofs
, er
->ecmd5
, sizeof(er
->ecmd5
)); //16
279 ofs
+= sizeof(er
->ecmd5
);
281 //write csp hashcode:
282 i2b_buf(4, CSP_HASH_SWAP(er
->csp_hash
), ofs
);
286 memcpy(ofs
, er
->cw
, sizeof(er
->cw
)); //16
287 ofs
+= sizeof(er
->cw
);
290 *ofs
= ll_count(er
->csp_lastnodes
) + 1;
294 memcpy(ofs
, camd35_node_id
, 8);
298 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
300 while((node
= ll_li_next(li
)))
302 memcpy(ofs
, node
, 8);
307 int32_t res
= camd35_send(cl
, buf
, size
);
312 static void camd35_cacheex_push_in(struct s_client
*cl
, uint8_t *buf
)
315 if(rc
!= E_FOUND
&& rc
!= E_UNHANDLED
) //Maybe later we could support other rcs
319 uint16_t size
= buf
[1] | (buf
[2] << 8);
320 if(size
< sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
))
322 cs_log_dbg(D_CACHEEX
, "cacheex: %s received old cash-push format! data ignored!", username(cl
));
326 if(!(er
= get_ecmtask()))
329 er
->srvid
= b2i(2, buf
+ 8);
330 er
->caid
= b2i(2, buf
+ 10);
331 er
->prid
= b2i(4, buf
+ 12);
332 er
->pid
= b2i(2, buf
+ 16);
333 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
340 if(buf
[18] & (0x01 << 7))
342 er
->cwc_cycletime
= (buf
[18] & 0x7F); // remove bit 8 to get cycletime
343 er
->cwc_next_cw_cycle
= 1;
347 er
->cwc_cycletime
= buf
[18];
348 er
->cwc_next_cw_cycle
= 0;
352 if (er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2)
354 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
355 { cl
->account
->cwc_info
++; }
356 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
358 cs_log_dbg(D_CWC
, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl
), er
->cwc_cycletime
, er
->cwc_next_cw_cycle
, er
->caid
, er
->prid
, er
->srvid
);
361 uint8_t *ofs
= buf
+ 20;
364 memcpy(er
->ecmd5
, ofs
, sizeof(er
->ecmd5
)); //16
365 ofs
+= sizeof(er
->ecmd5
);
367 if(!check_cacheex_filter(cl
, er
))
371 er
->csp_hash
= CSP_HASH_SWAP(b2i(4, ofs
));
375 memcpy(er
->cw
, ofs
, sizeof(er
->cw
)); //16
376 ofs
+= sizeof(er
->cw
);
378 //Check auf neues Format:
380 if(size
> (sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
)))
384 uint8_t count
= *ofs
;
388 if(count
> cacheex_maxhop(cl
))
390 cs_log_dbg(D_CACHEEX
, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count
, cacheex_maxhop(cl
), username(cl
));
394 cs_log_dbg(D_CACHEEX
, "cacheex: received %d nodes %s", (int32_t)count
, username(cl
));
396 er
->csp_lastnodes
= ll_create("csp_lastnodes");
400 if(!cs_malloc(&data
, 8))
402 memcpy(data
, ofs
, 8);
404 ll_append(er
->csp_lastnodes
, data
);
406 cs_log_dbg(D_CACHEEX
, "cacheex: received node %" PRIu64
"X %s", cacheex_node_id(data
), username(cl
));
411 cs_log_dbg(D_CACHEEX
, "cacheex: received old cachex from %s", username(cl
));
412 er
->csp_lastnodes
= ll_create("csp_lastnodes");
415 //store remote node id if we got one. The remote node is the first node in the node list
416 data
= ll_has_elements(er
->csp_lastnodes
);
417 if(data
&& !cl
->ncd_skey
[8]) //Ok, this is tricky, we use newcamd key storage for saving the remote node
419 memcpy(cl
->ncd_skey
, data
, 8);
420 cl
->ncd_skey
[8] = 1; //Mark as valid node
422 cs_log_dbg(D_CACHEEX
, "cacheex: received cacheex from remote node id %" PRIu64
"X", cacheex_node_id(cl
->ncd_skey
));
424 //for compatibility: add peer node if no node received (not working now, maybe later):
425 if(!ll_count(er
->csp_lastnodes
) && cl
->ncd_skey
[8])
427 if(!cs_malloc(&data
, 8))
429 memcpy(data
, cl
->ncd_skey
, 8);
430 ll_append(er
->csp_lastnodes
, data
);
431 cs_log_dbg(D_CACHEEX
, "cacheex: added missing remote node id %" PRIu64
"X", cacheex_node_id(data
));
434 cacheex_add_to_cache(cl
, er
);
437 void camd35_cacheex_recv_ce1_cwc_info(struct s_client
*cl
, uint8_t *buf
, int32_t idx
)
439 if(!(buf
[0] == 0x01 && buf
[18] < 0xFF && buf
[18] > 0x00)) // cwc info ; normal camd3 ecms send 0xFF but we need no cycletime of 255 ;)
442 ECM_REQUEST
*er
= NULL
;
445 for(i
= 0; i
< cfg
.max_pending
; i
++)
447 if (cl
->ecmtask
[i
].idx
== idx
)
449 er
= &cl
->ecmtask
[i
];
463 if(buf
[18] & (0x01 << 7))
465 er
->cwc_cycletime
= (buf
[18] & 0x7F); // remove bit 8 to get cycletime
466 er
->parent
->cwc_cycletime
= er
->cwc_cycletime
;
467 er
->cwc_next_cw_cycle
= 1;
468 er
->parent
->cwc_next_cw_cycle
= er
->cwc_next_cw_cycle
;
472 er
->cwc_cycletime
= buf
[18];
473 er
->parent
->cwc_cycletime
= er
->cwc_cycletime
;
474 er
->cwc_next_cw_cycle
= 0;
475 er
->parent
->cwc_next_cw_cycle
= er
->cwc_next_cw_cycle
;
479 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
480 { cl
->account
->cwc_info
++; }
481 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
484 cs_log_dbg(D_CWC
, "CWC (CE1) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl
), er
->cwc_cycletime
, er
->cwc_next_cw_cycle
, er
->caid
, er
->prid
, er
->srvid
);
490 * when a server client connects
492 static void camd35_server_client_init(struct s_client
*cl
)
496 cl
->cacheex_needfilter
= 1;
501 * store received remote id
503 static void camd35_cacheex_push_receive_remote_id(struct s_client
*cl
, uint8_t *buf
)
506 memcpy(cl
->ncd_skey
, buf
+ 20, 8);
508 cs_log_dbg(D_CACHEEX
, "cacheex: received id answer from %s: %" PRIu64
"X", username(cl
), cacheex_node_id(cl
->ncd_skey
));
512 void camd35_cacheex_init_dcw(struct s_client
*client
, ECM_REQUEST
*er
)
514 uint8_t *buf
= er
->src_data
; // get orig request
516 if(((client
->typ
== 'c' && client
->account
&& client
->account
->cacheex
.mode
)
517 || ((client
->typ
== 'p' || client
->typ
== 'r') && (client
->reader
&& client
->reader
->cacheex
.mode
)))
518 && er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2) // ce1
520 buf
[18] = er
->cwc_cycletime
; // contains cwc stage3 cycletime
521 if(er
->cwc_next_cw_cycle
== 1)
522 { buf
[18] = (buf
[18] | 0x80); } // set bit 8 to high
523 if(client
->typ
== 'c' && client
->account
&& client
->account
->cacheex
.mode
)
524 { client
->account
->cwc_info
++; }
525 else if((client
->typ
== 'p' || client
->typ
== 'r') && (client
->reader
&& client
->reader
->cacheex
.mode
))
526 { client
->cwc_info
++; }
527 cs_log_dbg(D_CWC
, "CWC (CE1) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(client
), er
->cwc_cycletime
, er
->cwc_next_cw_cycle
, er
->caid
, er
->prid
, er
->srvid
);
528 buf
[19] = er
->ecm
[0];
535 void camd35_cacheex_push_send_own_id(struct s_client
*cl
, uint8_t *mbuf
)
537 uint8_t rbuf
[32]; //minimal size
538 if(!cl
->crypted
) { return; }
539 cs_log_dbg(D_CACHEEX
, "cacheex: received id request from node %" PRIu64
"X %s", cacheex_node_id(mbuf
+ 20), username(cl
));
540 memset(rbuf
, 0, sizeof(rbuf
));
544 memcpy(rbuf
+ 20, camd35_node_id
, 8);
545 cs_log_dbg(D_CACHEEX
, "cacheex: sending own id %" PRIu64
"X request %s", cacheex_node_id(camd35_node_id
), username(cl
));
546 camd35_send(cl
, rbuf
, 12); //send adds +20
549 bool camd35_cacheex_server(struct s_client
*client
, uint8_t *mbuf
)
553 case 0x3c: // Cache-push filter request
554 if(client
->account
&& client
->account
->cacheex
.mode
==2){
555 camd35_cacheex_push_filter(client
, mbuf
, 2);
558 case 0x3d: // Cache-push id request
559 camd35_cacheex_push_receive_remote_id(client
, mbuf
); //reader send request id with its nodeid, so we save it!
560 camd35_cacheex_push_send_own_id(client
, mbuf
);
561 if(client
->cacheex_needfilter
&& client
->account
&& client
->account
->cacheex
.mode
==3){
562 camd35_cacheex_send_push_filter(client
, 3);
563 client
->cacheex_needfilter
= 0;
566 case 0x3e: // Cache-push id answer
567 camd35_cacheex_push_receive_remote_id(client
, mbuf
);
569 case 0x3f: // Cache-push
570 camd35_cacheex_push_in(client
, mbuf
);
573 return 0; // Not processed by cacheex
575 return 1; // Processed by cacheex
578 bool camd35_cacheex_recv_chk(struct s_client
*client
, uint8_t *buf
)
580 struct s_reader
*rdr
= client
->reader
;
583 case 0x3c: // Cache-push filter request
584 if(rdr
->cacheex
.mode
==3){
585 camd35_cacheex_push_filter(client
, buf
, 3);
588 case 0x3d: // Cache-push id request
589 camd35_cacheex_push_receive_remote_id(client
, buf
); //client send request id with its nodeid, so we save it!
590 camd35_cacheex_push_send_own_id(client
, buf
);
592 case 0x3e: // Cache-push id answer
593 camd35_cacheex_push_receive_remote_id(client
, buf
);
595 case 0x3f: //cache-push
596 camd35_cacheex_push_in(client
, buf
);
599 return 0; // Not processed by cacheex
601 return 1; // Processed by cacheex
607 void camd35_cacheex_push_request_remote_id(struct s_client
*cl
)
609 uint8_t rbuf
[32];//minimal size
610 memset(rbuf
, 0, sizeof(rbuf
));
614 memcpy(rbuf
+ 20, camd35_node_id
, 8);
615 cs_log_dbg(D_CACHEEX
, "cacheex: sending id request to %s", username(cl
));
616 camd35_send(cl
, rbuf
, 12); //send adds +20
619 void camd35_cacheex_module_init(struct s_module
*ph
)
621 ph
->c_cache_push
= camd35_cacheex_push_out
;
622 ph
->c_cache_push_chk
= camd35_cacheex_push_chk
;
623 ph
->s_init
= camd35_server_client_init
;