--- a/oscam-cache.h
+++ a/oscam-cache.h
@@ -2,6 +2,7 @@
 #define OSCAM_CACHE_H_
 
 void init_cache(void);
+void init_cw_cache(void);
 void free_cache(void);
 void add_cache(ECM_REQUEST *er);
 struct ecm_request_t *check_cache(ECM_REQUEST *er, struct s_client *cl);
@@ -10,5 +11,5 @@
 uint32_t cache_size(void);
 uint8_t get_odd_even(ECM_REQUEST *er);
 uint8_t check_is_pushed(void *cw, struct s_client *cl);
-
+void cw_cache_cleanup(bool force);
 #endif
--- a/oscam-cache.c
+++ a/oscam-cache.c
@@ -59,10 +59,43 @@
 	node                ll_node;             // node for linked list
 } ECMHASH;
 
+typedef struct cw_cache_t
+{
+	uint8_t             cw[16];
+	uint16_t            caid;
+	uint32_t            prid;
+	uint16_t            srvid;
+	struct timeb        first_recv_time;     // time of first cw received
+	struct timeb        upd_time;            // updated time. Update time at each cw got
+	node				ht_node;
+	node				ll_node;
+} CW_CACHE;
+
+typedef struct cw_cache_setting_t
+{
+	int8_t			mode;
+	uint16_t		timediff_old_cw;
+} CW_CACHE_SETTING;
+
 static pthread_rwlock_t cache_lock;
+static pthread_rwlock_t cw_cache_lock;
 static hash_table ht_cache;
+static hash_table ht_cw_cache;
 static list ll_cache;
+static list ll_cw_cache;
 static int8_t cache_init_done = 0;
+static int8_t cw_cache_init_done = 0;
+uint32_t cw_cache_remove_count = 0;
+
+void init_cw_cache(void){
+	if(cfg.cw_cache_size > 0 || cfg.cw_cache_memory > 0){
+		init_hash_table(&ht_cw_cache, &ll_cw_cache);
+		if (pthread_rwlock_init(&cw_cache_lock,NULL) != 0)
+			{ cs_log("Error creating lock cw_cache_lock!"); }
+		else
+			{ cw_cache_init_done = 1; }
+	}
+}
 
 void init_cache(void)
 {
@@ -76,9 +109,13 @@
 void free_cache(void)
 {
 	cleanup_cache(true);
+	cw_cache_cleanup(true);
 	cache_init_done = 0;
+	cw_cache_init_done = 0;
 	deinitialize_hash_table(&ht_cache);
+	deinitialize_hash_table(&ht_cw_cache);
 	pthread_rwlock_destroy(&cache_lock);
+	pthread_rwlock_destroy(&cw_cache_lock);
 }
 
 uint32_t cache_size(void)
@@ -95,6 +132,12 @@
 	return (a->count > b->count) ? -1 : 1; // DESC order by count
 }
 
+static uint8_t time_sort(CW_CACHE *a, CW_CACHE *b)
+{
+	if (((int64_t)(a->upd_time.time) * 1000ull + (int64_t) a->upd_time.millitm) == ((int64_t)(b->upd_time.time) * 1000ull + (int64_t) b->upd_time.millitm)) return 0;
+	return (((int64_t)(a->upd_time.time) * 1000ull + (int64_t) a->upd_time.millitm) > ((int64_t)(b->upd_time.time) * 1000ull + (int64_t) b->upd_time.millitm)) ? -1 : 1;
+}
+
 uint8_t check_is_pushed(void *cwp, struct s_client *cl)
 {
 	struct s_pushclient *cl_tmp;
@@ -172,6 +215,11 @@
 	return memcmp(arg, ((const CW*)obj)->cw, 16);
 }
 
