descrambler: Merge the common descrambler code - tvhcsa_descramble() calls

This commit is contained in:
Jaroslav Kysela 2014-05-29 16:08:02 +02:00
parent 2ca5d1e215
commit 7425d43a23
8 changed files with 99 additions and 166 deletions

View file

@ -125,7 +125,6 @@ SRCS = src/version.c \
src/lang_str.c \
src/imagecache.c \
src/tvhtime.c \
src/descrambler/descrambler.c \
src/service_mapper.c \
src/input.c \
src/httpc.c \
@ -193,6 +192,7 @@ SRCS += src/muxer.c \
# MPEGTS core
SRCS-$(CONFIG_MPEGTS) += \
src/descrambler/descrambler.c \
src/input/mpegts.c \
src/input/mpegts/mpegts_input.c \
src/input/mpegts/mpegts_network.c \

View file

@ -20,11 +20,11 @@
#define __TVH_DESCRAMBLER_H__
#include <stdint.h>
#include "queue.h"
struct service;
struct elementary_stream;
struct tvhcsa;
/**
* Descrambler superclass
@ -34,12 +34,18 @@ struct elementary_stream;
typedef struct th_descrambler {
LIST_ENTRY(th_descrambler) td_service_link;
void (*td_table)(struct th_descrambler *d, struct service *t,
struct elementary_stream *st,
const uint8_t *section, int section_len);
enum {
DS_UNKNOWN,
DS_RESOLVED,
DS_FORBIDDEN,
DS_IDLE
} td_keystate;
int (*td_descramble)(struct th_descrambler *d, struct service *t,
struct elementary_stream *st, const uint8_t *tsb);
struct service *td_service;
struct tvhcsa *td_csa;
void (*td_table)(struct th_descrambler *d, struct elementary_stream *st,
const uint8_t *section, int section_len);
void (*td_stop)(struct th_descrambler *d);
@ -79,9 +85,12 @@ LIST_HEAD(caid_list, caid);
void descrambler_init ( void );
void descrambler_done ( void );
void descrambler_service_start ( struct service *t );
const char *descrambler_caid2name(uint16_t caid);
uint16_t descrambler_name2caid(const char *str);
card_type_t detect_card_type(const uint16_t caid);
int descrambler_descramble ( th_descrambler_t *td,
struct elementary_stream *st,
const uint8_t *tsb );
const char *descrambler_caid2name( uint16_t caid );
uint16_t descrambler_name2caid ( const char *str );
card_type_t detect_card_type ( const uint16_t caid );
#endif /* __TVH_DESCRAMBLER_H__ */

View file

