From: Jaroslav Kysela Date: Wed, 24 May 2017 18:13:00 +0000 (+0200) Subject: descrambler: add multi-pid descrambling X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99e9a2af9d0eca9213af2b0051a96e39e77f97bb;p=thirdparty%2Ftvheadend.git descrambler: add multi-pid descrambling --- diff --git a/src/descrambler.h b/src/descrambler.h index e635bf3bf..c7f8ab297 100644 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -62,30 +62,33 @@ typedef struct th_descrambler { } th_descrambler_t; +typedef struct th_descrambler_key { + uint8_t key_data[2][16]; /* 0 = even, 1 = odd, max 16-byte key */ + tvhcsa_t key_csa; + uint16_t key_pid; /* keys are assigned to this pid (when multipid is set) */ + uint64_t key_interval; + int64_t key_start; + int64_t key_timestamp[2]; + uint8_t key_index; + uint8_t key_valid; + uint8_t key_changed; +} th_descrambler_key_t; + typedef struct th_descrambler_runtime { struct service *dr_service; - tvhcsa_t dr_csa; uint32_t dr_external:1; uint32_t dr_skip:1; uint32_t dr_quick_ecm:1; - uint32_t dr_key:1; - uint32_t dr_key_first:1; uint32_t dr_key_const:1; - uint8_t dr_key_index; - uint8_t dr_key_valid; - uint8_t dr_key_changed; - uint64_t dr_key_interval; - int64_t dr_key_start; - int64_t dr_key_timestamp[2]; + uint32_t dr_key_multipid:1; int64_t dr_ecm_start[2]; int64_t dr_ecm_last_key_time; int64_t dr_last_err; int64_t dr_force_skip; + th_descrambler_key_t dr_keys[DESCRAMBLER_MAX_KEYS]; TAILQ_HEAD(, th_descrambler_data) dr_queue; uint32_t dr_queue_total; tvhlog_limit_t dr_loglimit_key; - uint8_t dr_key_even[16]; - uint8_t dr_key_odd[16]; } th_descrambler_runtime_t; typedef void (*descrambler_section_callback_t) @@ -158,7 +161,7 @@ void descrambler_service_stop ( struct service *t ); void descrambler_caid_changed ( struct service *t ); int descrambler_resolved ( struct service *t, th_descrambler_t *ignore ); void descrambler_external ( struct service *t, int state ); -void descrambler_keys ( th_descrambler_t *t, int type, +void descrambler_keys ( th_descrambler_t *t, int type, uint16_t pid, const uint8_t *even, const uint8_t *odd ); void descrambler_notify ( th_descrambler_t *t, uint16_t caid, uint32_t provid, diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 31623d801..6b839308c 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -1105,7 +1105,7 @@ capmt_process_key(capmt_t *capmt, uint8_t adapter, uint32_t index, continue; found: - descrambler_keys((th_descrambler_t *)ct, type, even, odd); + descrambler_keys((th_descrambler_t *)ct, type, 0, even, odd); } pthread_mutex_unlock(&capmt->capmt_mutex); } diff --git a/src/descrambler/cccam.c b/src/descrambler/cccam.c index 7af24f739..9bcef6095 100644 --- a/src/descrambler/cccam.c +++ b/src/descrambler/cccam.c @@ -702,7 +702,7 @@ forbid: pthread_mutex_unlock(&cccam->cccam_mutex); descrambler_keys((th_descrambler_t *)ct, off == 16 ? DESCRAMBLER_AES_ECB : DESCRAMBLER_CSA_CBC, - dcw, dcw + off); + 0, dcw, dcw + off); snprintf(chaninfo, sizeof(chaninfo), "%s:%i", cccam->cccam_hostname, cccam->cccam_port); descrambler_notify((th_descrambler_t *)ct, es3.es_caid, es3.es_provid, diff --git a/src/descrambler/constcw.c b/src/descrambler/constcw.c index 14f9c5b7f..e703a7133 100644 --- a/src/descrambler/constcw.c +++ b/src/descrambler/constcw.c @@ -169,7 +169,7 @@ constcw_service_start(caclient_t *cac, service_t *t) LIST_INSERT_HEAD(&ccw->ccw_services, ct, cs_link); descrambler_keys(td, constcw_algo(cac), - ccw->ccw_key_even, ccw->ccw_key_odd); + 0, ccw->ccw_key_even, ccw->ccw_key_odd); } diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index 5b1fd9798..b1c4e8c51 100644 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -850,7 +850,7 @@ forbid: pthread_mutex_unlock(&cwc->cwc_mutex); descrambler_keys((th_descrambler_t *)ct, off == 16 ? DESCRAMBLER_AES_ECB : DESCRAMBLER_CSA_CBC, - msg + 3, msg + 3 + off); + 0, msg + 3, msg + 3 + off); snprintf(chaninfo, sizeof(chaninfo), "%s:%i", cwc->cwc_hostname, cwc->cwc_port); descrambler_notify((th_descrambler_t *)ct, es3.es_caid, es3.es_provid, diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index be7c81f27..7ecc10640 100644 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -32,6 +32,7 @@ #define MAX_QUICK_ECM_ENTRIES 100 #define MAX_CONSTCW_ENTRIES 100 +#define MAX_MULTI_PID_ENTRIES 100 typedef struct th_descrambler_data { TAILQ_ENTRY(th_descrambler_data) dd_link; @@ -41,6 +42,7 @@ typedef struct th_descrambler_data { TAILQ_HEAD(th_descrambler_queue, th_descrambler_data); +uint16_t *multi_pid_table = NULL; uint16_t *quick_ecm_table = NULL; uint16_t *constcw_table = NULL; @@ -143,14 +145,42 @@ descrambler_data_key_check(th_descrambler_runtime_t *dr, uint8_t key, int len) /* * */ -void -descrambler_init ( void ) +static uint16_t * +descrambler_load_table(htsmsg_t *c, const char *name, const char *field, int max) { - htsmsg_t *c, *e, *q; + htsmsg_t *e, *q; htsmsg_field_t *f; const char *s; uint32_t caid; int idx; + uint16_t *table = NULL; + + idx = 0; + if ((q = htsmsg_get_list(c, field)) != NULL) { + HTSMSG_FOREACH(f, q) { + if (!(e = htsmsg_field_get_map(f))) continue; + if (idx + 1 >= max) break; + if ((s = htsmsg_get_str(e, "caid")) == NULL) continue; + caid = strtol(s, NULL, 16); + tvhinfo(LS_DESCRAMBLER, "adding CAID %04X as %s (%s)", + caid, name, htsmsg_get_str(e, "name") ?: "unknown"); + if (!quick_ecm_table) + quick_ecm_table = malloc(sizeof(uint16_t) * max); + quick_ecm_table[idx++] = caid; + } + if (table) + table[idx] = 0; + } + return table; +} + +/* + * + */ +void +descrambler_init ( void ) +{ + htsmsg_t *c; #if (ENABLE_CWC || ENABLE_CAPMT || ENABLE_CCCAM) && !ENABLE_DVBCSA ffdecsa_init(); @@ -161,36 +191,9 @@ descrambler_init ( void ) #endif if ((c = hts_settings_load("descrambler")) != NULL) { - idx = 0; - if ((q = htsmsg_get_list(c, "quick_ecm")) != NULL) { - HTSMSG_FOREACH(f, q) { - if (!(e = htsmsg_field_get_map(f))) continue; - if (idx + 1 >= MAX_QUICK_ECM_ENTRIES) continue; - if ((s = htsmsg_get_str(e, "caid")) == NULL) continue; - caid = strtol(s, NULL, 16); - tvhinfo(LS_DESCRAMBLER, "adding CAID %04X as quick ECM (%s)", caid, htsmsg_get_str(e, "name") ?: "unknown"); - if (!quick_ecm_table) - quick_ecm_table = malloc(sizeof(uint16_t) * MAX_QUICK_ECM_ENTRIES); - quick_ecm_table[idx++] = caid; - } - if (quick_ecm_table) - quick_ecm_table[idx] = 0; - } - idx = 0; - if ((q = htsmsg_get_list(c, "const_cw")) != NULL) { - HTSMSG_FOREACH(f, q) { - if (!(e = htsmsg_field_get_map(f))) continue; - if (idx + 1 >= MAX_CONSTCW_ENTRIES) continue; - if ((s = htsmsg_get_str(e, "caid")) == NULL) continue; - caid = strtol(s, NULL, 16); - tvhinfo(LS_DESCRAMBLER, "adding CAID %04X as constant crypto-word (%s)", caid, htsmsg_get_str(e, "name") ?: "unknown"); - if (!constcw_table) - constcw_table = malloc(sizeof(uint16_t) * MAX_CONSTCW_ENTRIES); - constcw_table[idx++] = caid; - } - if (constcw_table) - constcw_table[idx] = 0; - } + quick_ecm_table = descrambler_load_table(c, "quick ECM", "quick_ecm", MAX_QUICK_ECM_ENTRIES); + constcw_table = descrambler_load_table(c, "const_cw", "constant crypto-word", MAX_CONSTCW_ENTRIES); + multi_pid_table = descrambler_load_table(c, "multi_pid", "multiple PIDs", MAX_MULTI_PID_ENTRIES); htsmsg_destroy(c); } } @@ -203,6 +206,8 @@ descrambler_done ( void ) quick_ecm_table = NULL; free(constcw_table); constcw_table = NULL; + free(multi_pid_table); + multi_pid_table = NULL; } /* @@ -236,9 +241,10 @@ void descrambler_service_start ( service_t *t ) { th_descrambler_runtime_t *dr; + th_descrambler_key_t *tk; elementary_stream_t *st; caid_t *ca; - int count, constcw = 0; + int i, count, constcw = 0, multipid = 0; uint16_t *p; if (t->s_scrambled_pass) @@ -253,7 +259,10 @@ descrambler_service_start ( service_t *t ) for (p = constcw_table; p && *p; p++) if (ca->caid == *p) { constcw = 1; - break; + } + for (p = multi_pid_table; p && *p; p++) + if (ca->caid == *p) { + multipid = 1; } count++; } @@ -272,6 +281,14 @@ descrambler_service_start ( service_t *t ) } } + if (multi_pid_table) { + for (p = multi_pid_table; *p; p++) + if (*p == t->s_dvb_forcecaid) { + multipid = 1; + break; + } + } + } ((mpegts_service_t *)t)->s_dvb_mux->mm_descrambler_flush = 0; @@ -279,14 +296,21 @@ descrambler_service_start ( service_t *t ) t->s_descramble = dr = calloc(1, sizeof(th_descrambler_runtime_t)); dr->dr_service = t; TAILQ_INIT(&dr->dr_queue); - dr->dr_key_index = 0xff; - dr->dr_key_interval = sec2mono(10); + for (i = 0; i < DESCRAMBLER_MAX_KEYS; i++) { + tk = &dr->dr_keys[i]; + tk->key_index = 0xff; + tk->key_interval = multipid ? sec2mono(2) : sec2mono(10); + tvhcsa_init(&tk->key_csa); + if (!multipid) break; + } dr->dr_key_const = constcw; + dr->dr_key_multipid = multipid; if (constcw) tvhtrace(LS_DESCRAMBLER, "using constcw for \"%s\"", t->s_nicename); + if (multipid) + tvhtrace(LS_DESCRAMBLER, "using multipid for \"%s\"", t->s_nicename); dr->dr_skip = 0; dr->dr_force_skip = 0; - tvhcsa_init(&dr->dr_csa); } if (t->s_dvb_forcecaid != 0xffff) @@ -308,8 +332,10 @@ descrambler_service_stop ( service_t *t ) { th_descrambler_t *td; th_descrambler_runtime_t *dr = t->s_descramble; + th_descrambler_key_t *tk; th_descrambler_data_t *dd; void *p; + int i; #if ENABLE_LINUXDVB_CA dvbcam_service_stop(t); @@ -323,7 +349,11 @@ descrambler_service_stop ( service_t *t ) t->s_descramble_info = NULL; free(p); if (dr) { - tvhcsa_destroy(&dr->dr_csa); + for (i = 0; i < DESCRAMBLER_MAX_KEYS; i++) { + tk = &dr->dr_keys[i]; + tvhcsa_destroy(&tk->key_csa); + if (!dr->dr_key_multipid) break; + } while ((dd = TAILQ_FIRST(&dr->dr_queue)) != NULL) descrambler_data_destroy(dr, dd, 0); free(dr); @@ -442,13 +472,16 @@ descrambler_external ( service_t *t, int state ) } void -descrambler_keys ( th_descrambler_t *td, int type, +descrambler_keys ( th_descrambler_t *td, int type, uint16_t pid, const uint8_t *even, const uint8_t *odd ) { static uint8_t empty[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; service_t *t = td->td_service; th_descrambler_runtime_t *dr; + th_descrambler_key_t *tk; th_descrambler_t *td2; + char pidname[16]; + uint16_t pid2; int j = 0; if (t == NULL || (dr = t->s_descramble) == NULL) { @@ -458,15 +491,29 @@ descrambler_keys ( th_descrambler_t *td, int type, pthread_mutex_lock(&t->s_stream_mutex); - if (tvhcsa_set_type(&dr->dr_csa, type) < 0) + if (!dr->dr_key_multipid) + pid = 0; + + for (j = 0; j < DESCRAMBLER_MAX_KEYS; j++) { + tk = &dr->dr_keys[j]; + pid2 = tk->key_pid; + if (pid2 == 0 || pid2 == pid) break; + } + + if (j >= DESCRAMBLER_MAX_KEYS) { + tvherror(LS_DESCRAMBLER, "too many keys"); + goto fin; + } + + if (tvhcsa_set_type(&tk->key_csa, type) < 0) goto fin; LIST_FOREACH(td2, &t->s_descramblers, td_service_link) if (td2 != td && td2->td_keystate == DS_RESOLVED) { tvhdebug(LS_DESCRAMBLER, - "Already has a key from %s for service \"%s\", " + "Already has a key[%d] from %s for service \"%s\", " "ignoring key from \"%s\"%s", - td2->td_nicename, + tk->key_pid, td2->td_nicename, ((mpegts_service_t *)td2->td_service)->s_dvb_svcname, td->td_nicename, dr->dr_key_const ? " (const)" : ""); @@ -476,58 +523,64 @@ descrambler_keys ( th_descrambler_t *td, int type, goto fin; } - if (memcmp(empty, even, dr->dr_csa.csa_keylen)) { + if (memcmp(empty, even, tk->key_csa.csa_keylen)) { j++; - memcpy(dr->dr_key_even, even, dr->dr_csa.csa_keylen); - dr->dr_key_changed |= 1; - dr->dr_key_valid |= 0x40; - dr->dr_key_timestamp[0] = mclk(); + memcpy(tk->key_data[0], even, tk->key_csa.csa_keylen); + tk->key_changed |= 1; + tk->key_valid |= 0x40; + tk->key_timestamp[0] = mclk(); } - if (memcmp(empty, odd, dr->dr_csa.csa_keylen)) { + if (memcmp(empty, odd, tk->key_csa.csa_keylen)) { j++; - memcpy(dr->dr_key_odd, odd, dr->dr_csa.csa_keylen); - dr->dr_key_changed |= 2; - dr->dr_key_valid |= 0x80; - dr->dr_key_timestamp[1] = mclk(); + memcpy(tk->key_data[1], odd, tk->key_csa.csa_keylen); + tk->key_changed |= 2; + tk->key_valid |= 0x80; + tk->key_timestamp[1] = mclk(); } + if (pid == 0) + pidname[0] = '\0'; + else + snprintf(pidname, sizeof(pidname), "[%d]", pid); if (j) { if (td->td_keystate != DS_RESOLVED) - tvhdebug( LS_DESCRAMBLER, - "Obtained keys from %s for service \"%s\"%s", - td->td_nicename, + tvhdebug(LS_DESCRAMBLER, + "Obtained keys%s from %s for service \"%s\"%s", + pidname, td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname, dr->dr_key_const ? " (const)" : ""); - if (dr->dr_csa.csa_keylen == 8) { - tvhtrace(LS_DESCRAMBLER, "Obtained keys " + if (tk->key_csa.csa_keylen == 8) { + tvhtrace(LS_DESCRAMBLER, "Obtained keys%s " "%02X%02X%02X%02X%02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X%02X%02X" - " from %s for service \"%s\"", + " pid %04X from %s for service \"%s\"", + pidname, even[0], even[1], even[2], even[3], even[4], even[5], even[6], even[7], odd[0], odd[1], odd[2], odd[3], odd[4], odd[5], odd[6], odd[7], - td->td_nicename, + pid, td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname); - } else if (dr->dr_csa.csa_keylen == 16) { - tvhtrace(LS_DESCRAMBLER, "Obtained keys " + } else if (tk->key_csa.csa_keylen == 16) { + tvhtrace(LS_DESCRAMBLER, "Obtained keys%s " "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X:" "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - " from %s for service \"%s\"", + " pid %04X from %s for service \"%s\"", + pidname, even[0], even[1], even[2], even[3], even[4], even[5], even[6], even[7], even[8], even[9], even[10], even[11], even[12], even[13], even[14], even[15], odd[0], odd[1], odd[2], odd[3], odd[4], odd[5], odd[6], odd[7], odd[8], odd[9], odd[10], odd[11], odd[12], odd[13], odd[14], odd[15], - td->td_nicename, + pid, td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname); } else { - tvhtrace(LS_DESCRAMBLER, "Unknown keys from %s for for service \"%s\"", - td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname); + tvhtrace(LS_DESCRAMBLER, "Unknown keys%s pid %04X from %s for for service \"%s\"", + pidname, pid, td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname); } dr->dr_ecm_last_key_time = mclk(); td->td_keystate = DS_RESOLVED; td->td_service->s_descrambler = td; } else { tvhdebug(LS_DESCRAMBLER, - "Empty keys received from %s for service \"%s\"%s", - td->td_nicename, + "Empty keys%s received from %s for service \"%s\"%s", + pidname, td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname, dr->dr_key_const ? " (const)" : ""); } @@ -537,7 +590,7 @@ fin: #if ENABLE_TSDEBUG if (j) { tsdebug_packet_t *tp = malloc(sizeof(*tp)); - uint16_t keylen = dr->dr_csa.csa_keylen; + uint16_t keylen = tk->key_csa.csa_keylen; uint16_t sid = ((mpegts_service_t *)td->td_service)->s_dvb_service_id; uint32_t pos = 0, crc; mpegts_mux_t *mm = ((mpegts_service_t *)td->td_service)->s_dvb_mux; @@ -558,6 +611,8 @@ fin: tp->pkt[pos++] = keylen & 0xff; tp->pkt[pos++] = (sid >> 8) & 0xff; tp->pkt[pos++] = sid & 0xff; + tp->pkt[pos++] = (pid >> 8) & 0xff; + tp->pkt[pos++] = pid & 0xff; memcpy(tp->pkt + pos, even, keylen); memcpy(tp->pkt + pos + keylen, odd, keylen); pos += 2 * keylen; @@ -598,54 +653,54 @@ descrambler_flush_table_data( service_t *t ) pthread_mutex_unlock(&mux->mm_descrambler_lock); } -static inline void -key_update( th_descrambler_runtime_t *dr, uint8_t key, int64_t timestamp ) +static inline void +key_update( th_descrambler_key_t *tk, uint8_t key, int64_t timestamp ) { /* set the even (0) or odd (0x40) key index */ - dr->dr_key_index = key & 0x40; - if (dr->dr_key_start) { - dr->dr_key_interval = dr->dr_key_start + sec2mono(50) < timestamp ? - sec2mono(10) : timestamp - dr->dr_key_start; - dr->dr_key_start = timestamp; + tk->key_index = key & 0x40; + if (tk->key_start) { + tk->key_interval = tk->key_start + sec2mono(50) < timestamp ? + sec2mono(10) : timestamp - tk->key_start; + tk->key_start = timestamp; } else { /* We don't know the exact start key switch time */ - dr->dr_key_start = timestamp - sec2mono(60); + tk->key_start = timestamp - sec2mono(60); } } static inline int -key_changed ( th_descrambler_runtime_t *dr, uint8_t ki, int64_t timestamp ) +key_changed ( th_descrambler_key_t *tk, uint8_t ki, int64_t timestamp ) { - return dr->dr_key_index != (ki & 0x40) && - dr->dr_key_start + sec2mono(2) < timestamp; + return tk->key_index != (ki & 0x40) && + tk->key_start + sec2mono(2) < timestamp; } static inline int -key_valid ( th_descrambler_runtime_t *dr, uint8_t ki ) +key_valid ( th_descrambler_key_t *tk, uint8_t ki ) { /* 0x40 (for even) or 0x80 (for odd) */ uint8_t mask = ((ki & 0x40) + 0x40); - return dr->dr_key_valid & mask; + return tk->key_valid & mask; } static inline int -key_late( th_descrambler_runtime_t *dr, uint8_t ki, int64_t timestamp ) +key_late( th_descrambler_runtime_t *dr, th_descrambler_key_t *tk, uint8_t ki, int64_t timestamp ) { uint8_t kidx = (ki & 0x40) >> 6; /* constcw - do not handle keys */ if (dr->dr_key_const) return 0; /* required key is older than previous? */ - if (dr->dr_key_timestamp[kidx] < dr->dr_key_timestamp[kidx^1]) { + if (tk->key_timestamp[kidx] < tk->key_timestamp[kidx^1]) { /* but don't take in account the keys modified just now */ - if (dr->dr_key_timestamp[kidx^1] + 2 < timestamp) + if (tk->key_timestamp[kidx^1] + 2 < timestamp) goto late; } /* ECM was sent, but no new key was received */ - if (dr->dr_ecm_last_key_time + sec2mono(2) < dr->dr_key_start && - (!dr->dr_quick_ecm || dr->dr_ecm_start[kidx] + 4 < dr->dr_key_start)) { + if (dr->dr_ecm_last_key_time + sec2mono(2) < tk->key_start && + (!dr->dr_quick_ecm || dr->dr_ecm_start[kidx] + 4 < tk->key_start)) { late: - dr->dr_key_valid &= ~((ki & 0x40) + 0x40); + tk->key_valid &= ~((ki & 0x40) + 0x40); return 1; } return 0; @@ -658,16 +713,55 @@ key_started( th_descrambler_runtime_t *dr, uint8_t ki ) return mclk() - dr->dr_ecm_start[kidx] < sec2mono(5); } +static void +key_flush( th_descrambler_key_t *tk, service_t *t ) +{ + /* update the keys */ + if (tk->key_changed) { + tk->key_csa.csa_flush(&tk->key_csa, (mpegts_service_t *)t); + if (tk->key_changed & 1) + tvhcsa_set_key_odd(&tk->key_csa, tk->key_data[0]); + if (tk->key_changed & 2) + tvhcsa_set_key_odd(&tk->key_csa, tk->key_data[1]); + tk->key_changed = 0; + } +} + +static th_descrambler_key_t * +key_find_struct( th_descrambler_runtime_t *dr, + th_descrambler_key_t *tk_old, + const uint8_t *tsb, + service_t *t ) +{ + th_descrambler_key_t *tk; + int i, pid = (tsb[1] & 0x1f) << 8 | tsb[2]; + for (i = 0; i < DESCRAMBLER_MAX_KEYS; i++) { + tk = &dr->dr_keys[i]; + if (tk->key_pid == pid) { + if (tk != tk_old && tk_old) + key_flush(tk_old, t); + return tk; + } + } + return NULL; +} + static int ecm_reset( service_t *t, th_descrambler_runtime_t *dr ) { th_descrambler_t *td; - int ret = 0; + th_descrambler_key_t *tk; + int ret = 0, i; /* reset the reader ECM state */ LIST_FOREACH(td, &t->s_descramblers, td_service_link) { if (!td->td_ecm_reset(td)) { - dr->dr_key_valid = 0; + for (i = 0; i < DESCRAMBLER_MAX_KEYS; i++) { + tk = &dr->dr_keys[i]; + tk->key_valid = 0; + if (tk->key_pid == 0) + break; + } ret = 1; } } @@ -682,6 +776,7 @@ descrambler_descramble ( service_t *t, { th_descrambler_t *td; th_descrambler_runtime_t *dr = t->s_descramble; + th_descrambler_key_t *tk; th_descrambler_data_t *dd, *dd_next; int count, failed, resolved, len2, len3, flush_data = 0; uint32_t dbuflen; @@ -699,7 +794,12 @@ descrambler_descramble ( service_t *t, return dr && dr->dr_external ? 1 : -1; } - if (dr->dr_csa.csa_type == DESCRAMBLER_NONE && dr->dr_queue_total == 0) + if (!dr->dr_key_multipid) { + tk = &dr->dr_keys[0]; + } else { + tk = key_find_struct(dr, NULL, tsb, t); + } + if ((tk == NULL || tk->key_csa.csa_type == DESCRAMBLER_NONE) && dr->dr_queue_total == 0) if ((tsb[3] & 0x80) == 0) { ts_recv_packet0((mpegts_service_t *)t, st, tsb, len); return 1; @@ -717,19 +817,17 @@ descrambler_descramble ( service_t *t, if (resolved) { - /* update the keys */ - if (dr->dr_key_changed) { - dr->dr_csa.csa_flush(&dr->dr_csa, (mpegts_service_t *)t); - if (dr->dr_key_changed & 1) - tvhcsa_set_key_even(&dr->dr_csa, dr->dr_key_even); - if (dr->dr_key_changed & 2) - tvhcsa_set_key_odd(&dr->dr_csa, dr->dr_key_odd); - dr->dr_key_changed = 0; + if (!dr->dr_key_multipid) { + tk = &dr->dr_keys[0]; + key_flush(tk, t); + } else { + tk = NULL; } /* process the queued TS packets */ if (dr->dr_queue_total > 0) { - descrambler_data_time_flush(dr, mclk() - (dr->dr_key_interval - sec2mono(2))); + if (!dr->dr_key_multipid) + descrambler_data_time_flush(dr, mclk() - (tk->key_interval - sec2mono(2))); for (dd = TAILQ_FIRST(&dr->dr_queue); dd; dd = dd_next) { dd_next = TAILQ_NEXT(dd, dd_link); sb = &dd->dd_sbuf; @@ -738,13 +836,17 @@ descrambler_descramble ( service_t *t, for (; len2 > 0; tsb2 += len3, len2 -= len3) { ki = tsb2[3]; if ((ki & 0x80) != 0x00) { - if (key_valid(dr, ki) == 0) + if (dr->dr_key_multipid) { + tk = key_find_struct(dr, tk, tsb2, t); + if (tk == NULL) goto next; + } + if (key_valid(tk, ki) == 0) goto next; - if (key_changed(dr, ki, dd->dd_timestamp)) { - tvhtrace(LS_DESCRAMBLER, "stream key changed to %s for service \"%s\"", - (ki & 0x40) ? "odd" : "even", + if (key_changed(tk, ki, dd->dd_timestamp)) { + tvhtrace(LS_DESCRAMBLER, "stream key[%d] changed to %s for service \"%s\"", + tk->key_pid, (ki & 0x40) ? "odd" : "even", ((mpegts_service_t *)t)->s_dvb_svcname); - if (key_late(dr, ki, dd->dd_timestamp)) { + if (key_late(dr, tk, ki, dd->dd_timestamp)) { descrambler_notify_nokey(dr); if (ecm_reset(t, dr)) { descrambler_data_cut(dr, tsb2 - sb->sb_data); @@ -752,11 +854,11 @@ descrambler_descramble ( service_t *t, goto next; } } - key_update(dr, ki, dd->dd_timestamp); + key_update(tk, ki, dd->dd_timestamp); } } - len3 = mpegts_word_count(tsb2, len2, 0xFF0000C0); - dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb2, len3); + len3 = mpegts_word_count(tsb2, len2, dr->dr_key_multipid ? 0xFF1FFFC0 : 0xFF0000C0); + tk->key_csa.csa_descramble(&tk->key_csa, (mpegts_service_t *)t, tsb2, len3); } if (len2 == 0) service_reset_streaming_status_flags(t, TSS_NO_ACCESS); @@ -767,20 +869,24 @@ descrambler_descramble ( service_t *t, /* check for key change */ ki = tsb[3]; if ((ki & 0x80) != 0x00) { - if (key_valid(dr, ki) == 0) { + if (dr->dr_key_multipid) { + tk = key_find_struct(dr, tk, tsb, t); + if (tk == NULL) goto next; + } + if (key_valid(tk, ki) == 0) { if (!key_started(dr, ki) && tvhlog_limit(&dr->dr_loglimit_key, 10)) - tvhwarn(LS_DESCRAMBLER, "%s %s", + tvhwarn(LS_DESCRAMBLER, "%s %s stream key[%d] is not valid", ((mpegts_service_t *)t)->s_dvb_svcname, - (ki & 0x40) ? "odd stream key is not valid" : - "even stream key is not valid"); + (ki & 0x40) ? "odd" : "even", tk->key_pid); goto next; } - if (key_changed(dr, ki, mclk())) { - tvhtrace(LS_DESCRAMBLER, "stream key changed to %s for service \"%s\"", - (ki & 0x40) ? "odd" : "even", + if (key_changed(tk, ki, mclk())) { + tvhtrace(LS_DESCRAMBLER, "stream key[%d] changed to %s for service \"%s\"", + tk->key_pid, (ki & 0x40) ? "odd" : "even", ((mpegts_service_t *)t)->s_dvb_svcname); - if (key_late(dr, ki, mclk())) { - tvherror(LS_DESCRAMBLER, "ECM - key late (%"PRId64" ms) for service \"%s\"", + if (key_late(dr, tk, ki, mclk())) { + tvherror(LS_DESCRAMBLER, "ECM - key[%d] late (%"PRId64" ms) for service \"%s\"", + tk->key_pid, mono2ms(mclk() - dr->dr_ecm_last_key_time), ((mpegts_service_t *)t)->s_dvb_svcname); descrambler_notify_nokey(dr); @@ -789,11 +895,11 @@ descrambler_descramble ( service_t *t, goto next; } } - key_update(dr, ki, mclk()); + key_update(tk, ki, mclk()); } } dr->dr_skip = 1; - dr->dr_csa.csa_descramble(&dr->dr_csa, (mpegts_service_t *)t, tsb, len); + tk->key_csa.csa_descramble(&tk->key_csa, (mpegts_service_t *)t, tsb, len); service_reset_streaming_status_flags(t, TSS_NO_ACCESS); return 1; } @@ -807,27 +913,37 @@ next: if (dr->dr_ecm_start[0] || dr->dr_ecm_start[1]) { /* ECM sent */ ki = tsb[3]; if ((ki & 0x80) != 0x00) { - if (dr->dr_key_start == 0) { + if (dr->dr_key_multipid) { + tk = key_find_struct(dr, tk, tsb, t); + if (tk == NULL) goto queue; + } else { + tk = &dr->dr_keys[0]; + } + if (tk->key_start == 0) { + if (dr->dr_key_multipid) + goto update; /* do not use the first TS packet to decide - it may be wrong */ while (dr->dr_queue_total > 20 * 188) { if (descrambler_data_key_check(dr, ki & 0xc0, 20 * 188)) { tvhtrace(LS_DESCRAMBLER, "initial stream key set to %s for service \"%s\"", (ki & 0x40) ? "odd" : "even", ((mpegts_service_t *)t)->s_dvb_svcname); - key_update(dr, ki, mclk()); + key_update(tk, ki, mclk()); break; } else { descrambler_data_cut(dr, 188); } } - } else if (dr->dr_key_index != (ki & 0x40) && - dr->dr_key_start + sec2mono(2) < mclk()) { + } else if (tk->key_index != (ki & 0x40) && + tk->key_start + sec2mono(2) < mclk()) { +update: tvhtrace(LS_DESCRAMBLER, "stream key changed to %s for service \"%s\"", (ki & 0x40) ? "odd" : "even", ((mpegts_service_t *)t)->s_dvb_svcname); - key_update(dr, ki, mclk()); + key_update(tk, ki, mclk()); } } +queue: if (count != failed) { /* * Fill a temporary buffer until the keys are known to make @@ -868,7 +984,10 @@ descrambler_table_callback descrambler_section_t *ds; descrambler_ecmsec_t *des; th_descrambler_runtime_t *dr; + th_descrambler_key_t *tk; int emm = (mt->mt_flags & MT_FAST) == 0; + uint8_t ki; + int i; if (len < 6) return 0; @@ -912,8 +1031,14 @@ descrambler_table_callback } if ((ptr[0] & 0xfe) == 0x80) { /* 0x80 = even, 0x81 = odd */ dr->dr_ecm_start[ptr[0] & 1] = mclk(); - if (dr->dr_quick_ecm) - dr->dr_key_valid &= ~(1 << ((ptr[0] & 1) + 6)); /* 0x40 = even, 0x80 = odd */ + if (dr->dr_quick_ecm) { + ki = 1 << ((ptr[0] & 1) + 6); /* 0x40 = even, 0x80 = odd */ + for (i = 0; i < DESCRAMBLER_MAX_KEYS; i++) { + tk = &dr->dr_keys[i]; + tk->key_valid &= ~ki; + if (tk->key_pid == 0) break; + } + } } tvhtrace(LS_DESCRAMBLER, "ECM message %02x (section %d, len %d, pid %d) for service \"%s\"", ptr[0], des->number, len, mt->mt_pid, t->s_dvb_svcname); diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 0501f4c7d..911ed23c8 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -1286,7 +1286,8 @@ tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt, int len ) type = pkt[pos + 0]; keylen = pkt[pos + 1]; sid = (pkt[pos + 2] << 8) | pkt[pos + 3]; - pos += 4 + 2 * keylen; + pid = (pkt[pos + 4] << 8) | pkt[pos + 5]; + pos += 6 + 2 * keylen; if (pos > 184) return; crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) | diff --git a/support/configure.inc b/support/configure.inc index 42b6af856..f7386f4a3 100755 --- a/support/configure.inc +++ b/support/configure.inc @@ -543,6 +543,11 @@ EOF fi done + # Add build config string declaration + cat >> "${CONFIG_H}" <> "${CONFIG_H}" <