+static int compare_cw_cache(const void *arg, const void *obj)
+{
+	return memcmp(arg, ((const CW_CACHE*)obj)->cw, 16);
+}
+
 static bool cwcycle_check_cache(struct s_client *cl, ECM_REQUEST *er, CW *cw)
 {
 	(void)cl; (void)er; (void)cw;
@@ -237,7 +285,7 @@
 		if((!cw->proxy && !cw->localcards) // cw received from ONLY cacheex/csp peers
 			&& check_cw.counter>1
 			&& cw->count < check_cw.counter
-			&& (check_cw.mode || !er->cacheex_wait_time_expired))
+			&& (check_cw.mode == 1 || !er->cacheex_wait_time_expired))
 		{
 			goto out_err;
 		}
@@ -317,9 +365,144 @@
 #endif
 }
 
+CW_CACHE_SETTING get_cw_cache(ECM_REQUEST *er)
+{
+	int32_t i, timediff_old_cw = 0;
+	int8_t mode = 0;
+
+	for(i = 0; i < cfg.cw_cache_settings.cwchecknum; i++)
+	{
+		CWCHECKTAB_DATA *d = &cfg.cw_cache_settings.cwcheckdata[i];
+
+		if(i == 0 && d->caid <= 0)
+		{
+			mode = d->mode;
+			timediff_old_cw = d->counter;
+			continue; //check other, only valid for unset
+		}
+
+		if(d->caid == er->caid || d->caid == er->caid >> 8 || ((d->cmask >= 0 && (er->caid & d->cmask) == d->caid) || d->caid == -1))
+		{
+			if((d->prid >= 0 && d->prid == (int32_t)er->prid) || d->prid == -1)
+			{
+				if((d->srvid >= 0 && d->srvid == er->srvid) || d->srvid == -1)
+				{
+					mode = d->mode;
+					timediff_old_cw = d->counter;
+					break;
+				}
+			}
+		}
+	}
+
+	//check for correct values
+	if(mode>3 || mode<0) mode=0;
+	if(timediff_old_cw<1) timediff_old_cw=0;
+	
+	CW_CACHE_SETTING cw_cache_setting;
+	memset(&cw_cache_setting, 0, sizeof(CW_CACHE_SETTING));
+	cw_cache_setting.mode = mode;
+	cw_cache_setting.timediff_old_cw = timediff_old_cw;
+
+	return cw_cache_setting;
+}
+
+bool cw_cache_check(ECM_REQUEST *er){
+	if(cw_cache_init_done){
+		CW_CACHE_SETTING cw_cache_setting = get_cw_cache(er);
+		if(cw_cache_setting.mode > 0){
+			CW_CACHE *cw_cache = NULL;
+			SAFE_RWLOCK_WRLOCK(&cw_cache_lock);
+			cw_cache = find_hash_table(&ht_cw_cache, &er->cw, sizeof(er->cw), &compare_cw_cache);
+			// add cw to ht_cw_cache if < cw_cache_size
+			if(!cw_cache){
+				// cw_cache-size(count/memory) pre-check
+				if(
+					(cfg.cw_cache_size && (cfg.cw_cache_size > tommy_hashlin_count(&ht_cw_cache)))
+					|| 	(cfg.cw_cache_memory && (cfg.cw_cache_memory*1024*1024 > (2 * tommy_hashlin_memory_usage(&ht_cw_cache))))
+				){
+					if(cs_malloc(&cw_cache, sizeof(CW_CACHE))){
+						memcpy(cw_cache->cw, er->cw, sizeof(er->cw));
+						cw_cache->caid = er->caid;
+						cw_cache->prid = er->prid;
+						cw_cache->srvid = er->srvid;
+						cs_ftime(&cw_cache->first_recv_time);
+						cs_ftime(&cw_cache->upd_time);
+						
+						tommy_hashlin_insert(&ht_cw_cache, &cw_cache->ht_node, cw_cache, tommy_hash_u32(0, &er->cw, sizeof(er->cw)));
+						tommy_list_insert_tail(&ll_cw_cache, &cw_cache->ll_node, cw_cache);
+
+						SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+						return true;
+					}
+					else{
+						SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+						cs_log("[cw_cache] ERROR: NO added HASH to cw_cache!!");
+						return false;
+					}
+				}
+				else{
+					// clean cache call;
+					SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+					cw_cache_cleanup(true);
+					return false;
+				}
+			}
+			// cw found
+			else{
+				char cw1[16*3+2];
+				char cw2[16*3+2];
+				int8_t drop_cw = 0;
+				uint32_t gone_diff = 0;
+				gone_diff = comp_timeb(&er->tps, &cw_cache->first_recv_time);
+
+				if(D_CW_CACHE & cs_dblevel){
+					cs_hexdump(0, cw_cache->cw, 16, cw1, sizeof(cw1));
+					cs_hexdump(0, er->cw, 16, cw2, sizeof(cw2));
+				}
+
+				if(cw_cache->srvid == er->srvid && cw_cache->caid == er->caid){
+					cs_ftime(&cw_cache->upd_time);
+					// late (>cw_cache_setting.timediff_old_cw) cw incoming
+					if(cw_cache_setting.timediff_old_cw > 0 && gone_diff > cw_cache_setting.timediff_old_cw){
+						cs_log_dbg(D_CW_CACHE,"[cw_cache][late CW] cache: %04X:%06X:%04X:%s | in: %04X:%06X:%04X:%s | diff(now): %ums > %d - %s", cw_cache->caid, cw_cache->prid, cw_cache->srvid, cw1, er->caid, er->prid, er->srvid, cw2, gone_diff, cw_cache_setting.timediff_old_cw, er->selected_reader->label);
+						drop_cw=1;
+					}
+				}
+				// same cw for different srvid incoming WTF? => drop
+				else if(cw_cache->srvid != er->srvid){
+					cs_ftime(&cw_cache->upd_time);
+					cs_log_dbg(D_CW_CACHE,"[cw_cache][dupe CW] cache: %04X:%06X:%04X:%s | in: %04X:%06X:%04X:%s | diff(now): %ums - %s", cw_cache->caid, cw_cache->prid, cw_cache->srvid, cw1, er->caid, er->prid, er->srvid, cw2, gone_diff, er->selected_reader->label);
+					drop_cw = 1;
+				}
+
+				if(cw_cache_setting.mode > 1 && drop_cw){
+					// cw_cache->drop_count++;
+					cs_log_dbg(D_CW_CACHE,"[cw_cache] incoming CW dropped - current cw_cache_size: %i - cw_cache-mem-size: %iMiB", count_hash_table(&ht_cw_cache), 2*(int)tommy_hashlin_memory_usage(&ht_cw_cache)/1024/1024);
+					SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+					return false;
+				}
+			}
+			
+			SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+			return true;
+		}
+	}
+	else{
+		cs_log_dbg(D_CW_CACHE,"[cw_cache] cw_cache_init_done %i cfg.cw_cache_size: %u cfg.cw_cache_memory %u", cw_cache_init_done, cfg.cw_cache_size, cfg.cw_cache_memory);
+		return true;
+	}
+	return true;
+}
+
 void add_cache(ECM_REQUEST *er)
 {
 	if(!cache_init_done || !er->csp_hash) return;
+	
+	// cw_cache_check
+	if(!cw_cache_check(er)){
+		return;
+	}
 
 	ECMHASH *result = NULL;
 	CW *cw = NULL;
@@ -334,10 +517,9 @@
 			result->csp_hash = er->csp_hash;
 			init_hash_table(&result->ht_cw, &result->ll_cw);
 			cs_ftime(&result->first_recv_time);
-
 			add_hash_table(&ht_cache, &result->ht_node, &ll_cache, &result->ll_node, result, &result->csp_hash, sizeof(uint32_t));
-
-		}else{
+		}
+		else{
 			SAFE_RWLOCK_UNLOCK(&cache_lock);
 			cs_log("ERROR: NO added HASH to cache!!");
 			return;
@@ -415,10 +597,63 @@
 		sort_list(&result->ll_cw, count_sort);
 
 	SAFE_RWLOCK_UNLOCK(&cache_lock);
-
+	
 	cacheex_cache_add(er, result, cw, add_new_cw);
 }
 
