- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / module-cw-cycle-check.c
blobf9cc810872d0b98376673a78f35db634418c5cbe
1 #define MODULE_LOG_PREFIX "cwccheck"
3 #include "globals.h"
4 #ifdef CW_CYCLE_CHECK
6 #include "module-cw-cycle-check.h"
7 #include "oscam-chk.h"
8 #include "oscam-client.h"
9 #include "oscam-ecm.h"
10 #include "oscam-lock.h"
11 #include "oscam-string.h"
12 #include "oscam-cache.h"
14 struct s_cwc_md5
16 uint8_t md5[CS_ECMSTORESIZE];
17 uint32_t csp_hash;
18 uint8_t cw[16];
21 struct s_cw_cycle_check
23 uint8_t cw[16];
24 time_t time;
25 time_t locktime; // lock in learning
26 uint16_t caid;
27 uint16_t sid;
28 uint16_t chid;
29 uint32_t provid;
30 int16_t ecmlen;
31 int8_t stage;
32 int32_t cycletime;
33 int32_t dyncycletime;
34 int8_t nextcyclecw;
35 struct s_cwc_md5 ecm_md5[15]; // max 15 old ecm md5 /csp-hashs
36 int8_t cwc_hist_entry;
37 uint8_t old;
38 int8_t stage4_repeat;
39 struct s_cw_cycle_check *prev;
40 struct s_cw_cycle_check *next;
43 extern CS_MUTEX_LOCK cwcycle_lock;
45 static struct s_cw_cycle_check *cw_cc_list;
46 static int32_t cw_cc_list_size;
47 static time_t last_cwcyclecleaning;
50 * Check for CW CYCLE
53 static uint8_t chk_is_pos_fallback(ECM_REQUEST *er, char *reader)
55 struct s_ecm_answer *ea;
56 struct s_reader *fbrdr;
57 char fb_reader[64];
59 for(ea = er->matching_rdr; ea; ea = ea->next)
61 if(ea->reader)
63 fbrdr = ea->reader;
64 snprintf(fb_reader, sizeof(fb_reader), "%s", ea->reader->label);
65 if(!strcmp(reader, fb_reader) && chk_is_fixed_fallback(fbrdr, er))
67 cs_log("cyclecheck [check Fixed FB] %s is set as fixed fallback", reader);
68 return 1;
72 return 0;
75 static inline uint8_t checkECMD5CW(uint8_t *ecmd5_cw)
77 int8_t i;
78 for(i = 0; i < CS_ECMSTORESIZE; i++)
79 if(ecmd5_cw[i]) { return 1; }
80 return 0;
84 * countCWpart is to prevent like this
85 * D41A1A08B01DAD7A 0F1D0A36AF9777BD found -> ok
86 * E9151917B01DAD7A 0F1D0A36AF9777BD found last -> worng (freeze), but for cwc is ok
87 * 7730F59C6653A55E D3822A7F133D3C8C cwc bad -> but cw is right, cwc out of step
89 static uint8_t countCWpart(ECM_REQUEST *er, struct s_cw_cycle_check *cwc)
91 uint8_t eo = cwc->nextcyclecw ? 0 : 8;
92 int8_t i, ret = 0;
94 #ifdef WITH_DEBUG
95 if(cs_dblevel & D_CWC)
97 char cwc_cw[9 * 3];
98 char er_cw[9 * 3];
99 cs_hexdump(0, cwc->cw + eo, 8, cwc_cw, sizeof(cwc_cw));
100 cs_hexdump(0, er->cw + eo, 8, er_cw, sizeof(er_cw));
101 cs_log_dbg(D_CWC, "cyclecheck [countCWpart] er-cw %s", er_cw);
102 cs_log_dbg(D_CWC, "cyclecheck [countCWpart] cw-cw %s", cwc_cw);
104 #endif
106 for(i = 0; i < 8; i++)
108 if(cwc->cw[i + eo] == er->cw[i + eo])
110 ret++;
115 if(ret > cfg.cwcycle_sensitive)
117 cs_log("cyclecheck [countCWpart] new cw is to like old one (unused part), sensitive %d, same bytes %d", cfg.cwcycle_sensitive, ret);
119 return ret;
122 static uint8_t checkvalidCW(ECM_REQUEST *er)
124 uint8_t ret = 1;
126 // Skip check for BISS1 - cw could be indeed zero
127 // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero
128 if(chk_is_null_CW(er->cw) && !caid_is_biss(er->caid))
129 { er->rc = E_NOTFOUND; }
131 if(er->rc == E_NOTFOUND)
132 { return 0; } // wrong leave the check
134 if(checkCWpart(er->cw, 0) && checkCWpart(er->cw, 1))
135 { return 1; } // cw1 and cw2 is filled -> we can check for cwc
137 if((!checkCWpart(er->cw, 0) || !checkCWpart(er->cw, 1)) && caid_is_videoguard(er->caid))
139 cs_log("CAID: %04X uses obviously half cycle cw's : NO need to check it with CWC! Remove CAID: %04X from CWC Config!", er->caid, er->caid);
140 ret = 0; // cw1 or cw2 is null
143 return ret;
146 void cleanupcwcycle(void)
148 time_t now = time(NULL);
149 if(last_cwcyclecleaning + 120 > now) // only clean once every 2min
150 { return; }
152 last_cwcyclecleaning = now;
153 int32_t count = 0, kct = cfg.keepcycletime * 60 + 30; // if keepcycletime is set, wait more before deleting
154 struct s_cw_cycle_check *prv = NULL, *currentnode = NULL, *temp = NULL;
156 bool bcleanup = false;
158 // write lock
159 cs_writelock(__func__, &cwcycle_lock);
160 for(currentnode = cw_cc_list, prv = NULL; currentnode; prv = currentnode, currentnode = currentnode->next, count++) // First Remove old Entrys
162 if((now - currentnode->time) <= kct) // delete Entry which old to hold list small
164 continue;
166 cs_log_dbg(D_CWC, "cyclecheck [Cleanup] diff: %ld kct: %i", now - currentnode->time, kct);
167 if(prv != NULL)
169 prv->next = NULL;
171 else
173 cw_cc_list = NULL;
175 bcleanup = true;
176 break; // we need only once, all follow to old
178 cs_writeunlock(__func__, &cwcycle_lock);
179 while(currentnode != NULL)
181 temp = currentnode->next;
182 if(!currentnode->old)
183 { cw_cc_list_size--; }
184 NULLFREE(currentnode);
185 currentnode = temp;
187 if(bcleanup)
188 { cs_log_dbg(D_CWC, "cyclecheck [Cleanup] list new size: %d (realsize: %d)", cw_cc_list_size, count); }
191 static int32_t checkcwcycle_int(ECM_REQUEST *er, char *er_ecmf , char *user, uint8_t *cw , char *reader, uint8_t cycletime_fr, uint8_t next_cw_cycle_fr)
194 int8_t i, ret = 6; // ret = 6 no checked
195 int8_t cycleok = -1;
196 time_t now = er->tps.time; //time(NULL);
197 uint8_t need_new_entry = 1, upd_entry = 1;
198 char cwstr[17 * 3]; // cw to check
200 char cwc_ecmf[ECM_FMT_LEN];
201 char cwc_cw[17 * 3];
202 #ifdef WITH_DEBUG
203 char cwc_md5[17 * 3];
204 char cwc_csp[5 * 3];
205 #endif
206 int8_t n = 1, m = 1, k;
207 int32_t mcl = cfg.maxcyclelist;
208 struct s_cw_cycle_check *currentnode = NULL, *cwc = NULL;
210 /*for(list = cw_cc_list; list; list = list->next) { // List all Entrys in Log for DEBUG
211 cs_log_dbg(D_CWC, "cyclecheck: [LIST] %04X@%06X:%04X OLD: %i Time: %ld DifftoNow: %ld Stage: %i cw: %s", list->caid, list->provid, list->sid, list->old, list->time, now - list->time, list->stage, cs_hexdump(0, list->cw, 16, cwstr, sizeof(cwstr)));
215 if(!checkvalidCW(er))
216 { return 3; } //cwc ign
218 //read lock
219 cs_readlock(__func__, &cwcycle_lock);
220 bool readlocked = true;
221 for(currentnode = cw_cc_list; currentnode; currentnode = currentnode->next)
223 if(currentnode->caid != er->caid || currentnode->provid != er->prid || currentnode->sid != er->srvid || currentnode->chid != er->chid)
225 continue;
227 if(er->ecmlen != 0 && currentnode->ecmlen != 0)
229 if(currentnode->ecmlen != er->ecmlen)
231 cs_log_dbg(D_CWC, "cyclecheck [other ECM LEN] -> don't check");
232 continue;
236 need_new_entry = 0; // we got a entry for caid/prov/sid so we dont need new one
238 #ifdef WITH_DEBUG
239 if(cs_dblevel & D_CWC)
241 cs_hexdump(0, cw, 16, cwstr, sizeof(cwstr)); //checked cw for log
243 #endif
244 if(cs_malloc(&cwc, sizeof(struct s_cw_cycle_check)))
246 memcpy(cwc, currentnode, sizeof(struct s_cw_cycle_check)); //copy current to new
248 if(!currentnode->old)
250 currentnode->old = 1; //need later to counting
251 cw_cc_list_size--;
253 //now we have all data and can leave read lock
254 cs_readunlock(__func__, &cwcycle_lock);
255 readlocked = false;
256 #ifdef WITH_DEBUG
257 if(cs_dblevel & D_CWC)
259 cs_hexdump(0, cwc->ecm_md5[cwc->cwc_hist_entry].md5, 16, cwc_md5, sizeof(cwc_md5));
260 cs_hexdump(0, (void *)&cwc->ecm_md5[cwc->cwc_hist_entry].csp_hash, 4, cwc_csp, sizeof(cwc_csp));
261 cs_hexdump(0, cwc->cw, 16, cwc_cw, sizeof(cwc_cw));
262 ecmfmt(cwc_ecmf, ECM_FMT_LEN, cwc->caid, 0, cwc->provid, cwc->chid, 0, cwc->sid, cwc->ecmlen, cwc_md5, cwc_csp, cwc_cw, 0, 0, NULL, NULL);
264 #endif
266 // Cycletime over Cacheex
267 if (cfg.cwcycle_usecwcfromce)
269 if(cycletime_fr > 0 && next_cw_cycle_fr < 2)
271 cs_log_dbg(D_CWC, "cyclecheck [Use Info in Request] Client: %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", user, cycletime_fr, next_cw_cycle_fr, er->caid, er->prid, er->srvid);
272 cwc->stage = 3;
273 cwc->cycletime = cycletime_fr;
274 cwc->nextcyclecw = next_cw_cycle_fr;
275 ret = 8;
276 if(memcmp(cwc->cw, cw, 16) == 0) //check if the store cw the same like the current
278 cs_log_dbg(D_CWC, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
279 cs_log_dbg(D_CWC, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
280 if(now - cwc->time >= cwc->cycletime - cwc->dyncycletime)
282 cs_log_dbg(D_CWC, "cyclecheck [Same CW but much too late] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
283 ret = cfg.cwcycle_dropold ? 2 : 4;
285 else
287 ret = 4; // Return 4 same CW
289 upd_entry = 0;
291 break;
295 if(cwc->stage == 3 && cwc->nextcyclecw < 2 && now - cwc->time < cwc->cycletime * 2 - cwc->dyncycletime - 1) // Check for Cycle no need to check Entrys others like stage 3
297 /*for (k=0; k<15; k++) { // debug md5
298 cs_log_dbg(D_CWC, "cyclecheck [checksumlist[%i]]: ecm_md5: %s csp-hash: %d Entry: %i", k, cs_hexdump(0, cwc->ecm_md5[k].md5, 16, ecm_md5, sizeof(ecm_md5)), cwc->ecm_md5[k].csp_hash, cwc->cwc_hist_entry);
299 } */
301 // first we check if the store cw the same like the current
302 if(memcmp(cwc->cw, cw, 16) == 0)
304 cs_log_dbg(D_CWC, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
305 cs_log_dbg(D_CWC, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
306 if(now - cwc->time >= cwc->cycletime - cwc->dyncycletime)
308 cs_log_dbg(D_CWC, "cyclecheck [Same CW but much too late] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
309 ret = cfg.cwcycle_dropold ? 2 : 4;
311 else
313 ret = 4; // Return 4 same CW
315 upd_entry = 0;
316 break;
319 if(cwc->nextcyclecw == 0) //CW0 must Cycle
321 for(i = 0; i < 8; i++)
323 if(cwc->cw[i] == cw[i])
325 cycleok = 0; //means CW0 Cycle OK
327 else
329 cycleok = -1;
330 break;
334 else if(cwc->nextcyclecw == 1) //CW1 must Cycle
336 for(i = 0; i < 8; i++)
338 if(cwc->cw[i + 8] == cw[i + 8])
340 cycleok = 1; //means CW1 Cycle OK
342 else
344 cycleok = -1;
345 break;
350 if(cycleok >= 0 && cfg.cwcycle_sensitive && countCWpart(er, cwc) >= cfg.cwcycle_sensitive) //2,3,4, 0 = off
352 cycleok = -2;
355 if(cycleok >= 0)
357 ret = 0; // return Code 0 Cycle OK
358 if(cycleok == 0)
360 cwc->nextcyclecw = 1;
361 er->cwc_next_cw_cycle = 1;
362 if(cwc->cycletime < 128 && (!(cwc->caid == 0x0100 && cwc->provid == 0x00006A))) // make sure cycletime is lower dez 128 because share over cacheex buf[18] bit 8 is used for cwc_next_cw_cycle
363 { er->cwc_cycletime = cwc->cycletime; }
364 cs_log_dbg(D_CWC, "cyclecheck [Valid CW 0 Cycle] Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now - cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader);
366 else if(cycleok == 1)
368 cwc->nextcyclecw = 0;
369 er->cwc_next_cw_cycle = 0;
370 if(cwc->cycletime < 128 && (!(cwc->caid == 0x0100 && cwc->provid == 0x00006A))) // make sure cycletime is lower dez 128 because share over cacheex buf[18] bit 8 is used for cwc_next_cw_cycle
371 { er->cwc_cycletime = cwc->cycletime; }
372 cs_log_dbg(D_CWC, "cyclecheck [Valid CW 1 Cycle] Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now - cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader);
374 cs_log_dbg(D_CWC, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
375 cs_log_dbg(D_CWC, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
377 else
380 for(k = 0; k < 15; k++) // check for old ECMs
382 #ifdef CS_CACHEEX
383 if((checkECMD5CW(er->ecmd5) && checkECMD5CW(cwc->ecm_md5[k].md5) && !(memcmp(er->ecmd5, cwc->ecm_md5[k].md5, sizeof(er->ecmd5)))) || (er->csp_hash && cwc->ecm_md5[k].csp_hash && er->csp_hash == cwc->ecm_md5[k].csp_hash))
384 #else
385 if((memcmp(er->ecmd5, cwc->ecm_md5[k].md5, sizeof(er->ecmd5))) == 0)
386 #endif
388 cs_log_dbg(D_CWC, "cyclecheck [OLD] [CheckedECM] Client: %s EA: %s", user, er_ecmf);
389 #ifdef WITH_DEBUG
390 if(cs_dblevel & D_CWC)
392 cs_hexdump(0, cwc->ecm_md5[k].md5, 16, cwc_md5, sizeof(cwc_md5));
393 cs_hexdump(0, (void *)&cwc->ecm_md5[k].csp_hash, 4, cwc_csp, sizeof(cwc_csp));
394 cs_log_dbg(D_CWC, "cyclecheck [OLD] [Stored ECM] Client: %s EA: %s.%s", user, cwc_md5, cwc_csp);
396 #endif
397 if(!cfg.cwcycle_dropold && !memcmp(cwc->ecm_md5[k].cw, cw, 16))
398 { ret = 4; }
399 else
400 { ret = 2; } // old ER
401 upd_entry = 0;
402 break;
405 if(!upd_entry) { break; }
406 if(cycleok == -2)
407 { cs_log_dbg(D_CWC, "cyclecheck [ATTENTION!! NON Valid CW] Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now - cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader); }
408 else
409 { cs_log_dbg(D_CWC, "cyclecheck [ATTENTION!! NON Valid CW Cycle] NO CW Cycle detected! Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now - cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader); }
410 cs_log_dbg(D_CWC, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
411 cs_log_dbg(D_CWC, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
412 ret = 1; // bad cycle
413 upd_entry = 0;
414 if(cfg.cwcycle_allowbadfromffb)
416 if(chk_is_pos_fallback(er, reader))
418 ret = 5;
419 cwc->stage = 4;
420 upd_entry = 1;
421 cwc->nextcyclecw = 2;
422 break;
425 break;
428 else
430 if(cwc->stage == 3)
432 if(cfg.keepcycletime > 0 && now - cwc->time < cfg.keepcycletime * 60) // we are in keepcycletime window
434 cwc->stage++; // go to stage 4
435 cs_log_dbg(D_CWC, "cyclecheck [Set Stage 4] for Entry: %s Cycletime: %i -> Entry too old but in keepcycletime window - no cycletime learning - only check which CW must cycle", cwc_ecmf, cwc->cycletime);
437 else
439 cwc->stage--; // go one stage back, we are not in keepcycletime window
440 cs_log_dbg(D_CWC, "cyclecheck [Back to Stage 2] for Entry: %s Cycletime: %i -> new cycletime learning", cwc_ecmf, cwc->cycletime);
442 memset(cwc->cw, 0, sizeof(cwc->cw)); //fake cw for stage 2/4
443 ret = 3;
444 cwc->nextcyclecw = 2;
447 if(upd_entry) // learning stages
449 if(now > cwc->locktime)
451 int16_t diff = now - cwc->time - cwc->cycletime;
452 if(cwc->stage <= 0) // stage 0 is passed; we update the cw's and time and store cycletime
454 // if(cwc->cycletime == now - cwc->time) // if we got a stable cycletime we go to stage 1
455 if(diff > -2 && diff < 2) // if we got a stable cycletime we go to stage 1
457 cwc->cycletime = now - cwc->time;
458 cs_log_dbg(D_CWC, "cyclecheck [Set Stage 1] %s Cycletime: %i Lockdiff: %ld", cwc_ecmf, cwc->cycletime, now - cwc->locktime);
459 cwc->stage++; // increase stage
461 else
463 cs_log_dbg(D_CWC, "cyclecheck [Stay on Stage 0] %s Cycletime: %i -> no constant CW-Change-Time", cwc_ecmf, cwc->cycletime);
467 else if(cwc->stage == 1) // stage 1 is passed; we update the cw's and time and store cycletime
469 // if(cwc->cycletime == now - cwc->time) // if we got a stable cycletime we go to stage 2
470 if(diff > -2 && diff < 2) // if we got a stable cycletime we go to stage 2
472 cwc->cycletime = now - cwc->time;
473 cs_log_dbg(D_CWC, "cyclecheck [Set Stage 2] %s Cycletime: %i Lockdiff: %ld", cwc_ecmf, cwc->cycletime, now - cwc->locktime);
474 cwc->stage++; // increase stage
476 else
478 cs_log_dbg(D_CWC, "cyclecheck [Back to Stage 0] for Entry %s Cycletime: %i -> no constant CW-Change-Time", cwc_ecmf, cwc->cycletime);
479 cwc->stage--;
482 else if(cwc->stage == 2) // stage 2 is passed; we update the cw's and compare cycletime
484 // if(cwc->cycletime == now - cwc->time && cwc->cycletime > 0) // if we got a stable cycletime we go to stage 3
485 if(diff > -2 && diff < 2 && cwc->cycletime > 0) // if we got a stable cycletime we go to stage 3
487 cwc->cycletime = now - cwc->time;
488 n = memcmp(cwc->cw, cw, 8);
489 m = memcmp(cwc->cw + 8, cw + 8, 8);
490 if(n == 0)
492 cwc->nextcyclecw = 1;
494 if(m == 0)
496 cwc->nextcyclecw = 0;
498 if(n == m || !checkECMD5CW(cw)) { cwc->nextcyclecw = 2; } //be sure only one cw part cycle and is valid
499 if(cwc->nextcyclecw < 2)
501 cs_log_dbg(D_CWC, "cyclecheck [Set Stage 3] %s Cycletime: %i Lockdiff: %ld nextCycleCW = CW%i", cwc_ecmf, cwc->cycletime, now - cwc->locktime, cwc->nextcyclecw);
502 cs_log_dbg(D_CWC, "cyclecheck [Set Cycletime %i] for Entry: %s -> now we can check CW's", cwc->cycletime, cwc_ecmf);
503 cwc->stage = 3; // increase stage
505 else
507 cs_log_dbg(D_CWC, "cyclecheck [Back to Stage 1] for Entry %s Cycletime: %i -> no CW-Cycle in Learning Stage", cwc_ecmf, cwc->cycletime); // if a server asked only every twice ECM we got a stable cycletime*2 ->but thats wrong
508 cwc->stage = 1;
512 else
515 cs_log_dbg(D_CWC, "cyclecheck [Back to Stage 1] for Entry %s Cycletime: %i -> no constant CW-Change-Time", cwc_ecmf, cwc->cycletime);
516 cwc->stage = 1;
519 else if(cwc->stage == 4) // we got a early learned cycletime.. use this cycletime and check only which cw cycle
521 n = memcmp(cwc->cw, cw, 8);
522 m = memcmp(cwc->cw + 8, cw + 8, 8);
523 if(n == 0)
525 cwc->nextcyclecw = 1;
527 if(m == 0)
529 cwc->nextcyclecw = 0;
531 if(n == m || !checkECMD5CW(cw)) { cwc->nextcyclecw = 2; } //be sure only one cw part cycle and is valid
532 if(cwc->nextcyclecw < 2)
534 cs_log_dbg(D_CWC, "cyclecheck [Back to Stage 3] %s Cycletime: %i Lockdiff: %ld nextCycleCW = CW%i", cwc_ecmf, cwc->cycletime, now - cwc->locktime, cwc->nextcyclecw);
535 cs_log_dbg(D_CWC, "cyclecheck [Set old Cycletime %i] for Entry: %s -> now we can check CW's", cwc->cycletime, cwc_ecmf);
536 cwc->stage = 3; // go back to stage 3
538 else
540 cs_log_dbg(D_CWC, "cyclecheck [Stay on Stage %d] for Entry %s Cycletime: %i no cycle detect!", cwc->stage, cwc_ecmf, cwc->cycletime);
541 if (cwc->stage4_repeat > 12)
543 cwc->stage = 1;
544 cs_log_dbg(D_CWC, "cyclecheck [Back to Stage 1] too much cyclefailure, maybe cycletime not correct %s Cycletime: %i Lockdiff: %ld nextCycleCW = CW%i", cwc_ecmf, cwc->cycletime, now - cwc->locktime, cwc->nextcyclecw);
547 cwc->stage4_repeat++;
548 ret = ret == 3 ? 3 : 7; // IGN for first stage4 otherwise LEARN
550 if(cwc->stage == 3)
552 cwc->locktime = 0;
553 cwc->stage4_repeat = 0;
555 else
557 if(cwc->stage < 3) { cwc->cycletime = now - cwc->time; }
558 cwc->locktime = now + (get_fallbacktimeout(cwc->caid) / 1000);
561 else if(cwc->stage != 3)
563 cs_log_dbg(D_CWC, "cyclecheck [Ignore this EA] for LearningStages because of locktime EA: %s Lockdiff: %ld", cwc_ecmf, now - cwc->locktime);
564 upd_entry = 0;
567 if(cwc->stage == 3) // we stay in Stage 3 so we update only time and cw
569 if(now - cwc->time > cwc->cycletime)
571 cwc->dyncycletime = now - cwc->time - cwc->cycletime;
573 else
575 cwc->dyncycletime = 0;
580 else
582 upd_entry = 0;
583 cwc = NULL;
585 break;
588 if (readlocked)
590 cs_readunlock(__func__, &cwcycle_lock);
593 if(need_new_entry)
595 cs_readunlock(__func__, &cwcycle_lock);
596 if(cw_cc_list_size <= mcl) //only add when we have space
598 struct s_cw_cycle_check *new = NULL;
599 if(cs_malloc(&new, sizeof(struct s_cw_cycle_check))) // store cw on top in cyclelist
601 memcpy(new->cw, cw, sizeof(new->cw));
602 // csp cache got no ecm and no md5 hash
603 memcpy(new->ecm_md5[0].md5, er->ecmd5, sizeof(er->ecmd5));
604 #ifdef CS_CACHEEX
605 new->ecm_md5[0].csp_hash = er->csp_hash; // we got no ecm_md5 so CSP-Hash could be necessary
606 #else
607 new->ecm_md5[0].csp_hash = 0; //fake CSP-Hash we got a ecm_md5 so CSP-Hash is not necessary
608 #endif
609 memcpy(new->ecm_md5[0].cw, cw, sizeof(new->cw));
610 new->ecmlen = er->ecmlen;
611 new->cwc_hist_entry = 0;
612 new->caid = er->caid;
613 new->provid = er->prid;
614 new->sid = er->srvid;
615 new->chid = er->chid;
616 new->time = now;
617 new->locktime = now + (get_fallbacktimeout(er->caid) / 1000);
618 new->dyncycletime = 0; // to react of share timings
619 // cycletime over Cacheex
620 new->stage = (cfg.cwcycle_usecwcfromce && cycletime_fr > 0 && next_cw_cycle_fr < 2) ? 3 : 0;
621 new->cycletime = (cfg.cwcycle_usecwcfromce && cycletime_fr > 0 && next_cw_cycle_fr < 2) ? cycletime_fr : 99;
622 new->nextcyclecw = (cfg.cwcycle_usecwcfromce && cycletime_fr > 0 && next_cw_cycle_fr < 2) ? next_cw_cycle_fr : 2; //2=we dont know which next cw Cycle; 0= next cw Cycle CW0; 1= next cw Cycle CW1;
623 ret = (cycletime_fr > 0 && next_cw_cycle_fr < 2) ? 8 : 6;
625 new->prev = new->next = NULL;
626 new->old = 0;
627 new->stage4_repeat = 0;
628 //write lock
629 cs_writelock(__func__, &cwcycle_lock);
630 if(cw_cc_list) // the new entry on top
632 cw_cc_list->prev = new;
633 new->next = cw_cc_list;
635 cw_cc_list = new;
636 cw_cc_list_size++;
637 //write unlock /
638 cs_writeunlock(__func__, &cwcycle_lock);
640 cs_log_dbg(D_CWC, "cyclecheck [Store New Entry] %s Time: %ld Stage: %i Cycletime: %i Locktime: %ld", er_ecmf, new->time, new->stage, new->cycletime, new->locktime);
643 else
645 cs_log("cyclecheck [Store New Entry] Max List arrived -> dont store new Entry list_size: %i, mcl: %i", cw_cc_list_size, mcl);
648 else if(upd_entry && cwc)
650 cwc->prev = cwc->next = NULL;
651 cwc->old = 0;
652 memcpy(cwc->cw, cw, sizeof(cwc->cw));
653 cwc->time = now;
654 cwc->cwc_hist_entry++;
655 if(cwc->cwc_hist_entry > 14) //ringbuffer for md5
657 cwc->cwc_hist_entry = 0;
659 // csp cache got no ecm and no md5 hash
660 memcpy(cwc->ecm_md5[cwc->cwc_hist_entry].md5, er->ecmd5, sizeof(cwc->ecm_md5[0].md5));
661 #ifdef CS_CACHEEX
662 cwc->ecm_md5[cwc->cwc_hist_entry].csp_hash = er->csp_hash;
663 #else
664 cwc->ecm_md5[cwc->cwc_hist_entry].csp_hash = 0; //fake CSP-Hash for logging
665 #endif
666 memcpy(cwc->ecm_md5[cwc->cwc_hist_entry].cw, cw, sizeof(cwc->cw));
667 cwc->ecmlen = er->ecmlen;
668 //write lock /
669 cs_writelock(__func__, &cwcycle_lock);
670 if(cw_cc_list) // the clone entry on top
672 cw_cc_list->prev = cwc;
673 cwc->next = cw_cc_list;
675 cw_cc_list = cwc;
676 cw_cc_list_size++;
677 //write unlock /
678 cs_writeunlock(__func__, &cwcycle_lock);
679 cs_log_dbg(D_CWC, "cyclecheck [Update Entry and add on top] %s Time: %ld Stage: %i Cycletime: %i", er_ecmf, cwc->time, cwc->stage, cwc->cycletime);
681 else if(cwc)
683 NULLFREE(cwc);
685 return ret;
688 static void count_ok(struct s_client *client)
690 if(client)
692 client->cwcycledchecked++;
693 client->cwcycledok++;
695 if(client && client->account)
697 client->account->cwcycledchecked++;
698 client->account->cwcycledok++;
702 static void count_nok(struct s_client *client)
704 if(client)
706 client->cwcycledchecked++;
707 client->cwcyclednok++;
709 if(client && client->account)
711 client->account->cwcycledchecked++;
712 client->account->cwcyclednok++;
716 static void count_ign(struct s_client *client)
718 if(client)
720 client->cwcycledchecked++;
721 client->cwcycledign++;
723 if(client && client->account)
725 client->account->cwcycledchecked++;
726 client->account->cwcycledign++;
730 uint8_t checkcwcycle(struct s_client *client, ECM_REQUEST *er, struct s_reader *reader, uint8_t *cw, int8_t rc, uint8_t cycletime_fr, uint8_t next_cw_cycle_fr)
733 if(!cfg.cwcycle_check_enable)
734 { return 3; }
735 if(client && client->account && client->account->cwc_disable)
736 { return 3; }
737 // if (!(rc == E_FOUND) && !(rc == E_CACHEEX))
738 if(rc >= E_NOTFOUND)
739 { return 2; }
740 if(!cw || !er)
741 { return 2; }
742 if(!(chk_ctab_ex(er->caid, &cfg.cwcycle_check_caidtab))) // dont check caid not in list
743 { return 1; } // no match leave the check
744 if(is_halfCW_er(er))
745 { return 1; } // half cw cycle, checks are done in ecm-handler
747 memcpy(er->cw, cw, 16);
748 char er_ecmf[ECM_FMT_LEN];
749 format_ecm(er, er_ecmf, ECM_FMT_LEN);
751 char c_reader[64];
752 char user[64];
754 if(!streq(username(client), "NULL"))
755 { snprintf(user, sizeof(user), "%s", username(client)); }
756 else
757 { snprintf(user, sizeof(user), "---"); }
759 if(reader)
760 { snprintf(c_reader, sizeof(c_reader), "%s", reader->label); }
761 else
762 { snprintf(c_reader, sizeof(c_reader), "cache"); }
765 cs_log_dbg(D_CWC | D_TRACE, "cyclecheck EA: %s rc: %i reader: %s", er_ecmf, rc, c_reader);
767 switch(checkcwcycle_int(er, er_ecmf, user, cw, c_reader, cycletime_fr, next_cw_cycle_fr))
770 case 0: // CWCYCLE OK
771 count_ok(client);
772 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc OK");
773 break;
775 case 1: // CWCYCLE NOK
776 count_nok(client);
777 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc NOK");
778 if(cfg.onbadcycle > 0) // ignore ECM Request
780 #ifdef CS_CACHEEX_AIO
781 if(!er->localgenerated)
783 #endif
784 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> drop cw (ECM Answer)", user, er_ecmf, c_reader); //D_CWC| D_TRACE
785 return 0;
786 #ifdef CS_CACHEEX_AIO
788 else
790 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> lg-flagged CW -> do nothing", user, er_ecmf, c_reader); //D_CWC| D_TRACE
791 break;
793 #endif
796 else // only logging
798 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> do nothing", user, er_ecmf, c_reader);//D_CWC| D_TRACE
799 break;
802 case 2: // ER to OLD
803 #ifdef CS_CACHEEX_AIO
804 if(!er->localgenerated)
806 #endif
807 count_nok(client);
808 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc NOK(old)");
809 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> ECM Answer is too OLD -> drop cw (ECM Answer)", user, er_ecmf, c_reader);//D_CWC| D_TRACE
810 return 0;
811 #ifdef CS_CACHEEX_AIO
813 else
815 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> ECM Answer is too OLD -> lg-flagged CW -> do nothing", user, er_ecmf, c_reader); //D_CWC| D_TRACE
816 break;
818 #endif
820 case 3: // CycleCheck ignored (stage 3 to stage 4)
821 count_ign(client);
822 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc IGN");
823 break;
825 case 4: // same CW
826 cs_log_dbg(D_CWC, "cyclecheck [Same CW] for: %s %s -> same CW detected from: %s -> do nothing ", user, er_ecmf, c_reader);
827 break;
829 case 5: //answer from fixed Fallbackreader with Bad Cycle
830 count_nok(client);
831 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc NOK but IGN (fixed FB)");
832 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> But Ignored because of answer from Fixed Fallback Reader", user, er_ecmf, c_reader);
833 break;
835 case 6: // not checked ( learning Stages Cycletime and CWCycle Stage < 3)
836 case 7: // not checked ( learning Stages only CWCycle Stage 4)
837 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc LEARN");
838 break;
840 case 8: // use Cyclecheck from CE Source
841 count_ok(client);
842 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc OK(CE)");
843 break;
845 case 9: // CWCYCLE NOK without counting
846 snprintf(er->cwc_msg_log, sizeof(er->cwc_msg_log), "cwc NOK");
847 if(cfg.onbadcycle > 0) // ignore ECM Request
849 #ifdef CS_CACHEEX_AIO
850 if(!er->localgenerated)
852 #endif
853 cs_log("cyclecheck [Bad CW Cycle already Counted] for: %s %s from: %s -> drop cw (ECM Answer)", user, er_ecmf, c_reader);
854 return 0;
855 #ifdef CS_CACHEEX_AIO
857 else
859 cs_log("cyclecheck [Bad CW Cycle already Counted] for: %s %s from: %s -> lg-flagged CW -> do nothing", user, er_ecmf, c_reader); //D_CWC| D_TRACE
860 break;
862 #endif
864 else // only logging
866 cs_log("cyclecheck [Bad CW Cycle already Counted] for: %s %s from: %s -> do nothing", user, er_ecmf, c_reader);
867 break;
871 return 1;
879 #endif