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
|
# CWC
|
||||||
SRCS-${CONFIG_CWC} += \
|
SRCS-${CONFIG_CWC} += \
|
||||||
src/cwc.c \
|
src/descrambler/tvhcsa.c \
|
||||||
src/capmt.c
|
src/descrambler/cwc.c \
|
||||||
|
src/descrambler/capmt.c
|
||||||
|
|
||||||
# FFdecsa
|
# FFdecsa
|
||||||
ifneq ($(CONFIG_DVBCSA),yes)
|
ifneq ($(CONFIG_DVBCSA),yes)
|
||||||
|
|
|
@ -38,20 +38,14 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "tvheadend.h"
|
#include "tvheadend.h"
|
||||||
#include "dvb/dvb.h"
|
#include "input/mpegts.h"
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
#include "psi.h"
|
|
||||||
#include "tsdemux.h"
|
|
||||||
#include "capmt.h"
|
#include "capmt.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "subscriptions.h"
|
#include "subscriptions.h"
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
|
#include "tvhcsa.h"
|
||||||
#if ENABLE_DVBCSA
|
#include "input/mpegts/linuxdvb/linuxdvb_private.h"
|
||||||
#include <dvbcsa/dvbcsa.h>
|
|
||||||
#else
|
|
||||||
#include "ffdecsa/FFdecsa.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ca_pmt_list_management values:
|
// ca_pmt_list_management values:
|
||||||
#define CAPMT_LIST_MORE 0x00 // append a 'MORE' CAPMT object the list and start receiving the next object
|
#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 {
|
typedef struct capmt_service {
|
||||||
th_descrambler_t ct_head;
|
th_descrambler_t ct_head;
|
||||||
|
|
||||||
service_t *ct_service;
|
mpegts_service_t *ct_service;
|
||||||
|
|
||||||
struct capmt *ct_capmt;
|
struct capmt *ct_capmt;
|
||||||
|
|
||||||
|
@ -166,24 +160,7 @@ typedef struct capmt_service {
|
||||||
CT_FORBIDDEN
|
CT_FORBIDDEN
|
||||||
} ct_keystate;
|
} ct_keystate;
|
||||||
|
|
||||||
/* buffers for keystructs */
|
tvhcsa_t ct_csa;
|
||||||
#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
|
|
||||||
|
|
||||||
/* current sequence number */
|
/* current sequence number */
|
||||||
uint16_t ct_seq;
|
uint16_t ct_seq;
|
||||||
|
@ -388,22 +365,14 @@ capmt_service_destroy(th_descrambler_t *td)
|
||||||
|
|
||||||
LIST_REMOVE(ct, ct_link);
|
LIST_REMOVE(ct, ct_link);
|
||||||
|
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_destroy(&ct->ct_csa);
|
||||||
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);
|
|
||||||
free(ct);
|
free(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_ca0(capmt_t* capmt) {
|
handle_ca0(capmt_t* capmt) {
|
||||||
capmt_service_t *ct;
|
capmt_service_t *ct;
|
||||||
service_t *t;
|
mpegts_service_t *t;
|
||||||
int ret, bufsize;
|
int ret, bufsize;
|
||||||
int *request;
|
int *request;
|
||||||
ca_descr_t *ca;
|
ca_descr_t *ca;
|
||||||
|
@ -522,7 +491,7 @@ handle_ca0(capmt_t* capmt) {
|
||||||
|
|
||||||
if(ret < bufsize) {
|
if(ret < bufsize) {
|
||||||
if(ct->ct_keystate != CT_FORBIDDEN) {
|
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;
|
ct->ct_keystate = CT_FORBIDDEN;
|
||||||
}
|
}
|
||||||
|
@ -534,20 +503,12 @@ handle_ca0(capmt_t* capmt) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (memcmp(even, invalid, 8))
|
if (memcmp(even, invalid, 8))
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_set_key_even(&ct->ct_csa, even);
|
||||||
dvbcsa_bs_key_set(even, ct->ct_key_even);
|
|
||||||
#else
|
|
||||||
set_even_control_word(ct->ct_keys, even);
|
|
||||||
#endif
|
|
||||||
if (memcmp(odd, invalid, 8))
|
if (memcmp(odd, invalid, 8))
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_set_key_odd(&ct->ct_csa, odd);
|
||||||
dvbcsa_bs_key_set(odd, ct->ct_key_odd);
|
|
||||||
#else
|
|
||||||
set_odd_control_word(ct->ct_keys, odd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(ct->ct_keystate != CT_RESOLVED)
|
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;
|
ct->ct_keystate = CT_RESOLVED;
|
||||||
}
|
}
|
||||||
|
@ -617,21 +578,22 @@ capmt_thread(void *aux)
|
||||||
if (!capmt->capmt_oscam) {
|
if (!capmt->capmt_oscam) {
|
||||||
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0], capmt->capmt_port);
|
bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0], capmt->capmt_port);
|
||||||
} else {
|
} else {
|
||||||
#if TODO_FIX_THIS //ENABLE_LINUXDVB
|
int i;
|
||||||
th_dvb_adapter_t *tda;
|
extern const idclass_t linuxdvb_adapter_class;
|
||||||
TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
|
linuxdvb_adapter_t *la;
|
||||||
if (!tda->tda_enabled)
|
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;
|
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)
|
if (bind_ok)
|
||||||
handle_ca0(capmt);
|
handle_ca0(capmt);
|
||||||
|
@ -672,14 +634,27 @@ capmt_thread(void *aux)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void
|
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)
|
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_service_t *ct = (capmt_service_t *)td;
|
||||||
capmt_t *capmt = ct->ct_capmt;
|
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;
|
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;
|
caid_t *c;
|
||||||
|
|
||||||
LIST_FOREACH(c, &st->es_caids, link) {
|
LIST_FOREACH(c, &st->es_caids, link) {
|
||||||
|
@ -713,7 +688,7 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
|
||||||
if (!cce)
|
if (!cce)
|
||||||
{
|
{
|
||||||
tvhlog(LOG_DEBUG, "capmt",
|
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 */
|
/* ecmpid not already seen, add it to list */
|
||||||
cce = calloc(1, sizeof(capmt_caid_ecm_t));
|
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 sid = t->s_dvb_service_id;
|
||||||
uint16_t ecmpid = st->es_pid;
|
uint16_t ecmpid = st->es_pid;
|
||||||
#if TODO_FIX_THIS
|
uint16_t transponder = t->s_dvb_mux->mm_tsid;
|
||||||
uint16_t transponder = t->s_dvb_mux_instance->tdmi_transport_stream_id;
|
uint16_t onid = t->s_dvb_mux->mm_onid;
|
||||||
uint16_t onid = t->s_dvb_mux_instance->tdmi_network_id;
|
|
||||||
#else
|
|
||||||
uint16_t transponder = 0, onid = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* don't do too much requests */
|
/* don't do too much requests */
|
||||||
if (current_caid == total_caids && caid != ct->ct_caid_last)
|
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)
|
if(ct->ct_keystate != CT_RESOLVED)
|
||||||
tvhlog(LOG_DEBUG, "capmt",
|
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;
|
buf[9] = pmtversion;
|
||||||
pmtversion = (pmtversion + 1) & 0x1F;
|
pmtversion = (pmtversion + 1) & 0x1F;
|
||||||
|
@ -876,21 +847,12 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#if ENABLE_DVBCSA
|
|
||||||
static int
|
static int
|
||||||
capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
capmt_descramble
|
||||||
const uint8_t *tsb)
|
(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||||
|
const uint8_t *tsb)
|
||||||
{
|
{
|
||||||
capmt_service_t *ct = (capmt_service_t *)td;
|
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)
|
if(ct->ct_keystate == CT_FORBIDDEN)
|
||||||
return 1;
|
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)
|
if(ct->ct_keystate != CT_RESOLVED)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pkt = ct->ct_tsbcluster + ct->ct_fill * 188;
|
tvhcsa_descramble(&ct->ct_csa, (mpegts_service_t*)t, st, tsb, 0);
|
||||||
memcpy(pkt, tsb, 188);
|
|
||||||
ct->ct_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->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;
|
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
|
* 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
|
* global_lock is held
|
||||||
*/
|
*/
|
||||||
void
|
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_t *capmt;
|
||||||
capmt_service_t *ct;
|
capmt_service_t *ct;
|
||||||
capmt_caid_ecm_t *cce;
|
capmt_caid_ecm_t *cce;
|
||||||
th_descrambler_t *td;
|
th_descrambler_t *td;
|
||||||
|
mpegts_service_t *t = (mpegts_service_t*)s;
|
||||||
|
linuxdvb_frontend_t *lfe;
|
||||||
|
int tuner = 0;
|
||||||
|
|
||||||
lock_assert(&global_lock);
|
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) {
|
TAILQ_FOREACH(capmt, &capmts, capmt_link) {
|
||||||
/* skip, if we're not active */
|
/* skip, if we're not active */
|
||||||
if (!capmt->capmt_enabled)
|
if (!capmt->capmt_enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#if TODO_FIX_THIS
|
|
||||||
if (!(t->s_dvb_mux_instance && t->s_dvb_mux_instance->tdmi_adapter))
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tvhlog(LOG_INFO, "capmt",
|
tvhlog(LOG_INFO, "capmt",
|
||||||
"Starting capmt server for service \"%s\" on tuner %d",
|
"Starting capmt server for service \"%s\" on tuner %d",
|
||||||
t->s_svcname,
|
t->s_dvb_svcname, tuner);
|
||||||
t->s_dvb_mux->dm_current_tdmi->tdmi_adapter->tda_adapter_num);
|
|
||||||
|
|
||||||
elementary_stream_t *st;
|
elementary_stream_t *st;
|
||||||
|
|
||||||
/* create new capmt service */
|
/* create new capmt service */
|
||||||
ct = calloc(1, sizeof(capmt_service_t));
|
ct = calloc(1, sizeof(capmt_service_t));
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_init(&ct->ct_csa);
|
||||||
ct->ct_cluster_size = dvbcsa_bs_batch_size();
|
ct->ct_capmt = capmt;
|
||||||
#else
|
ct->ct_service = t;
|
||||||
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
|
|
||||||
|
|
||||||
TAILQ_FOREACH(st, &t->s_components, es_link) {
|
TAILQ_FOREACH(st, &t->s_components, es_link) {
|
||||||
caid_t *c;
|
caid_t *c;
|
||||||
|
@ -1058,7 +919,7 @@ capmt_service_start(service_t *t)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tvhlog(LOG_DEBUG, "capmt",
|
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 */
|
/* add it to list */
|
||||||
cce = calloc(1, sizeof(capmt_caid_ecm_t));
|
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 = &ct->ct_head;
|
||||||
td->td_stop = capmt_service_destroy;
|
td->td_stop = capmt_service_destroy;
|
||||||
td->td_table = capmt_table_input;
|
td->td_table = capmt_table_input;
|
||||||
|
|
|
@ -31,20 +31,15 @@
|
||||||
|
|
||||||
#include "tvheadend.h"
|
#include "tvheadend.h"
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
#include "psi.h"
|
|
||||||
#include "tsdemux.h"
|
|
||||||
#include "cwc.h"
|
#include "cwc.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "subscriptions.h"
|
#include "subscriptions.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "input/mpegts.h"
|
||||||
#if ENABLE_DVBCSA
|
#include "input/mpegts/tsdemux.h"
|
||||||
#include <dvbcsa/dvbcsa.h>
|
#include "tvhcsa.h"
|
||||||
#else
|
|
||||||
#include "ffdecsa/FFdecsa.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -143,7 +138,7 @@ typedef struct ecm_pid {
|
||||||
typedef struct cwc_service {
|
typedef struct cwc_service {
|
||||||
th_descrambler_t cs_head;
|
th_descrambler_t cs_head;
|
||||||
|
|
||||||
service_t *cs_service;
|
mpegts_service_t *cs_service;
|
||||||
|
|
||||||
struct cwc *cs_cwc;
|
struct cwc *cs_cwc;
|
||||||
|
|
||||||
|
@ -170,28 +165,10 @@ typedef struct cwc_service {
|
||||||
CS_IDLE
|
CS_IDLE
|
||||||
} cs_keystate;
|
} 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];
|
uint8_t cs_cw[16];
|
||||||
int cs_pending_cw_update;
|
int cs_pending_cw_update;
|
||||||
|
|
||||||
/**
|
tvhcsa_t cs_csa;
|
||||||
* 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
|
|
||||||
|
|
||||||
LIST_HEAD(, ecm_pid) cs_pids;
|
LIST_HEAD(, ecm_pid) cs_pids;
|
||||||
|
|
||||||
|
@ -612,7 +589,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
|
||||||
cwc->cwc_connected = 1;
|
cwc->cwc_connected = 1;
|
||||||
cwc_comet_status_update(cwc);
|
cwc_comet_status_update(cwc);
|
||||||
cwc->cwc_caid = (msg[4] << 8) | msg[5];
|
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);
|
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,
|
handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
|
||||||
int len, int seq)
|
int len, int seq)
|
||||||
{
|
{
|
||||||
service_t *t = ct->cs_service;
|
mpegts_service_t *t = ct->cs_service;
|
||||||
ecm_pid_t *ep, *epn;
|
ecm_pid_t *ep, *epn;
|
||||||
cwc_service_t *ct2;
|
cwc_service_t *ct2;
|
||||||
cwc_t *cwc2;
|
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) {
|
if (es->es_nok > 2) {
|
||||||
tvhlog(LOG_DEBUG, "cwc",
|
tvhlog(LOG_DEBUG, "cwc",
|
||||||
"Too many NOKs for service \"%s\"%s from %s:%i",
|
"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);
|
ct->cs_cwc->cwc_port);
|
||||||
goto forbid;
|
goto forbid;
|
||||||
}
|
}
|
||||||
|
@ -812,7 +789,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
|
||||||
tvhlog(LOG_DEBUG, "cwc",
|
tvhlog(LOG_DEBUG, "cwc",
|
||||||
"NOK from %s:%i: Already has a key for service \"%s\", from %s:%i",
|
"NOK from %s:%i: Already has a key for service \"%s\", from %s:%i",
|
||||||
ct->cs_cwc->cwc_hostname, ct->cs_cwc->cwc_port,
|
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 */
|
es->es_nok = 3; /* do not send more ECM requests */
|
||||||
goto forbid;
|
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 "
|
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:
|
forbid:
|
||||||
LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
|
LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
|
||||||
|
@ -837,7 +814,7 @@ forbid:
|
||||||
tvhlog(LOG_ERR, "cwc",
|
tvhlog(LOG_ERR, "cwc",
|
||||||
"Can not descramble service \"%s\", access denied (seqno: %d "
|
"Can not descramble service \"%s\", access denied (seqno: %d "
|
||||||
"Req delay: %"PRId64" ms)",
|
"Req delay: %"PRId64" ms)",
|
||||||
t->s_svcname, seq, delay);
|
t->s_dvb_svcname, seq, delay);
|
||||||
|
|
||||||
ct->cs_keystate = CS_FORBIDDEN;
|
ct->cs_keystate = CS_FORBIDDEN;
|
||||||
ct->ecm_state = ECM_RESET;
|
ct->ecm_state = ECM_RESET;
|
||||||
|
@ -853,7 +830,7 @@ forbid:
|
||||||
if(t->s_prefcapid == 0 || t->s_prefcapid != ct->cs_channel) {
|
if(t->s_prefcapid == 0 || t->s_prefcapid != ct->cs_channel) {
|
||||||
t->s_prefcapid = ct->cs_channel;
|
t->s_prefcapid = ct->cs_channel;
|
||||||
tvhlog(LOG_DEBUG, "cwc", "Saving prefered PID %d", t->s_prefcapid);
|
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",
|
tvhlog(LOG_DEBUG, "cwc",
|
||||||
|
@ -862,7 +839,7 @@ forbid:
|
||||||
" odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d "
|
" odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d "
|
||||||
"Req delay: %"PRId64" ms)",
|
"Req delay: %"PRId64" ms)",
|
||||||
chaninfo,
|
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 + 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 + 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 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14],
|
||||||
|
@ -875,7 +852,7 @@ forbid:
|
||||||
ct->cs_keystate = CS_IDLE;
|
ct->cs_keystate = CS_IDLE;
|
||||||
tvhlog(LOG_DEBUG, "cwc",
|
tvhlog(LOG_DEBUG, "cwc",
|
||||||
"Already has a key for service \"%s\", from %s:%i",
|
"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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -884,7 +861,7 @@ forbid:
|
||||||
if(ct->cs_keystate != CS_RESOLVED)
|
if(ct->cs_keystate != CS_RESOLVED)
|
||||||
tvhlog(LOG_DEBUG, "cwc",
|
tvhlog(LOG_DEBUG, "cwc",
|
||||||
"Obtained key for service \"%s\" in %"PRId64" ms, from %s:%i",
|
"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_cwc->cwc_port);
|
||||||
|
|
||||||
ct->cs_keystate = CS_RESOLVED;
|
ct->cs_keystate = CS_RESOLVED;
|
||||||
|
@ -901,7 +878,7 @@ forbid:
|
||||||
for(i = 0; i < 256; i++)
|
for(i = 0; i < 256; i++)
|
||||||
free(ep->ep_sections[i]);
|
free(ep->ep_sections[i]);
|
||||||
LIST_REMOVE(ep, ep_link);
|
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);
|
free(ep);
|
||||||
ep = epn;
|
ep = epn;
|
||||||
}
|
}
|
||||||
|
@ -1162,7 +1139,7 @@ cwc_thread(void *aux)
|
||||||
cwc_t *cwc = aux;
|
cwc_t *cwc = aux;
|
||||||
int fd, d;
|
int fd, d;
|
||||||
char errbuf[100];
|
char errbuf[100];
|
||||||
service_t *t;
|
mpegts_service_t *t;
|
||||||
char hostname[256];
|
char hostname[256];
|
||||||
int port;
|
int port;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
@ -1609,10 +1586,11 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen)
|
||||||
* t->s_streaming_mutex is held
|
* t->s_streaming_mutex is held
|
||||||
*/
|
*/
|
||||||
static void
|
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)
|
struct elementary_stream *st, const uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
cwc_service_t *ct = (cwc_service_t *)td;
|
cwc_service_t *ct = (cwc_service_t *)td;
|
||||||
|
mpegts_service_t *t = (mpegts_service_t*)s;
|
||||||
uint16_t sid = t->s_dvb_service_id;
|
uint16_t sid = t->s_dvb_service_id;
|
||||||
cwc_t *cwc = ct->cs_cwc;
|
cwc_t *cwc = ct->cs_cwc;
|
||||||
int channel;
|
int channel;
|
||||||
|
@ -1641,15 +1619,16 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
|
||||||
ct->ecm_state = ECM_INIT;
|
ct->ecm_state = ECM_INIT;
|
||||||
ct->cs_channel = -1;
|
ct->cs_channel = -1;
|
||||||
t->s_prefcapid = 0;
|
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) {
|
if (ct->ecm_state == ECM_INIT) {
|
||||||
// Validate prefered ECM PID
|
// Validate prefered ECM PID
|
||||||
if(t->s_prefcapid != 0) {
|
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) {
|
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;
|
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 = calloc(1, sizeof(ecm_pid_t));
|
||||||
ep->ep_pid = t->s_prefcapid;
|
ep->ep_pid = t->s_prefcapid;
|
||||||
LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
|
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) {
|
else if(t->s_prefcapid == 0) {
|
||||||
ep = calloc(1, sizeof(ecm_pid_t));
|
ep = calloc(1, sizeof(ecm_pid_t));
|
||||||
ep->ep_pid = st->es_pid;
|
ep->ep_pid = st->es_pid;
|
||||||
LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
|
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",
|
tvhlog(LOG_DEBUG, "cwc",
|
||||||
"Sending ECM%s section=%d/%d, for service \"%s\" (seqno: %d)",
|
"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();
|
es->es_time = getmonoclock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1909,21 +1888,13 @@ update_keys(cwc_service_t *ct)
|
||||||
ct->cs_pending_cw_update = 0;
|
ct->cs_pending_cw_update = 0;
|
||||||
for(i = 0; i < 8; i++)
|
for(i = 0; i < 8; i++)
|
||||||
if(ct->cs_cw[i]) {
|
if(ct->cs_cw[i]) {
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_set_key_even(&ct->cs_csa, ct->cs_cw);
|
||||||
dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
|
|
||||||
#else
|
|
||||||
set_even_control_word(ct->cs_keys, ct->cs_cw);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < 8; i++)
|
for(i = 0; i < 8; i++)
|
||||||
if(ct->cs_cw[8 + i]) {
|
if(ct->cs_cw[8 + i]) {
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_set_key_odd(&ct->cs_csa, ct->cs_cw);
|
||||||
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
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1932,19 +1903,12 @@ update_keys(cwc_service_t *ct)
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#if ENABLE_DVBCSA
|
|
||||||
static int
|
static int
|
||||||
cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
cwc_descramble
|
||||||
const uint8_t *tsb)
|
(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||||
|
const uint8_t *tsb)
|
||||||
{
|
{
|
||||||
cwc_service_t *ct = (cwc_service_t *)td;
|
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)
|
if(ct->cs_keystate == CS_FORBIDDEN)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1952,140 +1916,17 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
|
||||||
if(ct->cs_keystate != CS_RESOLVED)
|
if(ct->cs_keystate != CS_RESOLVED)
|
||||||
return -1;
|
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);
|
update_keys(ct);
|
||||||
|
|
||||||
pkt = ct->cs_tsbcluster + ct->cs_fill * 188;
|
tvhcsa_descramble(&ct->cs_csa, (mpegts_service_t*)t, st, tsb,
|
||||||
memcpy(pkt, tsb, 188);
|
ct->cs_pending_cw_update);
|
||||||
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;
|
|
||||||
|
|
||||||
if(ct->cs_pending_cw_update)
|
if(ct->cs_pending_cw_update)
|
||||||
update_keys(ct);
|
update_keys(ct);
|
||||||
|
|
||||||
return 0;
|
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
|
* cwc_mutex is held
|
||||||
|
@ -2109,15 +1950,7 @@ cwc_service_destroy(th_descrambler_t *td)
|
||||||
|
|
||||||
LIST_REMOVE(ct, cs_link);
|
LIST_REMOVE(ct, cs_link);
|
||||||
|
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_destroy(&ct->cs_csa);
|
||||||
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);
|
|
||||||
free(ct);
|
free(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2152,6 +1985,10 @@ cwc_service_start(service_t *t)
|
||||||
cwc_service_t *ct;
|
cwc_service_t *ct;
|
||||||
th_descrambler_t *td;
|
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);
|
pthread_mutex_lock(&cwc_mutex);
|
||||||
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
|
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
|
||||||
if(cwc->cwc_caid == 0)
|
if(cwc->cwc_caid == 0)
|
||||||
|
@ -2161,24 +1998,9 @@ cwc_service_start(service_t *t)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ct = calloc(1, sizeof(cwc_service_t));
|
ct = calloc(1, sizeof(cwc_service_t));
|
||||||
#if ENABLE_DVBCSA
|
tvhcsa_init(&ct->cs_csa);
|
||||||
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
|
|
||||||
ct->cs_cwc = cwc;
|
ct->cs_cwc = cwc;
|
||||||
ct->cs_service = t;
|
ct->cs_service = (mpegts_service_t*)t;
|
||||||
ct->cs_channel = -1;
|
ct->cs_channel = -1;
|
||||||
ct->ecm_state = ECM_INIT;
|
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
|
// Note: we always test season first, though it will only be set
|
||||||
// if configured
|
// if configured
|
||||||
if(dae->dae_serieslink)
|
if(dae->dae_serieslink) {
|
||||||
if (!e->serieslink || dae->dae_serieslink != e->serieslink) return 0;
|
if (!e->serieslink || dae->dae_serieslink != e->serieslink) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if(dae->dae_season)
|
if(dae->dae_season)
|
||||||
if (!e->episode->season || dae->dae_season != e->episode->season) return 0;
|
if (!e->episode->season || dae->dae_season != e->episode->season) return 0;
|
||||||
if(dae->dae_brand)
|
if(dae->dae_brand)
|
||||||
|
|
Loading…
Add table
Reference in a new issue