+void cw_cache_cleanup(bool force){
+	if(!cw_cache_init_done)
+		{ return; }
+
+	SAFE_RWLOCK_WRLOCK(&cw_cache_lock);
+	// check cfg-values to force cleanup
+	if(
+		(cfg.cw_cache_size && (cfg.cw_cache_size == tommy_hashlin_count(&ht_cw_cache)))
+		|| 	(cfg.cw_cache_memory && (cfg.cw_cache_memory*1024*1024 < (2 * tommy_hashlin_memory_usage(&ht_cw_cache))))
+	){
+		force=true;
+	}
+
+	if(!force){
+		SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+		return;
+	}
+
+	CW_CACHE *cw_cache;
+	node *i, *i_next;
+	uint32_t ll_c = 0;
+	uint32_t ll_ten_percent = (uint)tommy_list_count(&ll_cw_cache)*0.1; // 10 percent of cache
+
+	sort_list(&ll_cw_cache, time_sort);
+
+	i = get_first_node_list(&ll_cw_cache);
+	while(i)
+	{
+		i_next = i->next;
+		
+		cw_cache = get_data_from_node(i);
+
+		if(!cw_cache)
+		{
+			i = i_next;
+			continue;
+		}
+		++ll_c;
+
+		if(ll_c < ll_ten_percent){
+			remove_elem_list(&ll_cw_cache, &cw_cache->ll_node);
+			remove_elem_hash_table(&ht_cw_cache, &cw_cache->ht_node);
+			NULLFREE(cw_cache);
+		}
+		else{
+			break;
+		}
+		i = i_next;
+	}
+
+	SAFE_RWLOCK_UNLOCK(&cw_cache_lock);
+}
+
 void cleanup_cache(bool force)
 {
 	ECMHASH *ecmhash;
@@ -488,4 +723,4 @@
 		i = i_next;
 	}
 	SAFE_RWLOCK_UNLOCK(&cache_lock);
