src/lang_str.c \
src/imagecache.c \
src/tvhtime.c \
- src/descrambler/descrambler.c \
src/service_mapper.c \
src/input.c \
src/httpc.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 \
#define __TVH_DESCRAMBLER_H__
#include <stdint.h>
-
#include "queue.h"
struct service;
struct elementary_stream;
+struct tvhcsa;
/**
* Descrambler superclass
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);
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__ */
#include "tvheadend.h"
#include "input.h"
+#include "service.h"
#include "tcp.h"
#include "capmt.h"
*
*/
typedef struct capmt_service {
- th_descrambler_t ct_head;
-
- mpegts_service_t *ct_service;
+ th_descrambler_t;
struct capmt *ct_capmt;
/* 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 */
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) {
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,
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);
}
}
// 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;
}
}
// 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;
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;
}
}
}
*
*/
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;
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;
}
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;
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);
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++;
}
}
}
-
-/**
- *
- */
-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
*
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;
}
}
/* 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++;
}
}
- 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);
*
*/
typedef struct cwc_service {
- th_descrambler_t cs_head;
-
- mpegts_service_t *cs_service;
+ th_descrambler_t;
struct cwc *cs_cwc;
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;
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;
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) {
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,
"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;
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);
}
}
- 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) {
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);
}
* 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;
char chaninfo[32];
caid_t *c;
- if (ct->cs_keystate == CS_IDLE)
+ if (ct->td_keystate == DS_IDLE)
return;
if(len > 4096)
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;
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
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) {
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);
#include "capmt.h"
#include "ffdecsa/FFdecsa.h"
#include "service.h"
+#include "tvhcsa.h"
static struct strtab caidnametab[] = {
{ "Seca", 0x0100 },
#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)
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;
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;
}
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 );
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);
}
/**
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;