@ -38,6 +38,7 @@
#include "tvheadend.h"
#include "input.h"
#include "service.h"
#include "tcp.h"
#include "capmt.h"
@ -148,9 +149,7 @@ typedef struct capmt_caid_ecm {
*
*/
typedef struct capmt_service {
th_descrambler_t ct_head;
mpegts_service_t *ct_service;
th_descrambler_t;
struct capmt *ct_capmt;
@ -159,15 +158,6 @@ typedef struct capmt_service {
/* list of used ca-systems with ids and last ecm */
struct capmt_caid_ecm_list ct_caid_ecm;
/**
* Status of the key(s) in ct_keys
*/
enum {
CT_UNKNOWN,
CT_RESOLVED,
CT_FORBIDDEN
} ct_keystate;
tvhcsa_t ct_csa;
/* current sequence number */
@ -336,11 +326,13 @@ capmt_send_msg(capmt_t *capmt, int sid, const uint8_t *buf, size_t len)
static void
capmt_send_stop(capmt_service_t *t)
{
mpegts_service_t *s = (mpegts_service_t *)t->td_service;
if (t->ct_capmt->capmt_oscam) {
int i;
// searching for socket to close
for (i = 0; i < MAX_SOCKETS; i++)
if (t->ct_capmt->sids[i] == t->ct_service->s_dvb_service_id)
if (t->ct_capmt->sids[i] == s->s_dvb_service_id)
break;
if (i == MAX_SOCKETS) {
@ -362,7 +354,7 @@ capmt_send_stop(capmt_service_t *t)
capmt_header_t head = {
.capmt_indicator = { 0x9F, 0x80, 0x32, 0x82, 0x00, 0x00 },
.capmt_list_management = CAPMT_LIST_ONLY,
.program_number = t->ct_service->s_dvb_service_id,
.program_number = s->s_dvb_service_id,
.version_number = 0,
.current_next_indicator = 0,
.program_info_length = 0,
@ -377,13 +369,13 @@ capmt_send_stop(capmt_service_t *t)
pos += sizeof(end);
buf[4] = ((pos - 6) >> 8);
buf[5] = ((pos - 6) & 0xFF);
buf[7] = t->ct_service->s_dvb_service_id >> 8;
buf[8] = t->ct_service->s_dvb_service_id & 0xFF;
buf[7] = s->s_dvb_service_id >> 8;
buf[8] = s->s_dvb_service_id & 0xFF;
buf[9] = 1;
buf[10] = ((pos - 5 - 12) & 0xF00) >> 8;
buf[11] = ((pos - 5 - 12) & 0xFF);
capmt_send_msg(t->ct_capmt, t->ct_service->s_dvb_service_id, buf, pos);
capmt_send_msg(t->ct_capmt, s->s_dvb_service_id, buf, pos);
}
}
@ -501,8 +493,8 @@ handle_ca0(capmt_t* capmt) {
// we are not connected any more - set services as unavailable
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
if (ct->ct_keystate != CT_FORBIDDEN) {
ct->ct_keystate = CT_FORBIDDEN;
if (ct->td_keystate != DS_FORBIDDEN) {
ct->td_keystate = DS_FORBIDDEN;
}
}
@ -581,13 +573,13 @@ handle_ca0(capmt_t* capmt) {
// processing key
if (process_key) {
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
t = ct->ct_service;
t = (mpegts_service_t *)ct->td_service;
if (!capmt->capmt_oscam && ret < bufsize) {
if(ct->ct_keystate != CT_FORBIDDEN) {
if(ct->td_keystate != DS_FORBIDDEN) {
tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_dvb_svcname);
ct->ct_keystate = CT_FORBIDDEN;
ct->td_keystate = DS_FORBIDDEN;
}
continue;
@ -601,10 +593,10 @@ handle_ca0(capmt_t* capmt) {
if (memcmp(odd, invalid, 8))
tvhcsa_set_key_odd(&ct->ct_csa, odd);
if(ct->ct_keystate != CT_RESOLVED)
if(ct->td_keystate != DS_RESOLVED)
tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_dvb_svcname);
ct->ct_keystate = CT_RESOLVED;
ct->td_keystate = DS_RESOLVED;
}
}
}
@ -738,19 +730,19 @@ capmt_thread(void *aux)
*
*/
static void
capmt_table_input(struct th_descrambler *td, struct service *s,
capmt_table_input(struct th_descrambler *td,
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;
mpegts_service_t *t = (mpegts_service_t*)s;
mpegts_service_t *t = (mpegts_service_t*)td->td_service;
linuxdvb_frontend_t *lfe;
int total_caids = 0, current_caid = 0;
/* Validate */
if (!idnode_is_instance(&s->s_id, &mpegts_service_class))
if (!idnode_is_instance(&td->td_service->s_id, &mpegts_service_class))
return;
if (!t->s_dvb_active_input) return;
lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
@ -805,7 +797,7 @@ capmt_table_input(struct th_descrambler *td, struct service *s,
if(!capmt->capmt_oscam && capmt->capmt_sock[0] == 0) {
/* New key, but we are not connected (anymore), can not descramble */
ct->ct_keystate = CT_UNKNOWN;
ct->td_keystate = DS_UNKNOWN;
break;
}
@ -833,7 +825,7 @@ static void
capmt_send_request(capmt_service_t *ct, int es_pid, int lm)
{
capmt_t *capmt = ct->ct_capmt;
mpegts_service_t *t = ct->ct_service;
mpegts_service_t *t = (mpegts_service_t *)ct->td_service;
uint16_t sid = t->s_dvb_service_id;
uint16_t ecmpid = es_pid;
uint16_t transponder = t->s_dvb_mux->mm_tsid;
@ -946,7 +938,7 @@ capmt_send_request(capmt_service_t *ct, int es_pid, int lm)
buf[8] = sid & 0xFF;
if(ct->ct_keystate != CT_RESOLVED)
if(ct->td_keystate != DS_RESOLVED)
tvhlog(LOG_DEBUG, "capmt",
"Trying to obtain key for service \"%s\"",t->s_dvb_svcname);
@ -967,7 +959,7 @@ capmt_enumerate_services(capmt_t *capmt, int es_pid, int force)
capmt_service_t *ct;
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
all_srv_count++;
if (ct->ct_keystate == CT_RESOLVED)
if (ct->td_keystate == DS_RESOLVED)
res_srv_count++;
}
@ -991,28 +983,6 @@ capmt_enumerate_services(capmt_t *capmt, int es_pid, int force)
}
}
/**
*
*/
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;
if(ct->ct_keystate == CT_FORBIDDEN)
return 1;
if(ct->ct_keystate != CT_RESOLVED)
return -1;
tvhcsa_descramble(&ct->ct_csa, (mpegts_service_t*)t, st, tsb, 0);
return 0;
}
/**
* Check if our CAID's matches, and if so, link
*
@ -1045,7 +1015,7 @@ capmt_service_start(service_t *s)
TAILQ_FOREACH(capmt, &capmts, capmt_link) {
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
/* skip, if we already have this service */
if (ct->ct_service == t)
if (ct->td_service == (service_t *)t)
return;
}
}
@ -1063,9 +1033,7 @@ capmt_service_start(service_t *s)
/* create new capmt service */
ct = calloc(1, sizeof(capmt_service_t));
tvhcsa_init(&ct->ct_csa);
ct->ct_capmt = capmt;
ct->ct_service = t;
ct->ct_seq = capmt->capmt_seq++;
@ -1092,10 +1060,11 @@ capmt_service_start(service_t *s)
}
}
td = &ct->ct_head;
td = (th_descrambler_t *)ct;
tvhcsa_init(td->td_csa = &ct->ct_csa);
td->td_service = s;
td->td_stop = capmt_service_destroy;
td->td_table = capmt_table_input;
td->td_descramble = capmt_descramble;
LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
LIST_INSERT_HEAD(&capmt->capmt_services, ct, ct_link);

View file

@ -124,9 +124,7 @@ typedef struct ecm_pid {
*
*/
typedef struct cwc_service {
th_descrambler_t cs_head;
mpegts_service_t *cs_service;
th_descrambler_t;
struct cwc *cs_cwc;
@ -143,19 +141,6 @@ typedef struct cwc_service {
ECM_RESET
} ecm_state;
/**
* Status of the key(s) in cs_keys
*/
enum {
CS_UNKNOWN,
CS_RESOLVED,
CS_FORBIDDEN,
CS_IDLE
} cs_keystate;
uint8_t cs_cw[16];
int cs_pending_cw_update;
tvhcsa_t cs_csa;
LIST_HEAD(, ecm_pid) cs_pids;
@ -696,7 +681,7 @@ static void
handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
int len, int seq)
{
mpegts_service_t *t = ct->cs_service;
mpegts_service_t *t = (mpegts_service_t *)ct->td_service;
ecm_pid_t *ep, *epn;
cwc_service_t *ct2;
cwc_t *cwc2;
@ -714,7 +699,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
if (es->es_nok < 3)
es->es_nok++;
if(ct->cs_keystate == CS_FORBIDDEN)
if(ct->td_keystate == DS_FORBIDDEN)
return; // We already know it's bad
if (es->es_nok > 2) {
@ -727,8 +712,8 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
TAILQ_FOREACH(cwc2, &cwcs, cwc_link) {
LIST_FOREACH(ct2, &cwc2->cwc_services, cs_link) {
if (ct != ct2 && ct2->cs_service == t &&
ct2->cs_keystate == CS_RESOLVED) {
if (ct != ct2 && ct2->td_service == (service_t *)t &&
ct2->td_keystate == DS_RESOLVED) {
tvhlog(LOG_DEBUG, "cwc",
"NOK from %s:%i: Already has a key for service \"%s\", from %s:%i",
ct->cs_cwc->cwc_hostname, ct->cs_cwc->cwc_port,
@ -759,7 +744,7 @@ forbid:
"Req delay: %"PRId64" ms)",
t->s_dvb_svcname, seq, delay);
ct->cs_keystate = CS_FORBIDDEN;
ct->td_keystate = DS_FORBIDDEN;
ct->ecm_state = ECM_RESET;
return;
@ -790,9 +775,9 @@ forbid:
TAILQ_FOREACH(cwc2, &cwcs, cwc_link) {
LIST_FOREACH(ct2, &cwc2->cwc_services, cs_link) {
if (ct != ct2 && ct2->cs_service == t &&
ct2->cs_keystate == CS_RESOLVED) {
ct->cs_keystate = CS_IDLE;
if (ct != ct2 && ct2->td_service == (service_t *)t &&
ct2->td_keystate == DS_RESOLVED) {
ct->td_keystate = DS_IDLE;
tvhlog(LOG_DEBUG, "cwc",
"Already has a key for service \"%s\", from %s:%i",
t->s_dvb_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
@ -801,15 +786,23 @@ forbid:
}
}
if(ct->cs_keystate != CS_RESOLVED)
if(ct->td_keystate != DS_RESOLVED)
tvhlog(LOG_DEBUG, "cwc",
"Obtained key for service \"%s\" in %"PRId64" ms, from %s:%i",
t->s_dvb_svcname, delay, ct->cs_cwc->cwc_hostname,
ct->cs_cwc->cwc_port);
ct->cs_keystate = CS_RESOLVED;
memcpy(ct->cs_cw, msg + 3, 16);
ct->cs_pending_cw_update = 1;
ct->td_keystate = DS_RESOLVED;
for (i = 3; i < 3 + 8; i++)
if (msg[i]) {
tvhcsa_set_key_even(&ct->cs_csa, msg + 3);
break;
}
for (i = 3 + 8; i < 3 + 8 + 8; i++)
if (msg[i]) {
tvhcsa_set_key_odd(&ct->cs_csa, msg + 3 + 8);
break;
}
ep = LIST_FIRST(&ct->cs_pids);
while(ep != NULL) {
@ -1210,9 +1203,9 @@ cwc_thread(void *aux)
cwc->cwc_hostname, cwc->cwc_port);
while((ct = LIST_FIRST(&cwc->cwc_services)) != NULL) {
t = ct->cs_service;
t = (mpegts_service_t *)ct->td_service;
pthread_mutex_lock(&t->s_stream_mutex);
cwc_service_destroy(&ct->cs_head);
cwc_service_destroy((th_descrambler_t *)&ct);
pthread_mutex_unlock(&t->s_stream_mutex);
}
@ -1601,11 +1594,11 @@ cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int mlen
* t->s_streaming_mutex is held
*/
static void
cwc_table_input(struct th_descrambler *td, service_t *s,
cwc_table_input(struct th_descrambler *td,
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;
mpegts_service_t *t = (mpegts_service_t*)td->td_service;
uint16_t sid = t->s_dvb_service_id;
cwc_t *cwc = ct->cs_cwc;
int channel;
@ -1615,7 +1608,7 @@ cwc_table_input(struct th_descrambler *td, service_t *s,
char chaninfo[32];
caid_t *c;
if (ct->cs_keystate == CS_IDLE)
if (ct->td_keystate == DS_IDLE)
return;
if(len > 4096)
@ -1708,7 +1701,7 @@ cwc_table_input(struct th_descrambler *td, service_t *s,
if(cwc->cwc_fd == -1) {
// New key, but we are not connected (anymore), can not descramble
ct->cs_keystate = CS_UNKNOWN;
ct->td_keystate = DS_UNKNOWN;
break;
}
es->es_channel = channel;
@ -1897,56 +1890,6 @@ cwc_emm_bulcrypt(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len)
cwc_send_msg(cwc, data, len, 0, 1, 0, 0);
}
/**
*
*/
static void
update_keys(cwc_service_t *ct)
{
int i;
ct->cs_pending_cw_update = 0;
for(i = 0; i < 8; i++)
if(ct->cs_cw[i]) {
tvhcsa_set_key_even(&ct->cs_csa, ct->cs_cw);
break;
}
for(i = 0; i < 8; i++)
if(ct->cs_cw[8 + i]) {
tvhcsa_set_key_odd(&ct->cs_csa, ct->cs_cw+8);
break;
}
}
/**
*
*/
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;
if(ct->cs_keystate == CS_FORBIDDEN)
return 1;
if(ct->cs_keystate != CS_RESOLVED)
return -1;
if(ct->cs_csa.csa_fill == 0 && ct->cs_pending_cw_update)
update_keys(ct);
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;
}
/**
* cwc_mutex is held
* s_stream_mutex is held
@ -2012,7 +1955,7 @@ cwc_service_start(service_t *t)
pthread_mutex_lock(&cwc_mutex);
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
LIST_FOREACH(ct, &cwc->cwc_services, cs_link) {
if (ct->cs_service == (mpegts_service_t*)t && ct->cs_cwc == cwc)
if (ct->td_service == t && ct->cs_cwc == cwc)
break;
}
LIST_FOREACH(pcard,&cwc->cwc_cards, cs_card) {
@ -2029,16 +1972,15 @@ cwc_service_start(service_t *t)
mpegts_table_register_caid(((mpegts_service_t *)t)->s_dvb_mux, pcard->cwc_caid);
ct = calloc(1, sizeof(cwc_service_t));
tvhcsa_init(&ct->cs_csa);
ct->cs_cwc = cwc;
ct->cs_service = (mpegts_service_t*)t;
ct->cs_channel = -1;
ct->ecm_state = ECM_INIT;
td = &ct->cs_head;
td->td_stop = cwc_service_destroy;
td->td_table = cwc_table_input;
td->td_descramble = cwc_descramble;
td = (th_descrambler_t *)ct;
tvhcsa_init(td->td_csa = &ct->cs_csa);
td->td_service = t;
td->td_stop = cwc_service_destroy;
td->td_table = cwc_table_input;
LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
LIST_INSERT_HEAD(&cwc->cwc_services, ct, cs_link);

View file

@ -21,6 +21,7 @@
#include "capmt.h"
#include "ffdecsa/FFdecsa.h"
#include "service.h"
#include "tvhcsa.h"
static struct strtab caidnametab[] = {
{ "Seca", 0x0100 },
@ -133,6 +134,21 @@ descrambler_service_start ( service_t *t )
#endif
}
int
descrambler_descramble ( th_descrambler_t *td,
struct elementary_stream *st,
const uint8_t *tsb )
{
if (td->td_keystate == DS_FORBIDDEN)
return 1;
if (td->td_keystate != DS_RESOLVED)
return -1;
tvhcsa_descramble(td->td_csa,
(struct mpegts_service *)td->td_service,
st, tsb);
return 0;
}
// TODO: might actually put const char* into caid_t
const char *
descrambler_caid2name(uint16_t caid)

View file

@ -27,7 +27,7 @@
void
tvhcsa_descramble
( tvhcsa_t *csa, struct mpegts_service *s, struct elementary_stream *st,
const uint8_t *tsb, int cw_update_pending )
const uint8_t *tsb )
{
#if ENABLE_DVBCSA
uint8_t *pkt;
@ -134,9 +134,6 @@ tvhcsa_descramble
if(r > 0)
memmove(csa->csa_tsbcluster, t0, r * 188);
csa->csa_fill = r;
if(cw_update_pending && r > 0)
continue;
} else {
csa->csa_fill = 0;
}

View file

@ -76,7 +76,7 @@ typedef struct tvhcsa
void
tvhcsa_descramble
( tvhcsa_t *csa, struct mpegts_service *s, struct elementary_stream *st,
const uint8_t *tsb, int cw_update_pending );
const uint8_t *tsb );
void tvhcsa_init ( tvhcsa_t *csa );
void tvhcsa_destroy ( tvhcsa_t *csa );

View file

@ -56,7 +56,7 @@ got_ca_section(const uint8_t *data, size_t len, void *opaque)
mpegts_service_t *t = (mpegts_service_t*)st->es_service;
LIST_FOREACH(td, &t->s_descramblers, td_service_link)
td->td_table(td, (service_t*)t, st, data, len);
td->td_table(td, st, data, len);
}
/**
@ -249,7 +249,7 @@ ts_recv_packet1
LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
n++;
r = td->td_descramble(td, (service_t*)t, st, tsb);
r = descrambler_descramble(td, st, tsb);
if(r == 0) {
pthread_mutex_unlock(&t->s_stream_mutex);
return 1;