-}
+}
\ No newline at end of file
--- a/oscam.c
+++ a/oscam.c
@@ -196,6 +196,7 @@
 	printf("                         .  1024 - Client ECM logging.\n");
 	printf("                         .  2048 - CSP logging.\n");
 	printf("                         .  4096 - CWC logging.\n");
+	printf("                         .  8192 - CW Cache logging.\n");
 	printf("                         . 65535 - Debug all.\n");
 	printf("\n Settings:\n");
 	printf(" -p, --pending-ecm <num> | Set the maximum number of pending ECM packets.\n");
@@ -1792,6 +1793,7 @@
 	init_cache();
 	cacheex_init_hitcache();
 	init_config();
+	init_cw_cache();
 	cs_init_log();
 	init_machine_info();
 	init_check();
--- a/module-webif.c
+++ a/module-webif.c
@@ -931,6 +931,15 @@
 
 #ifdef CS_CACHEEX
 	char *value = NULL;
+	
+	value = mk_t_cacheex_cwcheck_valuetab(&cfg.cw_cache_settings);
+	tpl_addVar(vars, TPLADD, "CWCACHESETTINGS", value);
+	free_mk_t(value);
+
+	tpl_printf(vars, TPLADD, "CWCACHESIZE", "%d", cfg.cw_cache_size);
+	
+	tpl_printf(vars, TPLADD, "CWCACHEMEMORY", "%d", cfg.cw_cache_memory);
+
 	value = mk_t_cacheex_valuetab(&cfg.cacheex_wait_timetab);
 	tpl_addVar(vars, TPLADD, "WAIT_TIME", value);
 	free_mk_t(value);
--- a/webif/config/cache.html
+++ a/webif/config/cache.html
@@ -3,5 +3,8 @@
 			<TR><TH COLSPAN="2">Global Cache Settings</TH></TR>
 			<TR><TD><A>Delay:</A></TD><TD><input name="delay" class="withunit short" type="text" maxlength="5" value="##CACHEDELAY##"> ms delaying answers from cache</TD></TR>
 			<TR><TD><A>Max time:</A></TD><TD><input name="max_time" class="withunit short" type="text" maxlength="5" value="##MAXCACHETIME##"> s keep ECMs in cache</TD></TR>
