From: Jaroslav Kysela Date: Thu, 4 Jan 2018 12:44:00 +0000 (+0100) Subject: cccam: implement card remove operation X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=068c222988ebf9618dc10715e2c73aa540995a7c;p=thirdparty%2Ftvheadend.git cccam: implement card remove operation --- diff --git a/src/descrambler/cccam.c b/src/descrambler/cccam.c index 1f753d307..71545c585 100644 --- a/src/descrambler/cccam.c +++ b/src/descrambler/cccam.c @@ -343,9 +343,10 @@ cccam_decode_card_data_reply(cccam_t *cccam, uint8_t *msg) caclient_set_status((caclient_t *)cccam, CACLIENT_STATUS_CONNECTED); cccam_set_ua(ua, msg + 16); - pcard = cc_new_card((cclient_t *)cccam, (msg[12] << 8) | msg[13], ua, nprov, pid, psa); + pcard = cc_new_card((cclient_t *)cccam, (msg[12] << 8) | msg[13], + (msg[4] << 24) | (msg[5] << 16) | (msg[6] << 8) | msg[7], + ua, nprov, pid, psa); if (pcard) { - pcard->cccam.cs_id = (msg[4] << 24) | (msg[5] << 16) | (msg[6] << 8) | msg[7]; pcard->cccam.cs_remote_id = (msg[8] << 24) | (msg[9] << 16) | (msg[10] << 8) | msg[11]; pcard->cccam.cs_hop = msg[14]; pcard->cccam.cs_reshare = msg[15]; @@ -364,7 +365,7 @@ cccam_handle_keys(cccam_t *cccam, cc_service_t *ct, cc_ecm_section_t *es, uint8_t *dcw_even, *dcw_odd, _dcw[16]; if (!cccam->cccam_extended) { - cccam_decrypt_cw(cccam->cccam_nodeid, es->cccam.es_card_id, buf + 4); + cccam_decrypt_cw(cccam->cccam_nodeid, es->es_card_id, buf + 4); memcpy(_dcw, buf + 4, 16); cccam_decrypt(&cccam->recvblock, buf + 4, len - 4); } else { @@ -412,6 +413,7 @@ cccam_running_reply(cccam_t *cccam, uint8_t *buf, int len) { cc_service_t *ct; cc_ecm_section_t *es; + uint32_t cardid; uint8_t seq; if (len < 4) @@ -428,7 +430,11 @@ cccam_running_reply(cccam_t *cccam, uint8_t *buf, int len) cccam_decode_card_data_reply(cccam, buf); break; case MSG_CARD_REMOVED: - tvhtrace(cccam->cc_subsys, "%s: del card message received", cccam->cc_name); + if (len >= 8) { + cardid = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; + tvhtrace(cccam->cc_subsys, "%s: del card %08X message received", cccam->cc_name, cardid); + cc_remove_card_by_id((cclient_t *)cccam, cardid); + } break; case MSG_KEEPALIVE: tvhtrace(cccam->cc_subsys, "%s: keepalive", cccam->cc_name); @@ -766,8 +772,8 @@ cccam_send_ecm(void *cc, cc_service_t *ct, cc_ecm_section_t *es, seq = atomic_add(&cccam->cc_seq, 1); caid = es->es_caid; provid = es->es_provid; - card_id = pcard->cccam.cs_id; - es->cccam.es_card_id = card_id; + card_id = pcard->cs_id; + es->es_card_id = card_id; sid = t->s_dvb_service_id; buf = alloca(len + 13); @@ -816,7 +822,7 @@ cccam_send_emm(void *cc, cc_service_t *ct, cc_card_data_t *pcard, seq = atomic_add(&cccam->cc_seq, 1); caid = pcard->cs_ra.caid; - card_id = pcard->cccam.cs_id; + card_id = pcard->cs_id; buf = alloca(len + 12); buf[ 0] = caid >> 8; diff --git a/src/descrambler/cclient.c b/src/descrambler/cclient.c index b0921feb3..cb8bbb40c 100644 --- a/src/descrambler/cclient.c +++ b/src/descrambler/cclient.c @@ -25,9 +25,7 @@ #include "cclient.h" #include "tvhpoll.h" -static void cc_service_pid_free(cc_service_t *ct); - -/** +/* * */ static int @@ -40,26 +38,100 @@ cc_check_empty(const uint8_t *str, int len) return 1; } +/** + * + */ +static void +cc_free_ecm_section(cc_ecm_section_t *es) +{ + LIST_REMOVE(es, es_link); + free(es); +} + +/** + * + */ +static void +cc_free_ecm_pid(cc_ecm_pid_t *ep) +{ + cc_ecm_section_t *es; + while ((es = LIST_FIRST(&ep->ep_sections)) != NULL) + cc_free_ecm_section(es); + LIST_REMOVE(ep, ep_link); + free(ep); +} + +/** + * + */ +static void +cc_service_ecm_pid_free(cc_service_t *ct) +{ + cc_ecm_pid_t *ep; + + while((ep = LIST_FIRST(&ct->cs_ecm_pids)) != NULL) + cc_free_ecm_pid(ep); +} + +/** + * + */ +static void +cc_free_card(cc_card_data_t *cd) +{ + LIST_REMOVE(cd, cs_card); + descrambler_close_emm(cd->cs_mux, cd, cd->cs_ra.caid); + emm_reass_done(&cd->cs_ra); + free(cd); +} + +/** + * + */ +static void +cc_free_cards(cclient_t *cc) +{ + cc_card_data_t *cd; + + while((cd = LIST_FIRST(&cc->cc_cards)) != NULL) + cc_free_card(cd); +} + +/** + * + */ +char * +cc_get_card_name(cc_card_data_t *pcard, char *buf, size_t buflen) +{ + snprintf(buf, buflen, "ID:%08x CAID:%04x with %d provider%s", + pcard->cs_id, pcard->cs_ra.caid, pcard->cs_ra.providers_count, + pcard->cs_ra.providers_count != 1 ? "s" : ""); + return buf; +} + /** * */ cc_card_data_t * -cc_new_card(cclient_t *cc, uint16_t caid, uint8_t *ua, +cc_new_card(cclient_t *cc, uint16_t caid, uint32_t cardid, uint8_t *ua, int pcount, uint8_t **pid, uint8_t **psa) { cc_card_data_t *pcard = NULL; emm_provider_t *ep; const char *n; const uint8_t *id, *sa; - int i, allocated = 0; + int i, j, c, allocated = 0; + char buf[256]; LIST_FOREACH(pcard, &cc->cc_cards, cs_card) - if (pcard->cs_ra.caid == caid) + if (pcard->cs_ra.caid == caid && + pcard->cs_id == cardid) break; if (pcard == NULL) { pcard = calloc(1, sizeof(cc_card_data_t)); emm_reass_init(&pcard->cs_ra, caid); + pcard->cs_id = cardid; allocated = 1; } @@ -87,30 +159,44 @@ cc_new_card(cclient_t *cc, uint16_t caid, uint8_t *ua, if (ua) { tvhinfo(cc->cc_subsys, "%s: Connected as user %s " - "to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] " + "to a %s-card-%08x [CAID:%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] " "with %d provider%s", - cc->cc_name, cc->cc_username, n, caid, + cc->cc_name, cc->cc_username, n, cardid, caid, ua[0], ua[1], ua[2], ua[3], ua[4], ua[5], ua[6], ua[7], - pcount, pcount > 1 ? "s" : ""); + pcount, pcount != 1 ? "s" : ""); } else { tvhinfo(cc->cc_subsys, "%s: Connected as user %s " - "to a %s-card [0x%04x] with %d provider%s", - cc->cc_name, cc->cc_username, n, caid, - pcount, pcount > 1 ? "s" : ""); + "to a %s-card-%08x [CAID:%04x] with %d provider%s", + cc->cc_name, cc->cc_username, n, cardid, caid, + pcount, pcount != 1 ? "s" : ""); } - for (i = 0, ep = pcard->cs_ra.providers; i < pcount; i++, ep++) { + buf[0] = '\0'; + for (i = j = c = 0, ep = pcard->cs_ra.providers; i < pcount; i++, ep++) { if (psa && !cc_check_empty(ep->sa, 8)) { sa = ep->sa; - tvhinfo(cc->cc_subsys, "%s: Provider ID #%d: 0x%04x:0x%06x %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x", - cc->cc_name, i + 1, caid, ep->id, - sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7]); + if (buf[0]) { + tvhdebug(cc->cc_subsys, "%s: Providers: ID:%08x CAID:%04X:[%s]", + cc->cc_name, cardid, caid, buf); + buf[0] = '\0'; + c = 0; + } + tvhdebug(cc->cc_subsys, "%s: Provider ID #%d: 0x%04x:0x%06x %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x", + cc->cc_name, i + 1, caid, ep->id, + sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7]); } else { - tvhinfo(cc->cc_subsys, "%s: Provider ID #%d: 0x%04x:0x%06x", - cc->cc_name, i + 1, caid, ep->id); + tvh_strlcatf(buf, sizeof(buf), c, "%s0x%06x", c > 0 ? "," : "", ep->id); + if (++j > 5) { + tvhdebug(cc->cc_subsys, "%s: Providers: ID:%08x CAID:%04X:[%s]", + cc->cc_name, cardid, caid, buf); + buf[0] = '\0'; + c = j = 0; + } } } - + if (j > 0) + tvhdebug(cc->cc_subsys, "%s: Providers: ID:%08x CAID:%04X:[%s]", + cc->cc_name, cardid, caid, buf); if (cc->cc_emm && ua) { ua = pcard->cs_ra.ua; i = ua[0] || ua[1] || ua[2] || ua[3] || @@ -125,6 +211,61 @@ cc_new_card(cclient_t *cc, uint16_t caid, uint8_t *ua, return pcard; } +/** + * + */ +void +cc_remove_card(cclient_t *cc, cc_card_data_t *pcard) +{ + cc_service_t *ct; + cc_ecm_pid_t *ep, *epn; + cc_ecm_section_t *es, *esn; + emm_provider_t *emmp; + char buf[256]; + int i; + + tvhinfo(cc->cc_subsys, "%s: card %s removed", cc->cc_name, + cc_get_card_name(pcard, buf, sizeof(buf))); + + /* invalidate all requests */ + LIST_FOREACH(ct, &cc->cc_services, cs_link) { + for (ep = LIST_FIRST(&ct->cs_ecm_pids); ep; ep = epn) { + epn = LIST_NEXT(ep, ep_link); + for (es = LIST_FIRST(&ep->ep_sections); es; es = esn) { + esn = LIST_NEXT(es, es_link); + if (es->es_caid == pcard->cs_ra.caid) { + emmp = pcard->cs_ra.providers; + for (i = 0; i < pcard->cs_ra.providers_count; i++, emmp++) + if (emmp->id == es->es_provid) { + cc_free_ecm_section(es); + break; + } + } + } + es = esn; + } + if (LIST_EMPTY(&ep->ep_sections)) + cc_free_ecm_pid(ep); + } + + cc_free_card(pcard); +} + +/** + * + */ +void +cc_remove_card_by_id(cclient_t *cc, uint32_t id) +{ + cc_card_data_t *pcard; + + LIST_FOREACH(pcard, &cc->cc_cards, cs_card) + if (pcard->cs_id == id) { + cc_remove_card(cc, pcard); + break; + } +} + /** * */ @@ -138,7 +279,7 @@ cc_ecm_reset(th_descrambler_t *th) pthread_mutex_lock(&cc->cc_mutex); descrambler_change_keystate(th, DS_READY, 1); - LIST_FOREACH(ep, &ct->cs_pids, ep_link) + LIST_FOREACH(ep, &ct->cs_ecm_pids, ep_link) LIST_FOREACH(es, &ep->ep_sections, es_link) es->es_keystate = ES_UNKNOWN; ct->ecm_state = ECM_RESET; @@ -158,7 +299,7 @@ cc_ecm_idle(th_descrambler_t *th) cc_ecm_section_t *es; pthread_mutex_lock(&cc->cc_mutex); - LIST_FOREACH(ep, &ct->cs_pids, ep_link) + LIST_FOREACH(ep, &ct->cs_ecm_pids, ep_link) LIST_FOREACH(es, &ep->ep_sections, es_link) es->es_keystate = ES_IDLE; ct->ecm_state = ECM_RESET; @@ -219,7 +360,7 @@ cc_ecm_reply(cc_service_t *ct, cc_ecm_section_t *es, forbid: i = 0; - LIST_FOREACH(ep, &ct->cs_pids, ep_link) + LIST_FOREACH(ep, &ct->cs_ecm_pids, ep_link) LIST_FOREACH(es2, &ep->ep_sections, es_link) if(es2 && es2 != es && es2->es_nok == 0) { if (es2->es_pending) @@ -230,7 +371,7 @@ forbid: return; es->es_keystate = ES_FORBIDDEN; - LIST_FOREACH(ep, &ct->cs_pids, ep_link) { + LIST_FOREACH(ep, &ct->cs_ecm_pids, ep_link) { LIST_FOREACH(es2, &ep->ep_sections, es_link) if (es2->es_keystate == ES_UNKNOWN || es2->es_keystate == ES_RESOLVED) @@ -305,7 +446,7 @@ cc_find_pending_section(cclient_t *cc, uint32_t seq, cc_service_t **_ct) if (_ct) *_ct = NULL; LIST_FOREACH(ct, &cc->cc_services, cs_link) - LIST_FOREACH(ep, &ct->cs_pids, ep_link) + LIST_FOREACH(ep, &ct->cs_ecm_pids, ep_link) LIST_FOREACH(es, &ep->ep_sections, es_link) if(es->es_seq == seq) { if (es->es_resolved) { @@ -340,22 +481,6 @@ cc_invalidate_cards(cclient_t *cc) cd->cs_running = 0; } -/** - * - */ -static void -cc_free_cards(cclient_t *cc) -{ - cc_card_data_t *cd; - - while((cd = LIST_FIRST(&cc->cc_cards)) != NULL) { - LIST_REMOVE(cd, cs_card); - descrambler_close_emm(cd->cs_mux, cd, cd->cs_ra.caid); - emm_reass_done(&cd->cs_ra); - free(cd); - } -} - /** * */ @@ -549,7 +674,7 @@ cc_thread(void *aux) break; } - tvhinfo(cc->cc_subsys, "%s: Connected", cc->cc_name); + tvhdebug(cc->cc_subsys, "%s: Connected", cc->cc_name); attempts = 0; cc->cc_fd = fd; @@ -718,7 +843,7 @@ cc_table_input(void *opaque, int pid, const uint8_t *data, int len, int emm) if (ct->ecm_state == ECM_RESET) { /* clean all */ - cc_service_pid_free(ct); + cc_service_ecm_pid_free(ct); /* move to init state */ ct->ecm_state = ECM_INIT; ct->cs_capid = 0xffff; @@ -727,7 +852,7 @@ cc_table_input(void *opaque, int pid, const uint8_t *data, int len, int emm) cc->cc_name, t->s_dvb_svcname); } - LIST_FOREACH(ep, &ct->cs_pids, ep_link) + LIST_FOREACH(ep, &ct->cs_ecm_pids, ep_link) if(ep->ep_capid == pid) break; if(ep == NULL) { @@ -754,7 +879,7 @@ prefcapid_ok: t->s_dvb_prefcapid_lock == PREFCAPID_OFF) { ep = calloc(1, sizeof(cc_ecm_pid_t)); ep->ep_capid = pid; - LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link); + LIST_INSERT_HEAD(&ct->cs_ecm_pids, ep, ep_link); tvhdebug(cc->cc_subsys, "%s: Insert %s ECM (PID %d) for service \"%s\"", cc->cc_name, t->s_dvb_prefcapid ? "preferred" : "new", pid, t->s_dvb_svcname); } @@ -838,7 +963,7 @@ found: cc->cc_name, pcard->cs_ra.caid, provid, t->s_dvb_svcname); tvhlog_hexdump(cc->cc_subsys, data, len); - cc->cc_send_emm(cc, ct, pcard, provid, data, len); + emm_filter(&pcard->cs_ra, data, len, t->s_dvb_mux, cc_emm_send, pcard); } } @@ -847,25 +972,6 @@ end: pthread_mutex_unlock(&cc->cc_mutex); } -/** - * cc_mutex is held - */ -static void -cc_service_pid_free(cc_service_t *ct) -{ - cc_ecm_pid_t *ep; - cc_ecm_section_t *es; - - while((ep = LIST_FIRST(&ct->cs_pids)) != NULL) { - while ((es = LIST_FIRST(&ep->ep_sections)) != NULL) { - LIST_REMOVE(es, es_link); - free(es); - } - LIST_REMOVE(ep, ep_link); - free(ep); - } -} - /** * cc_mutex is held */ @@ -879,7 +985,7 @@ cc_service_destroy0(th_descrambler_t *td) descrambler_close_pid(ct->cs_mux, ct, ct->cs_epids.pids[i].pid); mpegts_pid_done(&ct->cs_epids); - cc_service_pid_free(ct); + cc_service_ecm_pid_free(ct); LIST_REMOVE(td, td_service_link); diff --git a/src/descrambler/cclient.h b/src/descrambler/cclient.h index 389d0a31b..5674339b9 100644 --- a/src/descrambler/cclient.h +++ b/src/descrambler/cclient.h @@ -44,6 +44,7 @@ typedef struct cc_ecm_section { int es_section; + uint32_t es_card_id; uint16_t es_capid; uint16_t es_caid; uint32_t es_provid; @@ -54,12 +55,6 @@ typedef struct cc_ecm_section { uint8_t es_resolved; int64_t es_time; // time request was sent - union { - struct { - uint32_t es_card_id; - } cccam; - }; - } cc_ecm_section_t; /** @@ -98,7 +93,7 @@ typedef struct cc_service { ECM_RESET } ecm_state; - LIST_HEAD(, cc_ecm_pid) cs_pids; + LIST_HEAD(, cc_ecm_pid) cs_ecm_pids; } cc_service_t; @@ -116,13 +111,13 @@ typedef struct cc_message { */ typedef struct cc_card_data { LIST_ENTRY(cc_card_data) cs_card; + uint32_t cs_id; emm_reass_t cs_ra; void *cs_client; mpegts_mux_t *cs_mux; uint8_t cs_running; union { struct { - uint32_t cs_id; uint32_t cs_remote_id; uint8_t cs_hop; uint8_t cs_reshare; @@ -195,9 +190,13 @@ typedef struct cclient { static inline int cc_must_break(cclient_t *cc) { return !cc->cc_running || !cc->cac_enabled || cc->cc_reconfigure; } +char *cc_get_card_name(cc_card_data_t *pcard, char *buf, size_t buflen); cc_card_data_t *cc_new_card - (cclient_t *cc, uint16_t caid, uint8_t *ua, int pcount, uint8_t **pid, uint8_t **psa); + (cclient_t *cc, uint16_t caid, uint32_t cardid, + uint8_t *ua, int pcount, uint8_t **pid, uint8_t **psa); void cc_emm_set_allowed(cclient_t *cc, int emm_allowed); +void cc_remove_card(cclient_t *cc, cc_card_data_t *pcard); +void cc_remove_card_by_id(cclient_t *cc, uint32_t card_id); void cc_ecm_reply (cc_service_t *ct, cc_ecm_section_t *es, int key_type, diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index 917f40a80..b28854a14 100644 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -343,7 +343,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len) caclient_set_status((caclient_t *)cwc, CACLIENT_STATUS_CONNECTED); cc_new_card((cclient_t *)cwc, (msg[4] << 8) | msg[5], - msg + 6, nprov, pid, psa); + 0, msg + 6, nprov, pid, psa); return 0; } @@ -460,7 +460,7 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len) caclient_set_status((caclient_t *)cwc, CACLIENT_STATUS_CONNECTED); u8 = &msg[8]; - cc_new_card((cclient_t *)cwc, caid, NULL, 1, &u8, NULL); + cc_new_card((cclient_t *)cwc, caid, 0, NULL, 1, &u8, NULL); } } return 0;