[gbx] - more generalized routing info in cw msg
[oscam.git] / module-camd35-cacheex.c
blob8a70d9677f8e31dc6e2ad9d592038f24b8052ca7
1 #define MODULE_LOG_PREFIX "camd35"
3 #include "globals.h"
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))
24 /**
25 * send push filter
27 void camd35_cacheex_send_push_filter(struct s_client *cl, uint8_t mode)
29 struct s_reader *rdr = cl->reader;
30 int i = 20, j;
31 CECSPVALUETAB *filter;
32 //maximum size: 20+255
33 uint8_t buf[20+242];
34 memset(buf, 0, sizeof(buf));
35 buf[0] = 0x3c;
36 buf[1] = 0xf2;
38 //mode==2 send filters from rdr
39 if(mode == 2 && 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;
48 else {
49 return;
52 i2b_buf(2, filter->cevnum, buf + i);
53 i += 2;
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);
62 i += 4;
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);
71 i += 4;
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);
80 i += 4;
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);
89 i += 4;
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
96 /**
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;
102 int i = 20, j;
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;
117 else {
118 return;
121 cecspvaluetab_clear(filter);
122 i += 2;
124 int32_t max_filters = 15;
125 for(j=0; j<max_filters; j++)
127 caid = b2i(4, buf + i);
128 if(caid > 0){
129 CECSPVALUETAB_DATA d;
130 memset(&d, 0, sizeof(d));
131 d.caid = b2i(4, buf + i);
132 cecspvaluetab_add(filter, &d);
134 i += 4;
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];
142 d->cmask = cmask;
144 i += 4;
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];
152 d->prid = provid;
154 i += 4;
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];
162 d->srvid = srvid;
164 i += 4;
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));
175 return 0;
178 if(cl->reader)
180 if(!cl->reader->tcp_connected)
182 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
183 return 0;
187 //if(chk_is_null_nodeid(remote_node,8)){
188 if(!cl->ncd_skey[8])
190 cs_log_dbg(D_CACHEEX, "cacheex: NO peer_node_id got yet, skip!");
191 return 0;
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);
198 uint8_t *node;
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)
204 break;
207 ll_li_destroy(li);
209 //node found, so we got it from there, do not push:
210 if(node)
212 cs_log_dbg(D_CACHEEX,
213 "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node));
214 return 0;
217 //check if cw is already pushed
218 if(check_is_pushed(er->cw_cache, cl))
219 { return 0; }
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));
223 return 1;
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
234 if(cl->reader)
236 if(!camd35_tcp_connect(cl))
238 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
239 return (-1);
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;
245 uint8_t *buf;
246 if(!cs_malloc(&buf, size + 20)) //camd35_send() adds +20
247 { return -1; }
249 buf[0] = 0x3f; //New Command: Cache-push
250 buf[1] = size & 0xff;
251 buf[2] = size >> 8;
252 buf[3] = rc;
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))
268 { cl->cwc_info++; }
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;
277 //write oscam ecmd5:
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);
283 ofs += 4;
285 //write cw:
286 memcpy(ofs, er->cw, sizeof(er->cw)); //16
287 ofs += sizeof(er->cw);
289 //write node count:
290 *ofs = ll_count(er->csp_lastnodes) + 1;
291 ofs++;
293 //write own node:
294 memcpy(ofs, camd35_node_id, 8);
295 ofs += 8;
297 //write other nodes:
298 LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
299 uint8_t *node;
300 while((node = ll_li_next(li)))
302 memcpy(ofs, node, 8);
303 ofs += 8;
305 ll_li_destroy(li);
307 int32_t res = camd35_send(cl, buf, size);
308 NULLFREE(buf);
309 return res;
312 static void camd35_cacheex_push_in(struct s_client *cl, uint8_t *buf)
314 int8_t rc = buf[3];
315 if(rc != E_FOUND && rc != E_UNHANDLED) //Maybe later we could support other rcs
316 { return; }
318 ECM_REQUEST *er;
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));
323 return;
326 if(!(er = get_ecmtask()))
327 { return; }
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
334 er->rc = rc;
336 er->ecmlen = 0;
338 if(buf[18])
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;
345 else
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))
357 { cl->cwc_info++; }
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;
363 //Read ecmd5
364 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); //16
365 ofs += sizeof(er->ecmd5);
367 if(!check_cacheex_filter(cl, er))
368 { return; }
370 //Read csp_hash:
371 er->csp_hash = CSP_HASH_SWAP(b2i(4, ofs));
372 ofs += 4;
374 //Read cw:
375 memcpy(er->cw, ofs, sizeof(er->cw)); //16
376 ofs += sizeof(er->cw);
378 //Check auf neues Format:
379 uint8_t *data;
380 if(size > (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)))
383 //Read lastnodes:
384 uint8_t count = *ofs;
385 ofs++;
387 //check max nodes:
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));
391 NULLFREE(er);
392 return;
394 cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl));
395 if (er){
396 er->csp_lastnodes = ll_create("csp_lastnodes");
398 while(count)
400 if(!cs_malloc(&data, 8))
401 { break; }
402 memcpy(data, ofs, 8);
403 ofs += 8;
404 ll_append(er->csp_lastnodes, data);
405 count--;
406 cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl));
409 else
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))
428 { return; }
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 ;)
440 return;
442 ECM_REQUEST *er = NULL;
443 int32_t i;
445 for(i = 0; i < cfg.max_pending; i++)
447 if (cl->ecmtask[i].idx == idx)
449 er = &cl->ecmtask[i];
450 break;
454 if(!er)
455 { return; }
457 int8_t rc = buf[3];
458 if(rc != E_FOUND)
459 { return; }
461 if(buf[18])
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;
470 else
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))
482 { cl->cwc_info++; }
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)
494 if(!cl->init_done)
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);
507 cl->ncd_skey[8] = 1;
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];
533 * send own id
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));
541 rbuf[0] = 0x3e;
542 rbuf[1] = 12;
543 rbuf[2] = 0;
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)
551 switch(mbuf[0])
553 case 0x3c: // Cache-push filter request
554 if(client->account && client->account->cacheex.mode==2){
555 camd35_cacheex_push_filter(client, mbuf, 2);
557 break;
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;
565 break;
566 case 0x3e: // Cache-push id answer
567 camd35_cacheex_push_receive_remote_id(client, mbuf);
568 break;
569 case 0x3f: // Cache-push
570 camd35_cacheex_push_in(client, mbuf);
571 break;
572 default:
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;
581 switch(buf[0])
583 case 0x3c: // Cache-push filter request
584 if(rdr->cacheex.mode==3){
585 camd35_cacheex_push_filter(client, buf, 3);
587 break;
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);
591 break;
592 case 0x3e: // Cache-push id answer
593 camd35_cacheex_push_receive_remote_id(client, buf);
594 break;
595 case 0x3f: //cache-push
596 camd35_cacheex_push_in(client, buf);
597 break;
598 default:
599 return 0; // Not processed by cacheex
601 return 1; // Processed by cacheex
605 * request remote id
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));
611 rbuf[0] = 0x3d;
612 rbuf[1] = 12;
613 rbuf[2] = 0;
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;
626 #endif