+			<TR><TD><A>CW Cache Settings:</A></TD><TD><input name="cw_cache_settings" type="text" maxlength="320" value="##CWCACHESETTINGS##"><br />Format: caid[&amp;mask][@provid][$servid]:mode:timediff_old_cw[,n]</TD></TR>
+			<TR><TD><A>CW Cache Size:</A></TD><TD><input name="cw_cache_size" class="withunit short" type="text" maxlength="20" value="##CWCACHESIZE##"> count of max. CWs for CW cache </TD></TR>
+			<TR><TD><A>CW Cache Memory:</A></TD><TD><input name="cw_cache_memory" class="withunit short" type="text" maxlength="5" value="##CWCACHEMEMORY##"> MB of max. memory used for CW cache size</TD></TR>
 ##TPLCONFIGCACHEEXCSP##
 ##TPLCONFIGCWCYCLE##
--- a/webif/logpage/logpage_debugmenu.html
+++ a/webif/logpage/logpage_debugmenu.html
@@ -14,5 +14,6 @@
 				<SPAN CLASS="debugl"><A id="debug1024" sendval="1024" CLASS="debugl" HREF="#" TITLE="Client ECM logging">&nbsp;1024&nbsp;</A></SPAN>
 				<SPAN CLASS="debugl"><A id="debug2048" sendval="2048" CLASS="debugl" HREF="#" TITLE="CSP logging">&nbsp;2048&nbsp;</A></SPAN>
 				<SPAN CLASS="debugl"><A id="debug4096" sendval="4096" CLASS="debugl" HREF="#" TITLE="CWC logging">&nbsp;4096&nbsp;</A></SPAN>
+				<SPAN CLASS="debugl"><A id="debug8192" sendval="8192" CLASS="debugl" HREF="#" TITLE="CW Cache logging">&nbsp;8192&nbsp;</A></SPAN>
 				<SPAN CLASS="debugl"><A id="debug65535" sendval="65535" CLASS="debugl" HREF="#" TITLE="debug all">&nbsp;ALL&nbsp;</A></SPAN>
 			</DIV>
\ No newline at end of file
--- a/webif/status/status_sdebug.html
+++ a/webif/status/status_sdebug.html
@@ -14,5 +14,6 @@
 	<SPAN CLASS="debugs"><A CLASS="##DCLASS1024##" HREF="##NEXTPAGE##?debug=##DEBUGVAL1024####CUSTOMPARAM##" TITLE="Client ECM logging">&nbsp;1024&nbsp;</A></SPAN>
 	<SPAN CLASS="debugs"><A CLASS="##DCLASS2048##" HREF="##NEXTPAGE##?debug=##DEBUGVAL2048####CUSTOMPARAM##" TITLE="CSP logging">&nbsp;2048&nbsp;</A></SPAN>
 	<SPAN CLASS="debugs"><A CLASS="##DCLASS4096##" HREF="##NEXTPAGE##?debug=##DEBUGVAL4096####CUSTOMPARAM##" TITLE="CWC logging">&nbsp;4096&nbsp;</A></SPAN>
+	<SPAN CLASS="debugs"><A CLASS="##DCLASS8192##" HREF="##NEXTPAGE##?debug=##DEBUGVAL8192####CUSTOMPARAM##" TITLE="CW Cache logging">&nbsp;8192&nbsp;</A></SPAN>
 	<SPAN CLASS="debugs"><A CLASS="##DCLASS65535##" HREF="##NEXTPAGE##?debug=65535##CUSTOMPARAM##" TITLE="debug all">&nbsp;ALL&nbsp;</A></SPAN>
 </DIV>
--- a/Distribution/doc/html/oscam.1.html
+++ a/Distribution/doc/html/oscam.1.html
@@ -119,6 +119,7 @@
 <BR>&nbsp;&nbsp;<B>1024</B>&nbsp;=&nbsp;client&nbsp;ECM&nbsp;logging
 <BR>&nbsp;&nbsp;<B>2048</B>&nbsp;=&nbsp;CSP&nbsp;logging
 <BR>&nbsp;&nbsp;<B>4096</B>&nbsp;=&nbsp;CWC&nbsp;logging
