From 98dd35342fb1315ae260bc2c4043825d7d1feb48 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 10 Apr 2012 15:48:07 +0200 Subject: [PATCH 1/5] cwc: Use "per stream" update id for Cryptoworks and Viaccess CA composed emms This fixes possible shared EMM messages composing issues when multiple streams are sending EMMs to the card reader. Just make sure, that both parts of compose messages are from one "stream". Signed-off-by: Jaroslav Kysela --- src/cwc.c | 23 ++++++++++++++--------- src/cwc.h | 2 +- src/dvb/dvb_tables.c | 11 ++++++----- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/cwc.c b/src/cwc.c index a90c1f3a..e2442ea8 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -243,6 +243,7 @@ typedef struct cwc { int shared_toggle; int shared_len; uint8_t * shared_emm; + void *ca_update_id; } cwc_viaccess_emm; #define cwc_cryptoworks_emm cwc_viaccess_emm @@ -279,10 +280,10 @@ void cwc_emm_conax(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_irdeto(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_dre(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len); -void cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int len); +void cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id); void cwc_emm_nagra(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_nds(cwc_t *cwc, uint8_t *data, int len); -void cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len); +void cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id); /** @@ -1188,7 +1189,7 @@ cwc_emm_cache_lookup(cwc_t *cwc, uint32_t crc) * */ void -cwc_emm(uint8_t *data, int len, uint16_t caid) +cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id) { cwc_t *cwc; @@ -1208,7 +1209,7 @@ cwc_emm(uint8_t *data, int len, uint16_t caid) cwc_emm_seca(cwc, data, len); break; case CARD_VIACCESS: - cwc_emm_viaccess(cwc, data, len); + cwc_emm_viaccess(cwc, data, len, ca_update_id); break; case CARD_DRE: cwc_emm_dre(cwc, data, len); @@ -1220,7 +1221,7 @@ cwc_emm(uint8_t *data, int len, uint16_t caid) cwc_emm_nds(cwc, data, len); break; case CARD_CRYPTOWORKS: - cwc_emm_cryptoworks(cwc, data, len); + cwc_emm_cryptoworks(cwc, data, len, ca_update_id); break; case CARD_UNKNOWN: break; @@ -1382,7 +1383,7 @@ static int via_provider_id(uint8_t * data) void -cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen) +cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen, void *ca_update_id) { /* Get SCT len */ int len = 3 + ((data[1] & 0x0f) << 8) + data[2]; @@ -1414,13 +1415,15 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen) if (cwc->cwc_viaccess_emm.shared_emm) { cwc->cwc_viaccess_emm.shared_len = len; memcpy(cwc->cwc_viaccess_emm.shared_emm, data, len); + cwc->cwc_viaccess_emm.ca_update_id = ca_update_id; } cwc->cwc_viaccess_emm.shared_toggle = data[0]; } } break; case 0x8e: - if (cwc->cwc_viaccess_emm.shared_emm) { + if (cwc->cwc_viaccess_emm.shared_emm && + cwc->cwc_viaccess_emm.ca_update_id == ca_update_id) { int match = 0; int i; /* Match SA and provider in shared */ @@ -1667,7 +1670,7 @@ cwc_emm_nds(cwc_t *cwc, uint8_t *data, int len) } void -cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len) +cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id) { int match = 0; @@ -1686,11 +1689,13 @@ cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len) if (cwc->cwc_cryptoworks_emm.shared_emm) { cwc->cwc_cryptoworks_emm.shared_len = len; memcpy(cwc->cwc_cryptoworks_emm.shared_emm, data, len); + cwc->cwc_cryptoworks_emm.ca_update_id = ca_update_id; } } break; case 0x86: /* emm-sb */ - if (cwc->cwc_cryptoworks_emm.shared_emm) { + if (cwc->cwc_cryptoworks_emm.shared_emm && + cwc->cwc_cryptoworks_emm.ca_update_id == ca_update_id) { /* python: EMM_SH[0:12] + EMM_SB[5:-1] + EMM_SH[12:-1] */ uint32_t elen = len - 5 + cwc->cwc_cryptoworks_emm.shared_len - 12; uint8_t *tmp = malloc(elen); diff --git a/src/cwc.h b/src/cwc.h index da2381bf..3c28710a 100644 --- a/src/cwc.h +++ b/src/cwc.h @@ -23,6 +23,6 @@ void cwc_init(void); void cwc_service_start(struct service *t); -void cwc_emm(uint8_t *data, int len, uint16_t caid); +void cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id); #endif /* CWC_H_ */ diff --git a/src/dvb/dvb_tables.c b/src/dvb/dvb_tables.c index efcd5024..f2e83653 100644 --- a/src/dvb/dvb_tables.c +++ b/src/dvb/dvb_tables.c @@ -44,7 +44,7 @@ #define TDT_CRC 0x1 #define TDT_QUICKREQ 0x2 -#define TDT_INC_TABLE_HDR 0x4 +#define TDT_CA 0x4 static void dvb_table_add_pmt(th_dvb_mux_instance_t *tdmi, int pmt_pid); @@ -214,8 +214,9 @@ dvb_proc_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt, uint8_t *sec, ptr = &sec[3]; if(chkcrc) len -= 4; /* Strip trailing CRC */ - if(tdt->tdt_flags & TDT_INC_TABLE_HDR) - ret = tdt->tdt_callback(tdmi, sec, len + 3, tableid, tdt->tdt_opaque); + if(tdt->tdt_flags & TDT_CA) + ret = tdt->tdt_callback((th_dvb_mux_instance_t *)tdt, + sec, len + 3, tableid, tdt->tdt_opaque); else ret = tdt->tdt_callback(tdmi, ptr, len, tableid, tdt->tdt_opaque); @@ -828,7 +829,7 @@ static int dvb_ca_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, uint8_t tableid, void *opaque) { - cwc_emm(ptr, len, (uintptr_t)opaque); + cwc_emm(ptr, len, (uintptr_t)opaque, (void *)tdmi); return 0; } @@ -864,7 +865,7 @@ dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, break; tdt_add(tdmi, NULL, dvb_ca_callback, (void *)caid, "CA", - TDT_INC_TABLE_HDR, pid, NULL); + TDT_CA, pid, NULL); break; default: From 84842c951c4fded196e27d8a614c06b00a211a4d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 10 Apr 2012 20:51:10 +0200 Subject: [PATCH 2/5] cwc: Allow updating of EMMs only from one channel at a time Signed-off-by: Jaroslav Kysela --- docs/html/config_cwc.html | 3 +++ src/cwc.c | 38 +++++++++++++++++++++++-------- src/webui/static/app/cwceditor.js | 11 +++++++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/docs/html/config_cwc.html b/docs/html/config_cwc.html index 3877d541..24a5a251 100644 --- a/docs/html/config_cwc.html +++ b/docs/html/config_cwc.html @@ -51,6 +51,9 @@
Update Card
Forward Entitlement Management Messages (EMMs) to the server. +
Update One +
Forward EMMs only from one channel at a time. +
Comment
Allows the administrator to set a comment only visible in this editor. It does not serve any active purpose. diff --git a/src/cwc.c b/src/cwc.c index e2442ea8..7db23099 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -247,6 +247,10 @@ typedef struct cwc { } cwc_viaccess_emm; #define cwc_cryptoworks_emm cwc_viaccess_emm + /* one update id */ + int64_t cwc_update_time; + void *cwc_update_id; + /* Card type */ card_type_t cwc_card_type; @@ -261,6 +265,7 @@ typedef struct cwc { int cwc_port; char *cwc_id; int cwc_emm; + int cwc_emmex; const char *cwc_errtxt; @@ -280,10 +285,10 @@ void cwc_emm_conax(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_irdeto(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_dre(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len); -void cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id); +void cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_nagra(cwc_t *cwc, uint8_t *data, int len); void cwc_emm_nds(cwc_t *cwc, uint8_t *data, int len); -void cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id); +void cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len); /** @@ -1198,6 +1203,15 @@ cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id) TAILQ_FOREACH(cwc, &cwcs, cwc_link) { if(cwc->cwc_caid == caid && cwc->cwc_forward_emm && cwc->cwc_writer_running) { + if (cwc->cwc_emmex) { + if (cwc->cwc_update_id != ca_update_id) { + int64_t delta = getmonoclock() - cwc->cwc_update_time; + if (delta < 25000000UL) /* 25 seconds */ + continue; + } + cwc->cwc_update_time = getmonoclock(); + } + cwc->cwc_update_id = ca_update_id; switch (cwc->cwc_card_type) { case CARD_CONAX: cwc_emm_conax(cwc, data, len); @@ -1209,7 +1223,7 @@ cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id) cwc_emm_seca(cwc, data, len); break; case CARD_VIACCESS: - cwc_emm_viaccess(cwc, data, len, ca_update_id); + cwc_emm_viaccess(cwc, data, len); break; case CARD_DRE: cwc_emm_dre(cwc, data, len); @@ -1221,7 +1235,7 @@ cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id) cwc_emm_nds(cwc, data, len); break; case CARD_CRYPTOWORKS: - cwc_emm_cryptoworks(cwc, data, len, ca_update_id); + cwc_emm_cryptoworks(cwc, data, len); break; case CARD_UNKNOWN: break; @@ -1383,7 +1397,7 @@ static int via_provider_id(uint8_t * data) void -cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen, void *ca_update_id) +cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen) { /* Get SCT len */ int len = 3 + ((data[1] & 0x0f) << 8) + data[2]; @@ -1415,7 +1429,7 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen, void *ca_update_id) if (cwc->cwc_viaccess_emm.shared_emm) { cwc->cwc_viaccess_emm.shared_len = len; memcpy(cwc->cwc_viaccess_emm.shared_emm, data, len); - cwc->cwc_viaccess_emm.ca_update_id = ca_update_id; + cwc->cwc_viaccess_emm.ca_update_id = cwc->cwc_update_id; } cwc->cwc_viaccess_emm.shared_toggle = data[0]; } @@ -1423,7 +1437,7 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen, void *ca_update_id) break; case 0x8e: if (cwc->cwc_viaccess_emm.shared_emm && - cwc->cwc_viaccess_emm.ca_update_id == ca_update_id) { + cwc->cwc_viaccess_emm.ca_update_id == cwc->cwc_update_id) { int match = 0; int i; /* Match SA and provider in shared */ @@ -1670,7 +1684,7 @@ cwc_emm_nds(cwc_t *cwc, uint8_t *data, int len) } void -cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id) +cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len) { int match = 0; @@ -1689,13 +1703,13 @@ cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len, void *ca_update_id) if (cwc->cwc_cryptoworks_emm.shared_emm) { cwc->cwc_cryptoworks_emm.shared_len = len; memcpy(cwc->cwc_cryptoworks_emm.shared_emm, data, len); - cwc->cwc_cryptoworks_emm.ca_update_id = ca_update_id; + cwc->cwc_cryptoworks_emm.ca_update_id = cwc->cwc_update_id; } } break; case 0x86: /* emm-sb */ if (cwc->cwc_cryptoworks_emm.shared_emm && - cwc->cwc_cryptoworks_emm.ca_update_id == ca_update_id) { + cwc->cwc_cryptoworks_emm.ca_update_id == cwc->cwc_update_id) { /* python: EMM_SH[0:12] + EMM_SB[5:-1] + EMM_SH[12:-1] */ uint32_t elen = len - 5 + cwc->cwc_cryptoworks_emm.shared_len - 12; uint8_t *tmp = malloc(elen); @@ -1998,6 +2012,7 @@ cwc_record_build(cwc_t *cwc) htsmsg_add_str(e, "deskey", buf); htsmsg_add_u32(e, "emm", cwc->cwc_emm); + htsmsg_add_u32(e, "emmex", cwc->cwc_emmex); htsmsg_add_str(e, "comment", cwc->cwc_comment ?: ""); return e; @@ -2084,6 +2099,9 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate) if(!htsmsg_get_u32(values, "emm", &u32)) cwc->cwc_emm = u32; + if(!htsmsg_get_u32(values, "emmex", &u32)) + cwc->cwc_emmex = u32; + cwc->cwc_reconfigure = 1; if(cwc->cwc_fd != -1) diff --git a/src/webui/static/app/cwceditor.js b/src/webui/static/app/cwceditor.js index 99daadf1..ac5f610a 100644 --- a/src/webui/static/app/cwceditor.js +++ b/src/webui/static/app/cwceditor.js @@ -14,6 +14,12 @@ tvheadend.cwceditor = function() { width: 100 }); + var emmexColumn = new Ext.grid.CheckColumn({ + header: "Update One", + dataIndex: 'emmex', + width: 100 + }); + function setMetaAttr(meta, record){ var enabled = record.get('enabled'); if(!enabled) return; @@ -72,6 +78,7 @@ tvheadend.cwceditor = function() { editor: new fm.TextField({allowBlank: false}) }, emmColumn, + emmexColumn, { header: "Comment", dataIndex: 'comment', @@ -86,7 +93,7 @@ tvheadend.cwceditor = function() { var rec = Ext.data.Record.create([ 'enabled', 'connected', 'hostname', 'port', 'username', - 'password', 'deskey', 'emm', 'comment' + 'password', 'deskey', 'emm', 'emmex', 'comment' ]); var store = new Ext.data.JsonStore({ @@ -99,7 +106,7 @@ tvheadend.cwceditor = function() { }); var grid = new tvheadend.tableEditor('Code Word Client', 'cwc', cm, rec, - [enabledColumn, emmColumn], store, + [enabledColumn, emmColumn, emmexColumn], store, 'config_cwc.html', 'key'); tvheadend.comet.on('cwcStatus', function(msg) { From 39d1600bf984d255dd8d15d1dbfd489a9ebd0f9f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 12 Apr 2012 14:35:06 +0200 Subject: [PATCH 3/5] cwc: Use only one fastest ECM reader Use only one - fastest - ECM reader when multiple CA readers/cards are available for one program. Signed-off-by: Jaroslav Kysela --- src/cwc.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/cwc.c b/src/cwc.c index 7db23099..9be063c6 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -151,7 +151,8 @@ typedef struct cwc_service { enum { CS_UNKNOWN, CS_RESOLVED, - CS_FORBIDDEN + CS_FORBIDDEN, + CS_IDLE } cs_keystate; void *cs_keys; @@ -742,6 +743,8 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, int len, int seq) { service_t *t = ct->cs_service; + cwc_service_t *ct2; + cwc_t *cwc2; ecm_pid_t *ep; char chaninfo[32]; int i; @@ -800,12 +803,25 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, msg[3 + 5], msg[3 + 6], msg[3 + 7], msg[3 + 8], msg[3 + 9], msg[3 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14], msg[3 + 15], seq, delay); + + TAILQ_FOREACH(cwc2, &cwcs, cwc_link) { + LIST_FOREACH(ct2, &cwc2->cwc_services, cs_link) { + if (ct != ct2 && ct2->cs_service == t && + ct2->cs_keystate == CS_RESOLVED) { + ct->cs_keystate = CS_IDLE; + tvhlog(LOG_DEBUG, "cwc", + "Already has a key for service \"%s\", from %s:%i", + t->s_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port); + return; + } + } + } if(ct->cs_keystate != CS_RESOLVED) tvhlog(LOG_INFO, "cwc", "Obtained key for for service \"%s\" in %lld ms, from %s", t->s_svcname, delay, ct->cs_cwc->cwc_hostname); - + ct->cs_keystate = CS_RESOLVED; memcpy(ct->cs_cw, msg + 3, 16); ct->cs_pending_cw_update = 1; @@ -1519,6 +1535,9 @@ cwc_table_input(struct th_descrambler *td, struct service *t, char chaninfo[32]; caid_t *c; + if (ct->cs_keystate == CS_IDLE) + return; + if(len > 4096) return; From e5eef814f2312429a7b3cffb1458f9af1c528cf8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 12 Apr 2012 14:42:26 +0200 Subject: [PATCH 4/5] cwc: Use hostname:port notation in log messages Show all cwc connection information to users. Multiple card readers can be configured on same IP but different ports. Signed-off-by: Jaroslav Kysela --- src/cwc.c | 93 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/src/cwc.c b/src/cwc.c index 9be063c6..49b5b554 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -591,10 +591,10 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len) memcpy(cwc->cwc_ua, &msg[6], 8); - tvhlog(LOG_INFO, "cwc", "%s: Connected as user 0x%02x " + tvhlog(LOG_INFO, "cwc", "%s:%i: Connected as user 0x%02x " "to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] " "with %d providers", - cwc->cwc_hostname, + cwc->cwc_hostname, cwc->cwc_port, msg[3], n, cwc->cwc_caid, cwc->cwc_ua[0], cwc->cwc_ua[1], cwc->cwc_ua[2], cwc->cwc_ua[3], cwc->cwc_ua[4], cwc->cwc_ua[5], cwc->cwc_ua[6], cwc->cwc_ua[7], nprov); @@ -617,8 +617,8 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len) cwc->cwc_providers[i].sa[6] = msg[9]; cwc->cwc_providers[i].sa[7] = msg[10]; - tvhlog(LOG_INFO, "cwc", "%s: Provider ID #%d: 0x%06x %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x", - cwc->cwc_hostname, i + 1, + tvhlog(LOG_INFO, "cwc", "%s:%i: Provider ID #%d: 0x%06x %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x", + cwc->cwc_hostname, cwc->cwc_port, i + 1, cwc->cwc_providers[i].id, cwc->cwc_providers[i].sa[0], cwc->cwc_providers[i].sa[1], @@ -641,16 +641,16 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len) if (!emm_allowed) { tvhlog(LOG_INFO, "cwc", - "%s: Will not forward EMMs (not allowed by server)", - cwc->cwc_hostname); + "%s:%i: Will not forward EMMs (not allowed by server)", + cwc->cwc_hostname, cwc->cwc_port); } else if (cwc->cwc_card_type != CARD_UNKNOWN) { - tvhlog(LOG_INFO, "cwc", "%s: Will forward EMMs", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: Will forward EMMs", + cwc->cwc_hostname, cwc->cwc_port); cwc->cwc_forward_emm = 1; } else { tvhlog(LOG_INFO, "cwc", - "%s: Will not forward EMMs (unsupported CA system)", - cwc->cwc_hostname); + "%s:%i: Will not forward EMMs (unsupported CA system)", + cwc->cwc_hostname, cwc->cwc_port); } } @@ -673,43 +673,43 @@ cwc_detect_card_type(cwc_t *cwc) case 0x17: case 0x06: cwc->cwc_card_type = CARD_IRDETO; - tvhlog(LOG_INFO, "cwc", "%s: irdeto card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: irdeto card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x05: cwc->cwc_card_type = CARD_VIACCESS; - tvhlog(LOG_INFO, "cwc", "%s: viaccess card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: viaccess card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x0b: cwc->cwc_card_type = CARD_CONAX; - tvhlog(LOG_INFO, "cwc", "%s: conax card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: conax card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x01: cwc->cwc_card_type = CARD_SECA; - tvhlog(LOG_INFO, "cwc", "%s: seca card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: seca card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x4a: cwc->cwc_card_type = CARD_DRE; - tvhlog(LOG_INFO, "cwc", "%s: dre card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: dre card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x18: cwc->cwc_card_type = CARD_NAGRA; - tvhlog(LOG_INFO, "cwc", "%s: nagra card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: nagra card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x09: cwc->cwc_card_type = CARD_NDS; - tvhlog(LOG_INFO, "cwc", "%s: nds card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: nds card", + cwc->cwc_hostname, cwc->cwc_port); break; case 0x0d: cwc->cwc_card_type = CARD_CRYPTOWORKS; - tvhlog(LOG_INFO, "cwc", "%s: cryptoworks card", - cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: cryptoworks card", + cwc->cwc_hostname, cwc->cwc_port); break; default: cwc->cwc_card_type = CARD_UNKNOWN; @@ -819,8 +819,9 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, if(ct->cs_keystate != CS_RESOLVED) tvhlog(LOG_INFO, "cwc", - "Obtained key for for service \"%s\" in %lld ms, from %s", - t->s_svcname, delay, ct->cs_cwc->cwc_hostname); + "Obtained key for service \"%s\" in %lld ms, from %s:%i", + t->s_svcname, delay, ct->cs_cwc->cwc_hostname, + ct->cs_cwc->cwc_port); ct->cs_keystate = CS_RESOLVED; memcpy(ct->cs_cw, msg + 3, 16); @@ -907,15 +908,15 @@ cwc_read_message(cwc_t *cwc, const char *state, int timeout) int msglen, r; if((r = cwc_read(cwc, buf, 2, timeout))) { - tvhlog(LOG_INFO, "cwc", "%s: %s: Read error (header): %s", - cwc->cwc_hostname, state, strerror(r)); + tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Read error (header): %s", + cwc->cwc_hostname, cwc->cwc_port, state, strerror(r)); return -1; } msglen = (buf[0] << 8) | buf[1]; if(msglen >= CWS_NETMSGSIZE) { - tvhlog(LOG_INFO, "cwc", "%s: %s: Invalid message size: %d", - cwc->cwc_hostname, state, msglen); + tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Invalid message size: %d", + cwc->cwc_hostname, cwc->cwc_port, state, msglen); return -1; } @@ -923,14 +924,14 @@ cwc_read_message(cwc_t *cwc, const char *state, int timeout) so just wait 1 second here */ if((r = cwc_read(cwc, cwc->cwc_buf + 2, msglen, 1000))) { - tvhlog(LOG_INFO, "cwc", "%s: %s: Read error: %s", - cwc->cwc_hostname, state, strerror(r)); + tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Read error: %s", + cwc->cwc_hostname, cwc->cwc_port, state, strerror(r)); return -1; } if((msglen = des_decrypt(cwc->cwc_buf, msglen + 2, cwc)) < 15) { - tvhlog(LOG_INFO, "cwc", "%s: %s: Decrypt failed", - state, cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Decrypt failed", + cwc->cwc_hostname, cwc->cwc_port, state); return -1; } return msglen; @@ -992,8 +993,8 @@ cwc_session(cwc_t *cwc) * Get login key */ if((r = cwc_read(cwc, cwc->cwc_buf, 14, 5000))) { - tvhlog(LOG_INFO, "cwc", "%s: No login key received: %s", - cwc->cwc_hostname, strerror(r)); + tvhlog(LOG_INFO, "cwc", "%s:%i: No login key received: %s", + cwc->cwc_hostname, cwc->cwc_port, strerror(r)); return; } @@ -1008,7 +1009,8 @@ cwc_session(cwc_t *cwc) return; if(cwc->cwc_buf[12] != MSG_CLIENT_2_SERVER_LOGIN_ACK) { - tvhlog(LOG_INFO, "cwc", "%s: Login failed", cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: Login failed", + cwc->cwc_hostname, cwc->cwc_port); return; } @@ -1022,7 +1024,8 @@ cwc_session(cwc_t *cwc) return; if(cwc->cwc_buf[12] != MSG_CARD_DATA) { - tvhlog(LOG_INFO, "cwc", "%s: Card data request failed", cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i: Card data request failed", + cwc->cwc_hostname, cwc->cwc_port); return; } @@ -1124,7 +1127,8 @@ cwc_thread(void *aux) cwc->cwc_caid = 0; cwc->cwc_connected = 0; cwc_comet_status_update(cwc); - tvhlog(LOG_INFO, "cwc", "Disconnected from %s", cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "Disconnected from %s:%i", + cwc->cwc_hostname, cwc->cwc_port); } if(subscriptions_active()) { @@ -1139,13 +1143,14 @@ cwc_thread(void *aux) ts.tv_nsec = 0; tvhlog(LOG_INFO, "cwc", - "%s: Automatic connection attempt in in %d seconds", - cwc->cwc_hostname, d); + "%s:%i: Automatic connection attempt in in %d seconds", + cwc->cwc_hostname, cwc->cwc_port, d); pthread_cond_timedwait(&cwc_config_changed, &cwc_mutex, &ts); } - tvhlog(LOG_INFO, "cwc", "%s destroyed", cwc->cwc_hostname); + tvhlog(LOG_INFO, "cwc", "%s:%i destroyed", + cwc->cwc_hostname, cwc->cwc_port); while((ct = LIST_FIRST(&cwc->cwc_services)) != NULL) { t = ct->cs_service; From c8af1f21d499d5cb1f37ca160db23993da9b3b9f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 12 Apr 2012 20:03:46 +0200 Subject: [PATCH 5/5] cwc: do not send ECM requests when NOKs are received Do not send ECM requests to the card reader when ECMs cannot be read. Signed-off-by: Jaroslav Kysela --- src/cwc.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/cwc.c b/src/cwc.c index 49b5b554..34bc004e 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -765,20 +765,48 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, if(ct->cs_okchannel == es->es_channel) ct->cs_okchannel = -1; + if (es->es_nok < 3) + es->es_nok++; + if(ct->cs_keystate == CS_FORBIDDEN) return; // We already know it's bad - es->es_nok = 1; + if (es->es_nok > 2) { + tvhlog(LOG_DEBUG, "cwc", + "Too many NOKs for service \"%s\"%s from %s:%i", + t->s_svcname, chaninfo, ct->cs_cwc->cwc_hostname, + ct->cs_cwc->cwc_port); + goto forbid; + } + + TAILQ_FOREACH(cwc2, &cwcs, cwc_link) { + LIST_FOREACH(ct2, &cwc2->cwc_services, cs_link) { + if (ct != ct2 && ct2->cs_service == t && + ct2->cs_keystate == CS_RESOLVED) { + tvhlog(LOG_DEBUG, "cwc", + "NOK from %s:%i: Already has a key for service \"%s\", from %s:%i", + ct->cs_cwc->cwc_hostname, ct->cs_cwc->cwc_port, + t->s_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port); + es->es_nok = 3; /* do not send more ECM requests */ + goto forbid; + } + } + } tvhlog(LOG_DEBUG, "cwc", "Received NOK for service \"%s\"%s (seqno: %d " "Req delay: %lld ms)", t->s_svcname, chaninfo, seq, delay); +forbid: LIST_FOREACH(ep, &ct->cs_pids, ep_link) { for(i = 0; i <= ep->ep_last_section; i++) - if(ep->ep_sections[i] == NULL || - ep->ep_sections[i]->es_pending || - ep->ep_sections[i]->es_nok == 0) - return; + if(ep->ep_sections[i] == NULL) { + if(es->es_nok < 2) /* only first hit is allowed */ + return; + } else { + if(ep->ep_sections[i]->es_pending || + ep->ep_sections[i]->es_nok == 0) + return; + } } tvhlog(LOG_ERR, "cwc", "Can not descramble service \"%s\", access denied (seqno: %d " @@ -1594,6 +1622,9 @@ cwc_table_input(struct th_descrambler *td, struct service *t, es = ep->ep_sections[section]; + if (es->es_nok > 2) + break; /* too many NOK responses in a row */ + if(es->es_ecmsize == len && !memcmp(es->es_ecm, data, len)) break; /* key already sent */