1 #define MODULE_LOG_PREFIX "cccam"
4 #include "oscam-array.h"
6 #if defined(CS_CACHEEX) && defined(MODULE_CCCAM)
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"
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))
23 extern int32_t cc_cli_connect(struct s_client
*cl
);
24 extern int32_t cc_cmd_send(struct s_client
*cl
, uint8_t *buf
, int32_t len
, cc_msg_type_t cmd
);
26 void cc_cacheex_filter_out(struct s_client
*cl
)
28 struct s_reader
*rdr
= (cl
->typ
== 'c') ? NULL
: cl
->reader
;
30 CECSPVALUETAB
*filter
;
31 int32_t size
= 482; // minimal size, keep it <= 512 for max UDP packet size without fragmentation
33 memset(buf
, 0, sizeof(buf
));
35 if(rdr
&& rdr
->cacheex
.mode
== 2) // mode == 2 send filters from rdr
37 filter
= &rdr
->cacheex
.filter_caidtab
;
39 else if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
== 3) // mode == 3 send filters from acc
41 filter
= &cl
->account
->cacheex
.filter_caidtab
;
48 i2b_buf(2, filter
->cevnum
, buf
+ i
);
51 int32_t max_filters
= 30;
52 for(j
= 0; j
< max_filters
; j
++)
54 if(filter
->cevnum
> j
)
56 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
57 i2b_buf(4, d
->caid
, buf
+ i
);
62 for(j
= 0; j
< max_filters
; j
++)
64 if(filter
->cevnum
> j
)
66 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
67 i2b_buf(4, d
->cmask
, buf
+ i
);
72 for(j
= 0; j
< max_filters
; j
++)
74 if(filter
->cevnum
> j
)
76 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
77 i2b_buf(4, d
->prid
, buf
+ i
);
82 for(j
= 0; j
< max_filters
; j
++)
84 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 cc_cmd_send(cl
, buf
, size
, MSG_CACHE_FILTER
);
96 void cc_cacheex_filter_in(struct s_client
*cl
, uint8_t *buf
)
98 struct s_reader
*rdr
= (cl
->typ
== 'c') ? NULL
: cl
->reader
;
100 int32_t caid
, cmask
, provid
, srvid
;
101 CECSPVALUETAB
*filter
;
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)
106 filter
= &cl
->account
->cacheex
.filter_caidtab
;
108 else if(rdr
&& rdr
->cacheex
.mode
== 3 && rdr
->cacheex
.allow_filter
== 1) // mode == 3 write filters to rdr
110 filter
= &rdr
->cacheex
.filter_caidtab
;
117 cecspvaluetab_clear(filter
);
120 int32_t max_filters
= 30;
121 for(j
= 0; j
< max_filters
; j
++)
123 caid
= b2i(4, buf
+ i
);
126 CECSPVALUETAB_DATA d
;
127 memset(&d
, 0, sizeof(d
));
128 d
.caid
= b2i(4, buf
+ i
);
129 cecspvaluetab_add(filter
, &d
);
134 for(j
= 0; j
< max_filters
; j
++)
136 cmask
= b2i(4, buf
+ i
);
137 if(j
< filter
->cevnum
)
139 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
145 for(j
= 0; j
< max_filters
; j
++)
147 provid
= b2i(4, buf
+ i
);
148 if(j
< filter
->cevnum
)
150 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
156 for(j
= 0; j
< max_filters
; j
++)
158 srvid
= b2i(4, buf
+ i
);
159 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 cc_cacheex_push_chk(struct s_client
*cl
, struct ecm_request_t
*er
)
172 struct cc_data
*cc
= cl
->cc
;
173 if(chk_is_null_nodeid(cc
->peer_node_id
,8))
175 cs_log_dbg(D_CACHEEX
, "cacheex: NO peer_node_id got yet, skip!");
179 if(ll_count(er
->csp_lastnodes
) >= cacheex_maxhop(cl
)) // check max 10 nodes to push
181 cs_log_dbg(D_CACHEEX
, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl
));
185 uint8_t *remote_node
= cc
->peer_node_id
;
187 // search existing peer nodes
188 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
190 while((node
= ll_li_next(li
)))
192 cs_log_dbg(D_CACHEEX
, "cacheex: check node %" PRIu64
"X == %" PRIu64
"X ?",
193 cacheex_node_id(node
), cacheex_node_id(remote_node
));
195 if(memcmp(node
, remote_node
, 8) == 0)
202 // node found, so we got it from there, do not push
205 cs_log_dbg(D_CACHEEX
, "cacheex: node %" PRIu64
"X found in list => skip push!", cacheex_node_id(node
));
211 if(cl
->reader
&& !cl
->reader
->tcp_connected
)
217 if(!cc
|| !cl
->udp_fd
)
219 cs_log_dbg(D_CACHEEX
, "cacheex: not connected %s -> no push", username(cl
));
223 // check if cw is already pushed
224 if(check_is_pushed(er
->cw_cache
, cl
))
232 static int32_t cc_cacheex_push_out(struct s_client
*cl
, struct ecm_request_t
*er
)
234 int8_t rc
= (er
->rc
< E_NOTFOUND
) ? E_FOUND
: er
->rc
;
236 if(rc
!= E_FOUND
&& rc
!= E_UNHANDLED
)
238 return -1; // Maybe later we could support other rcs
243 if(!cl
->reader
->tcp_connected
)
249 struct cc_data
*cc
= cl
->cc
;
250 if(!cc
|| !cl
->udp_fd
)
252 cs_log_dbg(D_CACHEEX
, "cacheex: not connected %s -> no push", username(cl
));
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;
260 if(!cs_malloc(&buf
, size
+ 20)) // camd35_send() adds +20
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;
280 i2b_buf(2, er
->caid
, buf
+ 0);
281 i2b_buf(4, er
->prid
, buf
+ 2);
282 i2b_buf(2, er
->srvid
, buf
+ 10);
284 if(er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2)
286 buf
[18] = er
->cwc_cycletime
; // contains cwc stage3 cycletime
288 if(er
->cwc_next_cw_cycle
== 1)
290 buf
[18] = (buf
[18] | 0x80); // set bit 8 to high
293 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
295 cl
->account
->cwc_info
++;
297 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
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
);
306 buf
[19] = er
->ecm
[0] != 0x80 && er
->ecm
[0] != 0x81 ? 0 : er
->ecm
[0];
308 uint8_t *ofs
= buf
+ 20;
311 memcpy(ofs
, er
->ecmd5
, sizeof(er
->ecmd5
)); // 16
312 ofs
+= sizeof(er
->ecmd5
);
314 // write csp hashcode
315 i2b_buf(4, CSP_HASH_SWAP(er
->csp_hash
), ofs
);
319 memcpy(ofs
, er
->cw
, sizeof(er
->cw
)); // 16
320 ofs
+= sizeof(er
->cw
);
323 *ofs
= ll_count(er
->csp_lastnodes
) + 1;
327 memcpy(ofs
, cc
->node_id
, 8);
331 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
333 while((node
= ll_li_next(li
)))
335 memcpy(ofs
, node
, 8);
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!
345 cl
->reader
->last_s
= cl
->reader
->last_g
= time((time_t *)0); // correct
350 cl
->last
= time(NULL
);
358 void cc_cacheex_push_in(struct s_client
*cl
, uint8_t *buf
)
360 struct cc_data
*cc
= cl
->cc
;
370 cl
->reader
->last_s
= cl
->reader
->last_g
= time((time_t *)0);
375 cl
->last
= time(NULL
);
379 if(rc
!= E_FOUND
&& rc
!= E_UNHANDLED
) // Maybe later we could support other rcs
384 uint16_t size
= buf
[12] | (buf
[13] << 8);
385 if(size
!= sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
))
387 cs_log_dbg(D_CACHEEX
, "cacheex: %s received old cash-push format! data ignored!", username(cl
));
391 if(!(er
= get_ecmtask()))
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
406 if(buf
[18] & (0x01 << 7))
408 er
->cwc_cycletime
= (buf
[18] & 0x7F); // remove bit 8 to get cycletime
409 er
->cwc_next_cw_cycle
= 1;
413 er
->cwc_cycletime
= buf
[18];
414 er
->cwc_next_cw_cycle
= 0;
418 if (er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2)
420 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
422 cl
->account
->cwc_info
++;
424 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
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
);
433 uint8_t *ofs
= buf
+ 20;
436 memcpy(er
->ecmd5
, ofs
, sizeof(er
->ecmd5
)); // 16
437 ofs
+= sizeof(er
->ecmd5
);
439 if(!check_cacheex_filter(cl
, er
))
445 er
->csp_hash
= CSP_HASH_SWAP(b2i(4, ofs
));
449 memcpy(er
->cw
, ofs
, sizeof(er
->cw
)); // 16
450 ofs
+= sizeof(er
->cw
);
452 // Read lastnode count
453 uint8_t count
= *ofs
;
457 if(count
> cacheex_maxhop(cl
))
459 cs_log_dbg(D_CACHEEX
, "cacheex: received %d nodes (max=%d), ignored! %s",
460 (int32_t)count
, cacheex_maxhop(cl
), username(cl
));
466 cs_log_dbg(D_CACHEEX
, "cacheex: received %d nodes %s", (int32_t)count
, username(cl
));
472 er
->csp_lastnodes
= ll_create("csp_lastnodes");
477 if(!cs_malloc(&data
, 8))
482 memcpy(data
, ofs
, 8);
484 ll_append(er
->csp_lastnodes
, data
);
487 cs_log_dbg(D_CACHEEX
, "cacheex: received node %" PRIu64
"X %s", cacheex_node_id(data
), username(cl
));
490 // for compatibility: add peer node if no node received
491 if(!ll_count(er
->csp_lastnodes
))
493 if(!cs_malloc(&data
, 8))
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
));
503 cacheex_add_to_cache(cl
, er
);
506 void cc_cacheex_module_init(struct s_module
*ph
)
508 ph
->c_cache_push
= cc_cacheex_push_out
;
509 ph
->c_cache_push_chk
= cc_cacheex_push_chk
;