+<BR>&nbsp;&nbsp;<B>8192</B>&nbsp;=&nbsp;CW&nbsp;Cache&nbsp;logging
 <BR>&nbsp;<B>65535</B>&nbsp;=&nbsp;debug&nbsp;all
 </DL>
 
--- a/globals.h
+++ a/globals.h
@@ -418,9 +418,10 @@
 #define D_CLIENTECM				0x0400	// Debug Client ECMs
 #define D_CSP					0x0800	// Debug CSP
 #define D_CWC					0x1000	// Debug CWC
+#define D_CW_CACHE				0x2000	// Debug CW Cache
 #define D_ALL_DUMP				0xFFFF	// dumps all
 
-#define MAX_DEBUG_LEVELS		13
+#define MAX_DEBUG_LEVELS		14
 
 /////// phoenix readers which need baudrate setting and timings need to be guarded by OSCam: BEFORE R_MOUSE
 #define R_DB2COM1				0x1		// Reader Dbox2 @ com1
@@ -2307,6 +2308,10 @@
 
 	int32_t			max_cache_time;					// seconds ecms are stored in ecmcwcache
 	int32_t			max_hitcache_time;				// seconds hits are stored in cspec_hitcache (to detect dyn wait_time)
+	
+	uint32_t		cw_cache_size;
+	uint32_t		cw_cache_memory;
+	CWCHECKTAB		cw_cache_settings;
 
 	int8_t			reload_useraccounts;
 	int8_t			reload_readers;
--- a/oscam-config-global.c
+++ a/oscam-config-global.c
@@ -632,8 +632,9 @@
 static bool cache_should_save_fn(void *UNUSED(var))
 {
 	return cfg.delay > 0 || cfg.max_cache_time != 15
+			|| cfg.cw_cache_size > 0 || cfg.cw_cache_memory > 0 
 #ifdef CS_CACHEEX
-			|| cfg.cacheex_wait_timetab.cevnum || cfg.cacheex_enable_stats > 0 || cfg.csp_port || cfg.csp.filter_caidtab.cevnum || cfg.csp.allow_request == 0 || cfg.csp.allow_reforward > 0
+			|| cfg.cw_cache_settings.cwchecknum || cfg.cacheex_wait_timetab.cevnum || cfg.cacheex_enable_stats > 0 || cfg.csp_port || cfg.csp.filter_caidtab.cevnum || cfg.csp.allow_request == 0 || cfg.csp.allow_reforward > 0
 #endif
 #ifdef CW_CYCLE_CHECK
 			|| cfg.cwcycle_check_enable || cfg.cwcycle_check_caidtab.ctnum || cfg.maxcyclelist != 500 || cfg.keepcycletime || cfg.onbadcycle || cfg.cwcycle_dropold || cfg.cwcycle_sensitive || cfg.cwcycle_allowbadfromffb || cfg.cwcycle_usecwcfromce
@@ -648,6 +649,9 @@
 	DEF_OPT_UINT32("delay"                , OFS(delay)                  , CS_DELAY),
 	DEF_OPT_INT32("max_time"              , OFS(max_cache_time)         , DEFAULT_MAX_CACHE_TIME),
 #ifdef CS_CACHEEX
+	DEF_OPT_UINT32("cw_cache_size"        , OFS(cw_cache_size)          , 0),
+	DEF_OPT_UINT32("cw_cache_memory"      , OFS(cw_cache_memory)        , 0),
+	DEF_OPT_FUNC("cw_cache_settings"       , OFS(cw_cache_settings)    , cacheex_cwcheck_tab_fn),
 	DEF_OPT_INT32("max_hit_time"          , OFS(max_hitcache_time)      , DEFAULT_MAX_HITCACHE_TIME),
 	DEF_OPT_FUNC("wait_time"              , OFS(cacheex_wait_timetab)   , cacheex_valuetab_fn),
 	DEF_OPT_FUNC("cacheex_mode1_delay"    , OFS(cacheex_mode1_delay_tab), caidvaluetab_fn),
