csa: started to rework the descrambling support
This commit is contained in:
parent
cf7518d4a7
commit
a686fe34d2
4 changed files with 118 additions and 441 deletions
5
Makefile
5
Makefile
|
@ -215,8 +215,9 @@ SRCS-$(CONFIG_LIBAV) += src/libav.c \
|
|||
|
||||
# CWC
|
||||
SRCS-${CONFIG_CWC} += \
|
||||
src/cwc.c \
|
||||
src/capmt.c
|
||||
src/descrambler/tvhcsa.c \
|
||||
src/descrambler/cwc.c \
|
||||
src/descrambler/capmt.c
|
||||
|
||||
# FFdecsa
|
||||
ifneq ($(CONFIG_DVBCSA),yes)
|
||||
|
|
|
@ -38,20 +38,14 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb/dvb.h"
|
||||
#include "input/mpegts.h"
|
||||
#include "tcp.h"
|
||||
#include "psi.h"
|
||||
#include "tsdemux.h"
|
||||
#include "capmt.h"
|
||||
#include "notify.h"
|
||||
#include "subscriptions.h"
|
||||
#include "dtable.h"
|
||||
|
||||
#if ENABLE_DVBCSA
|
||||
#include <dvbcsa/dvbcsa.h>
|
||||
#else
|
||||
#include "ffdecsa/FFdecsa.h"
|
||||
#endif
|
||||
#include "tvhcsa.h"
|
||||
#include "input/mpegts/linuxdvb/linuxdvb_private.h"
|
||||
|
||||
// ca_pmt_list_management values:
|
||||
#define CAPMT_LIST_MORE 0x00 // append a 'MORE' CAPMT object the list and start receiving the next object
|
||||
|
@ -148,7 +142,7 @@ typedef struct capmt_caid_ecm {
|
|||
typedef struct capmt_service {
|
||||
th_descrambler_t ct_head;
|
||||
|
||||
service_t *ct_service;
|
||||
mpegts_service_t *ct_service;
|
||||
|
||||
struct capmt *ct_capmt;
|
||||
|
||||
|
@ -166,24 +160,7 @@ typedef struct capmt_service {
|
|||
CT_FORBIDDEN
|
||||
} ct_keystate;
|
||||
|
||||
/* buffers for keystructs */
|
||||
#if ENABLE_DVBCSA
|
||||
struct dvbcsa_bs_key_s *ct_key_even;
|
||||
struct dvbcsa_bs_key_s *ct_key_odd;
|
||||
#else
|
||||
void *ct_keys;
|
||||
#endif
|
||||
|
||||
/* CSA */
|
||||
int ct_cluster_size;
|
||||
uint8_t *ct_tsbcluster;
|
||||
int ct_fill;
|
||||
#if ENABLE_DVBCSA
|
||||
struct dvbcsa_bs_batch_s *ct_tsbbatch_even;
|
||||
struct dvbcsa_bs_batch_s *ct_tsbbatch_odd;
|
||||
int ct_fill_even;
|
||||
int ct_fill_odd;
|
||||
#endif
|
||||
tvhcsa_t ct_csa;
|
||||
|
||||
/* current sequence number */
|
||||
uint16_t ct_seq;
|
||||
|
@ -388,22 +365,14 @@ capmt_service_destroy(th_descrambler_t *td)
|
|||
|
||||
LIST_REMOVE(ct, ct_link);
|
||||
|
||||
#if ENABLE_DVBCSA
|
||||
dvbcsa_bs_key_free(ct->ct_key_odd);
|
||||
dvbcsa_bs_key_free(ct->ct_key_even);
|
||||
free(ct->ct_tsbbatch_odd);
|
||||
free(ct->ct_tsbbatch_even);
|
||||
#else
|
||||
free_key_struct(ct->ct_keys);
|
||||
#endif
|
||||
free(ct->ct_tsbcluster);
|
||||
tvhcsa_destroy(&ct->ct_csa);
|
||||
free(ct);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_ca0(capmt_t* capmt) {
|
||||
capmt_service_t *ct;
|
||||
service_t *t;
|
||||
mpegts_service_t *t;
|
||||
int ret, bufsize;
|
||||
int *request;
|
||||
ca_descr_t *ca;
|
||||
|
@ -522,7 +491,7 @@ handle_ca0(capmt_t* capmt) {
|
|||
|
||||
if(ret < bufsize) {
|
||||
if(ct->ct_keystate != CT_FORBIDDEN) {
|
||||
tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_svcname);
|
||||
tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_dvb_svcname);
|
||||
|
||||
ct->ct_keystate = CT_FORBIDDEN;
|
||||
}
|
||||
|
@ -534,20 +503,12 @@ handle_ca0(capmt_t* capmt) {
|
|||
continue;
|
||||
|
||||
if (memcmp(even, invalid, 8))
|
||||
#if ENABLE_DVBCSA
|
||||
dvbcsa_bs_key_set(even, ct->ct_key_even);
|
||||
#else
|
||||
set_even_control_word(ct->ct_keys, even);
|
||||
#endif
|
||||
tvhcsa_set_key_even(&ct->ct_csa, even);
|
||||
if (memcmp(odd, invalid, 8))
|
||||
#if ENABLE_DVBCSA
|
||||
dvbcsa_bs_key_set(odd, ct->ct_key_odd);
|
||||
#else
|
||||
set_odd_control_word(ct->ct_keys, odd);
|
||||
#endif
|
||||
tvhcsa_set_key_odd(&ct->ct_csa, odd);
|
||||
|
||||
if(ct->ct_keystate != CT_RESOLVED)
|
||||
tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
|
||||
tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_dvb_svcname);
|
||||
|
||||
ct->ct_keystate = CT_RESOLVED;
|
||||
}
|
||||
|
@ -617,21 +578,22 @@ capmt_thread(void *aux)
|
|||
if (!capmt->capmt_oscam) {
|
||||
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0], capmt->capmt_port);
|
||||
} else {
|
||||
#if TODO_FIX_THIS //ENABLE_LINUXDVB
|
||||
th_dvb_adapter_t *tda;
|
||||
TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
|
||||
if (!tda->tda_enabled)
|
||||
int i;
|
||||
extern const idclass_t linuxdvb_adapter_class;
|
||||
linuxdvb_adapter_t *la;
|
||||
idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class);
|
||||
for (i = 0; i < is->is_count; i++) {
|
||||
la = (linuxdvb_adapter_t*)is->is_array[i];
|
||||
if (!la->mi_enabled) continue;
|
||||
if (!la->la_rootpath) continue;
|
||||
if (la->la_number > MAX_CA) {
|
||||
tvhlog(LOG_ERR, "capmt", "adapter number > MAX_CA");
|
||||
continue;
|
||||
if (tda->tda_rootpath) { //if rootpath is NULL then can't rely on tda_adapter_num because it is always 0
|
||||
if (tda->tda_adapter_num > MAX_CA) {
|
||||
tvhlog(LOG_ERR, "capmt", "adapter number > MAX_CA");
|
||||
continue;
|
||||
}
|
||||
tvhlog(LOG_INFO, "capmt", "Creating capmt UDP socket for adapter %d", tda->tda_adapter_num);
|
||||
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[tda->tda_adapter_num], 9000 + tda->tda_adapter_num);
|
||||
}
|
||||
tvhlog(LOG_INFO, "capmt", "Creating capmt UDP socket for adapter %d",
|
||||
la->la_number);
|
||||
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[la->la_number], 9000 + la->la_number);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (bind_ok)
|
||||
handle_ca0(capmt);
|
||||
|
@ -672,14 +634,27 @@ capmt_thread(void *aux)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
capmt_table_input(struct th_descrambler *td, struct service *t,
|
||||
capmt_table_input(struct th_descrambler *td, struct service *s,
|
||||
struct elementary_stream *st, const uint8_t *data, int len)
|
||||
{
|
||||
extern const idclass_t mpegts_service_class;
|
||||
extern const idclass_t linuxdvb_frontend_class;
|
||||
capmt_service_t *ct = (capmt_service_t *)td;
|
||||
capmt_t *capmt = ct->ct_capmt;
|
||||
int adapter_num = t->s_dvb_mux->dm_current_tdmi->tdmi_adapter->tda_adapter_num;
|
||||
mpegts_service_t *t = (mpegts_service_t*)s;
|
||||
linuxdvb_frontend_t *lfe;
|
||||
int adapter_num;
|
||||
int total_caids = 0, current_caid = 0;
|
||||
|
||||
/* Validate */
|
||||
if (!idnode_is_instance(&s->s_id, &mpegts_service_class))
|
||||
return;
|
||||
if (!t->s_dvb_active_input) return;
|
||||
lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
|
||||
if (!idnode_is_instance(&lfe->mi_id, &linuxdvb_frontend_class))
|
||||
return;
|
||||
adapter_num = ((linuxdvb_adapter_t*)lfe->lh_parent)->la_number;
|
||||
|
||||
caid_t *c;
|
||||
|
||||
LIST_FOREACH(c, &st->es_caids, link) {
|
||||
|
@ -713,7 +688,7 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
|
|||
if (!cce)
|
||||
{
|
||||
tvhlog(LOG_DEBUG, "capmt",
|
||||
"New caid 0x%04X for service \"%s\"", c->caid, t->s_svcname);
|
||||
"New caid 0x%04X for service \"%s\"", c->caid, t->s_dvb_svcname);
|
||||
|
||||
/* ecmpid not already seen, add it to list */
|
||||
cce = calloc(1, sizeof(capmt_caid_ecm_t));
|
||||
|
@ -734,12 +709,8 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
|
|||
|
||||
uint16_t sid = t->s_dvb_service_id;
|
||||
uint16_t ecmpid = st->es_pid;
|
||||
#if TODO_FIX_THIS
|
||||
uint16_t transponder = t->s_dvb_mux_instance->tdmi_transport_stream_id;
|
||||
uint16_t onid = t->s_dvb_mux_instance->tdmi_network_id;
|
||||
#else
|
||||
uint16_t transponder = 0, onid = 0;
|
||||
#endif
|
||||
uint16_t transponder = t->s_dvb_mux->mm_tsid;
|
||||
uint16_t onid = t->s_dvb_mux->mm_onid;
|
||||
|
||||
/* don't do too much requests */
|
||||
if (current_caid == total_caids && caid != ct->ct_caid_last)
|
||||
|
@ -857,7 +828,7 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
|
|||
|
||||
if(ct->ct_keystate != CT_RESOLVED)
|
||||
tvhlog(LOG_DEBUG, "capmt",
|
||||
"Trying to obtain key for service \"%s\"",t->s_svcname);
|
||||
"Trying to obtain key for service \"%s\"",t->s_dvb_svcname);
|
||||
|
||||
buf[9] = pmtversion;
|
||||
pmtversion = (pmtversion + 1) & 0x1F;
|
||||
|
@ -876,21 +847,12 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
|
|||
/**
|
||||
*
|
||||
*/
|
||||
#if ENABLE_DVBCSA
|
||||
static int
|
||||
capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||
const uint8_t *tsb)
|
||||
capmt_descramble
|
||||
(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||
const uint8_t *tsb)
|
||||
{
|
||||
capmt_service_t *ct = (capmt_service_t *)td;
|
||||
uint8_t *pkt;
|
||||
int xc0;
|
||||
int ev_od;
|
||||
int len;
|
||||
int offset;
|
||||
int n;
|
||||
// FIXME: //int residue;
|
||||
int i;
|
||||
uint8_t *t0;
|
||||
|
||||
if(ct->ct_keystate == CT_FORBIDDEN)
|
||||
return 1;
|
||||
|
@ -898,110 +860,10 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
|
|||
if(ct->ct_keystate != CT_RESOLVED)
|
||||
return -1;
|
||||
|
||||
pkt = ct->ct_tsbcluster + ct->ct_fill * 188;
|
||||
memcpy(pkt, tsb, 188);
|
||||
ct->ct_fill++;
|
||||
tvhcsa_descramble(&ct->ct_csa, (mpegts_service_t*)t, st, tsb, 0);
|
||||
|
||||
do { // handle this packet
|
||||
xc0 = pkt[3] & 0xc0;
|
||||
if(xc0 == 0x00) { // clear
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x40) { // reserved
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
|
||||
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
|
||||
pkt[3] &= 0x3f; // consider it decrypted now
|
||||
if(pkt[3] & 0x20) { // incomplete packet
|
||||
offset = 4 + pkt[4] + 1;
|
||||
len = 188 - offset;
|
||||
n = len >> 3;
|
||||
// FIXME: //residue = len - (n << 3);
|
||||
if(n == 0) { // decrypted==encrypted!
|
||||
break; // this doesn't need more processing
|
||||
}
|
||||
} else {
|
||||
len = 184;
|
||||
offset = 4;
|
||||
// FIXME: //n = 23;
|
||||
// FIXME: //residue = 0;
|
||||
}
|
||||
if(ev_od == 0) {
|
||||
ct->ct_tsbbatch_even[ct->ct_fill_even].data = pkt + offset;
|
||||
ct->ct_tsbbatch_even[ct->ct_fill_even].len = len;
|
||||
ct->ct_fill_even++;
|
||||
} else {
|
||||
ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = pkt + offset;
|
||||
ct->ct_tsbbatch_odd[ct->ct_fill_odd].len = len;
|
||||
ct->ct_fill_odd++;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(ct->ct_fill != ct->ct_cluster_size)
|
||||
return 0;
|
||||
|
||||
if(ct->ct_fill_even) {
|
||||
ct->ct_tsbbatch_even[ct->ct_fill_even].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->ct_key_even, ct->ct_tsbbatch_even, 184);
|
||||
ct->ct_fill_even = 0;
|
||||
}
|
||||
if(ct->ct_fill_odd) {
|
||||
ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->ct_key_odd, ct->ct_tsbbatch_odd, 184);
|
||||
ct->ct_fill_odd = 0;
|
||||
}
|
||||
|
||||
t0 = ct->ct_tsbcluster;
|
||||
for(i = 0; i < ct->ct_fill; i++) {
|
||||
ts_recv_packet2(t, t0);
|
||||
t0 += 188;
|
||||
}
|
||||
ct->ct_fill = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||
const uint8_t *tsb)
|
||||
{
|
||||
capmt_service_t *ct = (capmt_service_t *)td;
|
||||
int r, i;
|
||||
unsigned char *vec[3];
|
||||
uint8_t *t0;
|
||||
|
||||
if(ct->ct_keystate == CT_FORBIDDEN)
|
||||
return 1;
|
||||
|
||||
if(ct->ct_keystate != CT_RESOLVED)
|
||||
return -1;
|
||||
|
||||
memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
|
||||
ct->ct_fill++;
|
||||
|
||||
if(ct->ct_fill != ct->ct_cluster_size)
|
||||
return 0;
|
||||
|
||||
ct->ct_fill = 0;
|
||||
|
||||
vec[0] = ct->ct_tsbcluster;
|
||||
vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
|
||||
vec[2] = NULL;
|
||||
|
||||
while(1) {
|
||||
t0 = vec[0];
|
||||
r = decrypt_packets(ct->ct_keys, vec);
|
||||
if(r == 0)
|
||||
break;
|
||||
for(i = 0; i < r; i++) {
|
||||
ts_recv_packet2(t, t0);
|
||||
t0 += 188;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check if our CAID's matches, and if so, link
|
||||
|
@ -1009,47 +871,46 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
|
|||
* global_lock is held
|
||||
*/
|
||||
void
|
||||
capmt_service_start(service_t *t)
|
||||
capmt_service_start(service_t *s)
|
||||
{
|
||||
extern const idclass_t mpegts_service_class;
|
||||
extern const idclass_t linuxdvb_frontend_class;
|
||||
capmt_t *capmt;
|
||||
capmt_service_t *ct;
|
||||
capmt_caid_ecm_t *cce;
|
||||
th_descrambler_t *td;
|
||||
mpegts_service_t *t = (mpegts_service_t*)s;
|
||||
linuxdvb_frontend_t *lfe;
|
||||
int tuner = 0;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
/* Validate */
|
||||
if (!idnode_is_instance(&s->s_id, &mpegts_service_class))
|
||||
return;
|
||||
if (!t->s_dvb_active_input) return;
|
||||
lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
|
||||
if (!idnode_is_instance(&lfe->mi_id, &linuxdvb_frontend_class))
|
||||
return;
|
||||
tuner = ((linuxdvb_adapter_t*)lfe->lh_parent)->la_number;
|
||||
|
||||
TAILQ_FOREACH(capmt, &capmts, capmt_link) {
|
||||
/* skip, if we're not active */
|
||||
if (!capmt->capmt_enabled)
|
||||
continue;
|
||||
|
||||
#if TODO_FIX_THIS
|
||||
if (!(t->s_dvb_mux_instance && t->s_dvb_mux_instance->tdmi_adapter))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
tvhlog(LOG_INFO, "capmt",
|
||||
"Starting capmt server for service \"%s\" on tuner %d",
|
||||
t->s_svcname,
|
||||
t->s_dvb_mux->dm_current_tdmi->tdmi_adapter->tda_adapter_num);
|
||||
t->s_dvb_svcname, tuner);
|
||||
|
||||
elementary_stream_t *st;
|
||||
|
||||
/* create new capmt service */
|
||||
ct = calloc(1, sizeof(capmt_service_t));
|
||||
#if ENABLE_DVBCSA
|
||||
ct->ct_cluster_size = dvbcsa_bs_batch_size();
|
||||
#else
|
||||
ct->ct_cluster_size = get_suggested_cluster_size();
|
||||
#endif
|
||||
ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
|
||||
ct->ct_seq = capmt->capmt_seq++;
|
||||
#if ENABLE_DVBCSA
|
||||
ct->ct_tsbbatch_even = malloc((ct->ct_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
ct->ct_tsbbatch_odd = malloc((ct->ct_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
#endif
|
||||
ct = calloc(1, sizeof(capmt_service_t));
|
||||
tvhcsa_init(&ct->ct_csa);
|
||||
ct->ct_capmt = capmt;
|
||||
ct->ct_service = t;
|
||||
|
||||
|
||||
TAILQ_FOREACH(st, &t->s_components, es_link) {
|
||||
caid_t *c;
|
||||
|
@ -1058,7 +919,7 @@ capmt_service_start(service_t *t)
|
|||
continue;
|
||||
|
||||
tvhlog(LOG_DEBUG, "capmt",
|
||||
"New caid 0x%04X for service \"%s\"", c->caid, t->s_svcname);
|
||||
"New caid 0x%04X for service \"%s\"", c->caid, t->s_dvb_svcname);
|
||||
|
||||
/* add it to list */
|
||||
cce = calloc(1, sizeof(capmt_caid_ecm_t));
|
||||
|
@ -1072,15 +933,6 @@ capmt_service_start(service_t *t)
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_DVBCSA
|
||||
ct->ct_key_even = dvbcsa_bs_key_alloc();
|
||||
ct->ct_key_odd = dvbcsa_bs_key_alloc();
|
||||
#else
|
||||
ct->ct_keys = get_key_struct();
|
||||
#endif
|
||||
ct->ct_capmt = capmt;
|
||||
ct->ct_service = t;
|
||||
|
||||
td = &ct->ct_head;
|
||||
td->td_stop = capmt_service_destroy;
|
||||
td->td_table = capmt_table_input;
|
||||
|
|
|
@ -31,20 +31,15 @@
|
|||
|
||||
#include "tvheadend.h"
|
||||
#include "tcp.h"
|
||||
#include "psi.h"
|
||||
#include "tsdemux.h"
|
||||
#include "cwc.h"
|
||||
#include "notify.h"
|
||||
#include "atomic.h"
|
||||
#include "dtable.h"
|
||||
#include "subscriptions.h"
|
||||
#include "service.h"
|
||||
|
||||
#if ENABLE_DVBCSA
|
||||
#include <dvbcsa/dvbcsa.h>
|
||||
#else
|
||||
#include "ffdecsa/FFdecsa.h"
|
||||
#endif
|
||||
#include "input/mpegts.h"
|
||||
#include "input/mpegts/tsdemux.h"
|
||||
#include "tvhcsa.h"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -143,7 +138,7 @@ typedef struct ecm_pid {
|
|||
typedef struct cwc_service {
|
||||
th_descrambler_t cs_head;
|
||||
|
||||
service_t *cs_service;
|
||||
mpegts_service_t *cs_service;
|
||||
|
||||
struct cwc *cs_cwc;
|
||||
|
||||
|
@ -170,29 +165,11 @@ typedef struct cwc_service {
|
|||
CS_IDLE
|
||||
} cs_keystate;
|
||||
|
||||
#if ENABLE_DVBCSA
|
||||
struct dvbcsa_bs_key_s *cs_key_even;
|
||||
struct dvbcsa_bs_key_s *cs_key_odd;
|
||||
#else
|
||||
void *cs_keys;
|
||||
#endif
|
||||
|
||||
uint8_t cs_cw[16];
|
||||
int cs_pending_cw_update;
|
||||
|
||||
/**
|
||||
* CSA
|
||||
*/
|
||||
int cs_cluster_size;
|
||||
uint8_t *cs_tsbcluster;
|
||||
int cs_fill;
|
||||
#if ENABLE_DVBCSA
|
||||
struct dvbcsa_bs_batch_s *cs_tsbbatch_even;
|
||||
struct dvbcsa_bs_batch_s *cs_tsbbatch_odd;
|
||||
int cs_fill_even;
|
||||
int cs_fill_odd;
|
||||
#endif
|
||||
|
||||
tvhcsa_t cs_csa;
|
||||
|
||||
LIST_HEAD(, ecm_pid) cs_pids;
|
||||
|
||||
} cwc_service_t;
|
||||
|
@ -612,7 +589,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
|
|||
cwc->cwc_connected = 1;
|
||||
cwc_comet_status_update(cwc);
|
||||
cwc->cwc_caid = (msg[4] << 8) | msg[5];
|
||||
n = psi_caid2name(cwc->cwc_caid & 0xff00) ?: "Unknown";
|
||||
n = descrambler_caid2name(cwc->cwc_caid & 0xff00) ?: "Unknown";
|
||||
|
||||
memcpy(cwc->cwc_ua, &msg[6], 8);
|
||||
|
||||
|
@ -776,7 +753,7 @@ static void
|
|||
handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
|
||||
int len, int seq)
|
||||
{
|
||||
service_t *t = ct->cs_service;
|
||||
mpegts_service_t *t = ct->cs_service;
|
||||
ecm_pid_t *ep, *epn;
|
||||
cwc_service_t *ct2;
|
||||
cwc_t *cwc2;
|
||||
|
@ -800,7 +777,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
|
|||
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,
|
||||
t->s_dvb_svcname, chaninfo, ct->cs_cwc->cwc_hostname,
|
||||
ct->cs_cwc->cwc_port);
|
||||
goto forbid;
|
||||
}
|
||||
|
@ -812,7 +789,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
|
|||
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);
|
||||
t->s_dvb_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
|
||||
es->es_nok = 3; /* do not send more ECM requests */
|
||||
goto forbid;
|
||||
}
|
||||
|
@ -820,7 +797,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
|
|||
}
|
||||
|
||||
tvhlog(LOG_DEBUG, "cwc", "Received NOK for service \"%s\"%s (seqno: %d "
|
||||
"Req delay: %"PRId64" ms)", t->s_svcname, chaninfo, seq, delay);
|
||||
"Req delay: %"PRId64" ms)", t->s_dvb_svcname, chaninfo, seq, delay);
|
||||
|
||||
forbid:
|
||||
LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
|
||||
|
@ -837,7 +814,7 @@ forbid:
|
|||
tvhlog(LOG_ERR, "cwc",
|
||||
"Can not descramble service \"%s\", access denied (seqno: %d "
|
||||
"Req delay: %"PRId64" ms)",
|
||||
t->s_svcname, seq, delay);
|
||||
t->s_dvb_svcname, seq, delay);
|
||||
|
||||
ct->cs_keystate = CS_FORBIDDEN;
|
||||
ct->ecm_state = ECM_RESET;
|
||||
|
@ -853,7 +830,7 @@ forbid:
|
|||
if(t->s_prefcapid == 0 || t->s_prefcapid != ct->cs_channel) {
|
||||
t->s_prefcapid = ct->cs_channel;
|
||||
tvhlog(LOG_DEBUG, "cwc", "Saving prefered PID %d", t->s_prefcapid);
|
||||
service_request_save(t, 0);
|
||||
service_request_save((service_t*)t, 0);
|
||||
}
|
||||
|
||||
tvhlog(LOG_DEBUG, "cwc",
|
||||
|
@ -862,7 +839,7 @@ forbid:
|
|||
" odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d "
|
||||
"Req delay: %"PRId64" ms)",
|
||||
chaninfo,
|
||||
t->s_svcname,
|
||||
t->s_dvb_svcname,
|
||||
msg[3 + 0], msg[3 + 1], msg[3 + 2], msg[3 + 3], msg[3 + 4],
|
||||
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],
|
||||
|
@ -875,7 +852,7 @@ forbid:
|
|||
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);
|
||||
t->s_dvb_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -884,7 +861,7 @@ forbid:
|
|||
if(ct->cs_keystate != CS_RESOLVED)
|
||||
tvhlog(LOG_DEBUG, "cwc",
|
||||
"Obtained key for service \"%s\" in %"PRId64" ms, from %s:%i",
|
||||
t->s_svcname, delay, ct->cs_cwc->cwc_hostname,
|
||||
t->s_dvb_svcname, delay, ct->cs_cwc->cwc_hostname,
|
||||
ct->cs_cwc->cwc_port);
|
||||
|
||||
ct->cs_keystate = CS_RESOLVED;
|
||||
|
@ -901,7 +878,7 @@ forbid:
|
|||
for(i = 0; i < 256; i++)
|
||||
free(ep->ep_sections[i]);
|
||||
LIST_REMOVE(ep, ep_link);
|
||||
tvhlog(LOG_WARNING, "cwc", "Delete ECM (PID %d) for service \"%s\"", ep->ep_pid, t->s_svcname);
|
||||
tvhlog(LOG_WARNING, "cwc", "Delete ECM (PID %d) for service \"%s\"", ep->ep_pid, t->s_dvb_svcname);
|
||||
free(ep);
|
||||
ep = epn;
|
||||
}
|
||||
|
@ -1162,7 +1139,7 @@ cwc_thread(void *aux)
|
|||
cwc_t *cwc = aux;
|
||||
int fd, d;
|
||||
char errbuf[100];
|
||||
service_t *t;
|
||||
mpegts_service_t *t;
|
||||
char hostname[256];
|
||||
int port;
|
||||
struct timespec ts;
|
||||
|
@ -1609,10 +1586,11 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen)
|
|||
* t->s_streaming_mutex is held
|
||||
*/
|
||||
static void
|
||||
cwc_table_input(struct th_descrambler *td, struct service *t,
|
||||
cwc_table_input(struct th_descrambler *td, service_t *s,
|
||||
struct elementary_stream *st, const uint8_t *data, int len)
|
||||
{
|
||||
cwc_service_t *ct = (cwc_service_t *)td;
|
||||
mpegts_service_t *t = (mpegts_service_t*)s;
|
||||
uint16_t sid = t->s_dvb_service_id;
|
||||
cwc_t *cwc = ct->cs_cwc;
|
||||
int channel;
|
||||
|
@ -1641,15 +1619,16 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
|
|||
ct->ecm_state = ECM_INIT;
|
||||
ct->cs_channel = -1;
|
||||
t->s_prefcapid = 0;
|
||||
tvhlog(LOG_DEBUG, "cwc", "Reset after unexpected or no reply for service \"%s\"", t->s_svcname);
|
||||
tvhlog(LOG_DEBUG, "cwc", "Reset after unexpected or no reply for service \"%s\"", t->s_dvb_svcname);
|
||||
}
|
||||
|
||||
if (ct->ecm_state == ECM_INIT) {
|
||||
// Validate prefered ECM PID
|
||||
if(t->s_prefcapid != 0) {
|
||||
struct elementary_stream *prefca = service_stream_find(t, t->s_prefcapid);
|
||||
struct elementary_stream *prefca
|
||||
= service_stream_find((service_t*)t, t->s_prefcapid);
|
||||
if (!prefca || prefca->es_type != SCT_CA) {
|
||||
tvhlog(LOG_DEBUG, "cwc", "Invalid prefered ECM (PID %d) found for service \"%s\"", t->s_prefcapid, t->s_svcname);
|
||||
tvhlog(LOG_DEBUG, "cwc", "Invalid prefered ECM (PID %d) found for service \"%s\"", t->s_prefcapid, t->s_dvb_svcname);
|
||||
t->s_prefcapid = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1658,13 +1637,13 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
|
|||
ep = calloc(1, sizeof(ecm_pid_t));
|
||||
ep->ep_pid = t->s_prefcapid;
|
||||
LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
|
||||
tvhlog(LOG_DEBUG, "cwc", "Insert prefered ECM (PID %d) for service \"%s\"", t->s_prefcapid, t->s_svcname);
|
||||
tvhlog(LOG_DEBUG, "cwc", "Insert prefered ECM (PID %d) for service \"%s\"", t->s_prefcapid, t->s_dvb_svcname);
|
||||
}
|
||||
else if(t->s_prefcapid == 0) {
|
||||
ep = calloc(1, sizeof(ecm_pid_t));
|
||||
ep->ep_pid = st->es_pid;
|
||||
LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
|
||||
tvhlog(LOG_DEBUG, "cwc", "Insert new ECM (PID %d) for service \"%s\"", st->es_pid, t->s_svcname);
|
||||
tvhlog(LOG_DEBUG, "cwc", "Insert new ECM (PID %d) for service \"%s\"", st->es_pid, t->s_dvb_svcname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1733,7 +1712,7 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
|
|||
|
||||
tvhlog(LOG_DEBUG, "cwc",
|
||||
"Sending ECM%s section=%d/%d, for service \"%s\" (seqno: %d)",
|
||||
chaninfo, section, ep->ep_last_section, t->s_svcname, es->es_seq);
|
||||
chaninfo, section, ep->ep_last_section, t->s_dvb_svcname, es->es_seq);
|
||||
es->es_time = getmonoclock();
|
||||
break;
|
||||
|
||||
|
@ -1909,21 +1888,13 @@ update_keys(cwc_service_t *ct)
|
|||
ct->cs_pending_cw_update = 0;
|
||||
for(i = 0; i < 8; i++)
|
||||
if(ct->cs_cw[i]) {
|
||||
#if ENABLE_DVBCSA
|
||||
dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
|
||||
#else
|
||||
set_even_control_word(ct->cs_keys, ct->cs_cw);
|
||||
#endif
|
||||
tvhcsa_set_key_even(&ct->cs_csa, ct->cs_cw);
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
if(ct->cs_cw[8 + i]) {
|
||||
#if ENABLE_DVBCSA
|
||||
dvbcsa_bs_key_set(ct->cs_cw + 8, ct->cs_key_odd);
|
||||
#else
|
||||
set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
|
||||
#endif
|
||||
tvhcsa_set_key_odd(&ct->cs_csa, ct->cs_cw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1932,160 +1903,30 @@ update_keys(cwc_service_t *ct)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
#if ENABLE_DVBCSA
|
||||
static int
|
||||
cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||
const uint8_t *tsb)
|
||||
cwc_descramble
|
||||
(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||
const uint8_t *tsb)
|
||||
{
|
||||
cwc_service_t *ct = (cwc_service_t *)td;
|
||||
uint8_t *pkt;
|
||||
int xc0;
|
||||
int ev_od;
|
||||
int len;
|
||||
int offset;
|
||||
int n;
|
||||
// FIXME: //int residue;
|
||||
|
||||
if(ct->cs_keystate == CS_FORBIDDEN)
|
||||
return 1;
|
||||
|
||||
if(ct->cs_keystate != CS_RESOLVED)
|
||||
return -1;
|
||||
|
||||
if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
|
||||
|
||||
if(ct->cs_csa.csa_fill == 0 && ct->cs_pending_cw_update)
|
||||
update_keys(ct);
|
||||
|
||||
pkt = ct->cs_tsbcluster + ct->cs_fill * 188;
|
||||
memcpy(pkt, tsb, 188);
|
||||
ct->cs_fill++;
|
||||
|
||||
do { // handle this packet
|
||||
xc0 = pkt[3] & 0xc0;
|
||||
if(xc0 == 0x00) { // clear
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x40) { // reserved
|
||||
break;
|
||||
}
|
||||
if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
|
||||
ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
|
||||
pkt[3] &= 0x3f; // consider it decrypted now
|
||||
if(pkt[3] & 0x20) { // incomplete packet
|
||||
offset = 4 + pkt[4] + 1;
|
||||
len = 188 - offset;
|
||||
n = len >> 3;
|
||||
// FIXME: //residue = len - (n << 3);
|
||||
if(n == 0) { // decrypted==encrypted!
|
||||
break; // this doesn't need more processing
|
||||
}
|
||||
} else {
|
||||
len = 184;
|
||||
offset = 4;
|
||||
// FIXME: //n = 23;
|
||||
// FIXME: //residue = 0;
|
||||
}
|
||||
if(ev_od == 0) {
|
||||
ct->cs_tsbbatch_even[ct->cs_fill_even].data = pkt + offset;
|
||||
ct->cs_tsbbatch_even[ct->cs_fill_even].len = len;
|
||||
ct->cs_fill_even++;
|
||||
} else {
|
||||
ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = pkt + offset;
|
||||
ct->cs_tsbbatch_odd[ct->cs_fill_odd].len = len;
|
||||
ct->cs_fill_odd++;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(ct->cs_fill != ct->cs_cluster_size)
|
||||
return 0;
|
||||
|
||||
if(ct->cs_fill_even) {
|
||||
ct->cs_tsbbatch_even[ct->cs_fill_even].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->cs_key_even, ct->cs_tsbbatch_even, 184);
|
||||
ct->cs_fill_even = 0;
|
||||
}
|
||||
if(ct->cs_fill_odd) {
|
||||
ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = NULL;
|
||||
dvbcsa_bs_decrypt(ct->cs_key_odd, ct->cs_tsbbatch_odd, 184);
|
||||
ct->cs_fill_odd = 0;
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
const uint8_t *t0 = ct->cs_tsbcluster;
|
||||
|
||||
for(i = 0; i < ct->cs_fill; i++) {
|
||||
ts_recv_packet2(t, t0);
|
||||
t0 += 188;
|
||||
}
|
||||
}
|
||||
ct->cs_fill = 0;
|
||||
tvhcsa_descramble(&ct->cs_csa, (mpegts_service_t*)t, st, tsb,
|
||||
ct->cs_pending_cw_update);
|
||||
|
||||
if(ct->cs_pending_cw_update)
|
||||
update_keys(ct);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||
const uint8_t *tsb)
|
||||
{
|
||||
cwc_service_t *ct = (cwc_service_t *)td;
|
||||
int r;
|
||||
unsigned char *vec[3];
|
||||
|
||||
if(ct->cs_keystate == CS_FORBIDDEN)
|
||||
return 1;
|
||||
|
||||
if(ct->cs_keystate != CS_RESOLVED)
|
||||
return -1;
|
||||
|
||||
if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
|
||||
update_keys(ct);
|
||||
|
||||
memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
|
||||
ct->cs_fill++;
|
||||
|
||||
if(ct->cs_fill != ct->cs_cluster_size)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
|
||||
vec[0] = ct->cs_tsbcluster;
|
||||
vec[1] = ct->cs_tsbcluster + ct->cs_fill * 188;
|
||||
vec[2] = NULL;
|
||||
|
||||
r = decrypt_packets(ct->cs_keys, vec);
|
||||
if(r > 0) {
|
||||
int i;
|
||||
const uint8_t *t0 = ct->cs_tsbcluster;
|
||||
|
||||
for(i = 0; i < r; i++) {
|
||||
ts_recv_packet2(t, t0);
|
||||
t0 += 188;
|
||||
}
|
||||
|
||||
r = ct->cs_fill - r;
|
||||
assert(r >= 0);
|
||||
|
||||
if(r > 0)
|
||||
memmove(ct->cs_tsbcluster, t0, r * 188);
|
||||
ct->cs_fill = r;
|
||||
|
||||
if(ct->cs_pending_cw_update && r > 0)
|
||||
continue;
|
||||
} else {
|
||||
ct->cs_fill = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(ct->cs_pending_cw_update)
|
||||
update_keys(ct);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cwc_mutex is held
|
||||
|
@ -2109,15 +1950,7 @@ cwc_service_destroy(th_descrambler_t *td)
|
|||
|
||||
LIST_REMOVE(ct, cs_link);
|
||||
|
||||
#if ENABLE_DVBCSA
|
||||
dvbcsa_bs_key_free(ct->cs_key_odd);
|
||||
dvbcsa_bs_key_free(ct->cs_key_even);
|
||||
free(ct->cs_tsbbatch_odd);
|
||||
free(ct->cs_tsbbatch_even);
|
||||
#else
|
||||
free_key_struct(ct->cs_keys);
|
||||
#endif
|
||||
free(ct->cs_tsbcluster);
|
||||
tvhcsa_destroy(&ct->cs_csa);
|
||||
free(ct);
|
||||
}
|
||||
|
||||
|
@ -2152,6 +1985,10 @@ cwc_service_start(service_t *t)
|
|||
cwc_service_t *ct;
|
||||
th_descrambler_t *td;
|
||||
|
||||
extern const idclass_t mpegts_service_class;
|
||||
if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&cwc_mutex);
|
||||
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
|
||||
if(cwc->cwc_caid == 0)
|
||||
|
@ -2161,24 +1998,9 @@ cwc_service_start(service_t *t)
|
|||
continue;
|
||||
|
||||
ct = calloc(1, sizeof(cwc_service_t));
|
||||
#if ENABLE_DVBCSA
|
||||
ct->cs_cluster_size = dvbcsa_bs_batch_size();
|
||||
#else
|
||||
ct->cs_cluster_size = get_suggested_cluster_size();
|
||||
#endif
|
||||
ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188);
|
||||
#if ENABLE_DVBCSA
|
||||
ct->cs_tsbbatch_even = malloc((ct->cs_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
ct->cs_tsbbatch_odd = malloc((ct->cs_cluster_size + 1) *
|
||||
sizeof(struct dvbcsa_bs_batch_s));
|
||||
ct->cs_key_even = dvbcsa_bs_key_alloc();
|
||||
ct->cs_key_odd = dvbcsa_bs_key_alloc();
|
||||
#else
|
||||
ct->cs_keys = get_key_struct();
|
||||
#endif
|
||||
tvhcsa_init(&ct->cs_csa);
|
||||
ct->cs_cwc = cwc;
|
||||
ct->cs_service = t;
|
||||
ct->cs_service = (mpegts_service_t*)t;
|
||||
ct->cs_channel = -1;
|
||||
ct->ecm_state = ECM_INIT;
|
||||
|
||||
|
|
|
@ -88,8 +88,10 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
|
|||
|
||||
// Note: we always test season first, though it will only be set
|
||||
// if configured
|
||||
if(dae->dae_serieslink)
|
||||
if(dae->dae_serieslink) {
|
||||
if (!e->serieslink || dae->dae_serieslink != e->serieslink) return 0;
|
||||
return 1;
|
||||
}
|
||||
if(dae->dae_season)
|
||||
if (!e->episode->season || dae->dae_season != e->episode->season) return 0;
|
||||
if(dae->dae_brand)
|
||||
|
|
Loading…
Add table
Reference in a new issue