1 #define MODULE_LOG_PREFIX "cwccheck"
6 #include "module-cw-cycle-check.h"
8 #include "oscam-client.h"
10 #include "oscam-lock.h"
11 #include "oscam-string.h"
12 #include "oscam-cache.h"
16 uint8_t md5
[CS_ECMSTORESIZE
];
21 struct s_cw_cycle_check
25 time_t locktime
; // lock in learning
35 struct s_cwc_md5 ecm_md5
[15]; // max 15 old ecm md5 /csp-hashs
36 int8_t cwc_hist_entry
;
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
;
53 static uint8_t chk_is_pos_fallback(ECM_REQUEST
*er
, char *reader
)
55 struct s_ecm_answer
*ea
;
56 struct s_reader
*fbrdr
;
59 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
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
);
75 static inline uint8_t checkECMD5CW(uint8_t *ecmd5_cw
)
78 for(i
= 0; i
< CS_ECMSTORESIZE
; i
++)
79 if(ecmd5_cw
[i
]) { return 1; }
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;
95 if(cs_dblevel
& D_CWC
)
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
);
106 for(i
= 0; i
< 8; i
++)
108 if(cwc
->cw
[i
+ eo
] == er
->cw
[i
+ eo
])
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
);
122 static uint8_t checkvalidCW(ECM_REQUEST
*er
)
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
146 void cleanupcwcycle(void)
148 time_t now
= time(NULL
);
149 if(last_cwcyclecleaning
+ 120 > now
) // only clean once every 2min
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;
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
166 cs_log_dbg(D_CWC
, "cyclecheck [Cleanup] diff: %ld kct: %i", now
- currentnode
->time
, kct
);
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
);
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
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
];
203 char cwc_md5
[17 * 3];
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
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
)
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");
236 need_new_entry
= 0; // we got a entry for caid/prov/sid so we dont need new one
239 if(cs_dblevel
& D_CWC
)
241 cs_hexdump(0, cw
, 16, cwstr
, sizeof(cwstr
)); //checked cw for log
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
253 //now we have all data and can leave read lock
254 cs_readunlock(__func__
, &cwcycle_lock
);
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
);
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
);
273 cwc
->cycletime
= cycletime_fr
;
274 cwc
->nextcyclecw
= next_cw_cycle_fr
;
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;
287 ret
= 4; // Return 4 same CW
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);
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;
313 ret
= 4; // Return 4 same CW
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
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
350 if(cycleok
>= 0 && cfg
.cwcycle_sensitive
&& countCWpart(er
, cwc
) >= cfg
.cwcycle_sensitive
) //2,3,4, 0 = off
357 ret
= 0; // return Code 0 Cycle OK
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
);
380 for(k
= 0; k
< 15; k
++) // check for old ECMs
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
))
385 if((memcmp(er
->ecmd5
, cwc
->ecm_md5
[k
].md5
, sizeof(er
->ecmd5
))) == 0)
388 cs_log_dbg(D_CWC
, "cyclecheck [OLD] [CheckedECM] Client: %s EA: %s", user
, er_ecmf
);
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
);
397 if(!cfg
.cwcycle_dropold
&& !memcmp(cwc
->ecm_md5
[k
].cw
, cw
, 16))
400 { ret
= 2; } // old ER
405 if(!upd_entry
) { break; }
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
); }
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
414 if(cfg
.cwcycle_allowbadfromffb
)
416 if(chk_is_pos_fallback(er
, reader
))
421 cwc
->nextcyclecw
= 2;
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
);
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
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
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
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
);
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);
492 cwc
->nextcyclecw
= 1;
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
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
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
);
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);
525 cwc
->nextcyclecw
= 1;
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
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)
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
553 cwc
->stage4_repeat
= 0;
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
);
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
;
575 cwc
->dyncycletime
= 0;
590 cs_readunlock(__func__
, &cwcycle_lock
);
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
));
605 new->ecm_md5
[0].csp_hash
= er
->csp_hash
; // we got no ecm_md5 so CSP-Hash could be necessary
607 new->ecm_md5
[0].csp_hash
= 0; //fake CSP-Hash we got a ecm_md5 so CSP-Hash is not necessary
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
;
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
;
627 new->stage4_repeat
= 0;
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
;
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
);
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
;
652 memcpy(cwc
->cw
, cw
, sizeof(cwc
->cw
));
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
));
662 cwc
->ecm_md5
[cwc
->cwc_hist_entry
].csp_hash
= er
->csp_hash
;
664 cwc
->ecm_md5
[cwc
->cwc_hist_entry
].csp_hash
= 0; //fake CSP-Hash for logging
666 memcpy(cwc
->ecm_md5
[cwc
->cwc_hist_entry
].cw
, cw
, sizeof(cwc
->cw
));
667 cwc
->ecmlen
= er
->ecmlen
;
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
;
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
);
688 static void count_ok(struct s_client
*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
)
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
)
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
)
735 if(client
&& client
->account
&& client
->account
->cwc_disable
)
737 // if (!(rc == E_FOUND) && !(rc == E_CACHEEX))
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
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
);
754 if(!streq(username(client
), "NULL"))
755 { snprintf(user
, sizeof(user
), "%s", username(client
)); }
757 { snprintf(user
, sizeof(user
), "---"); }
760 { snprintf(c_reader
, sizeof(c_reader
), "%s", reader
->label
); }
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
772 snprintf(er
->cwc_msg_log
, sizeof(er
->cwc_msg_log
), "cwc OK");
775 case 1: // CWCYCLE NOK
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
)
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
786 #ifdef CS_CACHEEX_AIO
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
798 cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> do nothing", user
, er_ecmf
, c_reader
);//D_CWC| D_TRACE
803 #ifdef CS_CACHEEX_AIO
804 if(!er
->localgenerated
)
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
811 #ifdef CS_CACHEEX_AIO
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
820 case 3: // CycleCheck ignored (stage 3 to stage 4)
822 snprintf(er
->cwc_msg_log
, sizeof(er
->cwc_msg_log
), "cwc IGN");
826 cs_log_dbg(D_CWC
, "cyclecheck [Same CW] for: %s %s -> same CW detected from: %s -> do nothing ", user
, er_ecmf
, c_reader
);
829 case 5: //answer from fixed Fallbackreader with Bad Cycle
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
);
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");
840 case 8: // use Cyclecheck from CE Source
842 snprintf(er
->cwc_msg_log
, sizeof(er
->cwc_msg_log
), "cwc OK(CE)");
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
)
853 cs_log("cyclecheck [Bad CW Cycle already Counted] for: %s %s from: %s -> drop cw (ECM Answer)", user
, er_ecmf
, c_reader
);
855 #ifdef CS_CACHEEX_AIO
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
866 cs_log("cyclecheck [Bad CW Cycle already Counted] for: %s %s from: %s -> do nothing", user
, er_ecmf
, c_reader
);