Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
capmt: fix some wrong assumptions - improve support for recent OSCAM
  • Loading branch information
perexg committed Nov 25, 2015
1 parent d2b08ca commit 2ddbb07
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 55 deletions.
131 changes: 76 additions & 55 deletions src/descrambler/capmt.c
Expand Up @@ -84,6 +84,8 @@ typedef struct dmx_filter {
#define DVBAPI_SERVER_INFO 0xFFFF0002
#define DVBAPI_ECM_INFO 0xFFFF0003

#define PID_UNUSED (0xffff)
#define PID_BLOCKED (0xfffe)

// ca_pmt_list_management values:
#define CAPMT_LIST_MORE 0x00 // append a 'MORE' CAPMT object the list and start receiving the next object
Expand Down Expand Up @@ -137,7 +139,7 @@ LIST_HEAD(capmt_caid_ecm_list, capmt_caid_ecm);
* ECM descriptor
*/
typedef struct ca_info {
uint16_t seq; // sequence / service id number
uint16_t pids[MAX_PIDS]; // elementary stream pids (was: sequence / service id number)
} ca_info_t;

/**
Expand Down Expand Up @@ -274,9 +276,6 @@ typedef struct capmt {
int capmt_running;
int capmt_reconfigure;

/* next sequence number */
uint16_t capmt_seq;

/* runtime status */
tvhpoll_t *capmt_poll;
th_pipe_t capmt_pipe;
Expand Down Expand Up @@ -359,9 +358,11 @@ capmt_pid_add(capmt_t *capmt, int adapter, int pid, mpegts_service_t *s)
t = &ca->ca_pids[i];
if (t->pid == pid && t->ecm == ecm) {
t->pid_refs++;
tvhtrace("capmt", "%s: adding pid %d adapter %d - reusing (%d)",
capmt_name(capmt), pid, adapter, t->pid_refs);
return;
}
if (t->pid == 0)
if (t->pid == PID_UNUSED)
o = t;
}
if (o) {
Expand All @@ -372,6 +373,7 @@ capmt_pid_add(capmt_t *capmt, int adapter, int pid, mpegts_service_t *s)
o->ecm = ecm;
mmi = ca->ca_tuner ? LIST_FIRST(&ca->ca_tuner->mi_mux_active) : NULL;
mux = mmi ? mmi->mmi_mux : NULL;
tvhtrace("capmt", "%s: adding pid %d adapter %d, tuner %p, mmi %p, mux %p", capmt_name(capmt), pid, adapter, ca->ca_tuner, mmi, mux);
if (mux) {
pthread_mutex_unlock(&capmt->capmt_mutex);
descrambler_open_pid(mux, o,
Expand Down Expand Up @@ -407,7 +409,7 @@ capmt_pid_remove(capmt_t *capmt, int adapter, int pid, uint32_t flags)
return;
mmi = ca->ca_tuner ? LIST_FIRST(&ca->ca_tuner->mi_mux_active) : NULL;
mux = mmi ? mmi->mmi_mux : NULL;
o->pid = -1; /* block for new registrations */
o->pid = PID_BLOCKED;
o->pid_refs = 0;
if (o->ecm)
pid = DESCRAMBLER_ECM_PID(pid);
Expand All @@ -417,7 +419,7 @@ capmt_pid_remove(capmt_t *capmt, int adapter, int pid, uint32_t flags)
descrambler_close_pid(mux, o, pid);
pthread_mutex_lock(&capmt->capmt_mutex);
}
o->pid = 0;
o->pid = PID_UNUSED;
}

static void
Expand All @@ -430,13 +432,14 @@ capmt_pid_flush_adapter(capmt_t *capmt, int adapter)
capmt_opaque_t *o;
int pid, i;

tvhtrace("capmt", "%s: pid flush for adapter %d", capmt_name(capmt), adapter);
ca = &capmt->capmt_adapters[adapter];
tuner = capmt->capmt_adapters[adapter].ca_tuner;
if (tuner == NULL) {
/* clean all pids (to be sure) */
for (i = 0; i < MAX_PIDS; i++) {
o = &ca->ca_pids[i];
o->pid = 0;
o->pid = PID_UNUSED;
o->pid_refs = 0;
}
return;
Expand All @@ -446,14 +449,14 @@ capmt_pid_flush_adapter(capmt_t *capmt, int adapter)
for (i = 0; i < MAX_PIDS; i++) {
o = &ca->ca_pids[i];
if ((pid = o->pid) > 0) {
o->pid = -1; /* block for new registrations */
o->pid = PID_BLOCKED;
o->pid_refs = 0;
if (mux) {
pthread_mutex_unlock(&capmt->capmt_mutex);
descrambler_close_pid(mux, &ca->ca_pids[i], pid);
pthread_mutex_lock(&capmt->capmt_mutex);
}
o->pid = 0;
o->pid = PID_UNUSED;
}
}
}
Expand Down Expand Up @@ -538,6 +541,7 @@ capmt_socket_close(capmt_t *capmt, int sock_idx)
{
int fd = capmt->capmt_sock[sock_idx];
lock_assert(&capmt->capmt_mutex);
tvhtrace("capmt", "%s: socket close %d", capmt_name(capmt), fd);
if (fd < 0)
return;
capmt_poll_rem(capmt, fd);
Expand Down Expand Up @@ -1050,12 +1054,15 @@ capmt_ecm_reset(th_descrambler_t *th)
}

static void
capmt_process_key(capmt_t *capmt, uint8_t adapter, uint16_t seq,
capmt_process_key(capmt_t *capmt, uint8_t adapter, uint32_t index,
int type, const uint8_t *even, const uint8_t *odd,
int ok)
{
mpegts_service_t *t;
capmt_service_t *ct;
ca_info_t *cai;
uint16_t *pids;
int i;

pthread_mutex_lock(&capmt->capmt_mutex);
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
Expand All @@ -1071,12 +1078,17 @@ capmt_process_key(capmt_t *capmt, uint8_t adapter, uint16_t seq,
continue;
}

if (seq != ct->ct_seq)
continue;
if (adapter != ct->ct_adapter)
continue;

descrambler_keys((th_descrambler_t *)ct, type, even, odd);
cai = &capmt->capmt_adapters[adapter].ca_info[index];
pids = cai->pids;

for (i = 0; i < MAX_PIDS; i++)
if (pids[i]) break;

if (i < MAX_PIDS)
descrambler_keys((th_descrambler_t *)ct, type, even, odd);
}
pthread_mutex_unlock(&capmt->capmt_mutex);
}
Expand Down Expand Up @@ -1192,32 +1204,38 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)

if (cmd == CA_SET_PID) {

uint32_t seq = sbuf_peek_u32(sb, offset + 4);
uint32_t pid = sbuf_peek_u32(sb, offset + 4);
int32_t index = sbuf_peek_s32(sb, offset + 8);
int i, j;
ca_info_t *cai;

tvhlog(LOG_DEBUG, "capmt", "%s: CA_SET_PID adapter %d index %d seq 0x%04x", capmt_name(capmt), adapter, index, seq);
tvhlog(LOG_DEBUG, "capmt", "%s: CA_SET_PID adapter %d index %d pid %d (0x%04x)", capmt_name(capmt), adapter, index, pid, pid);
if (adapter < MAX_CA && index >= 0 && index < MAX_INDEX) {
cai = &capmt->capmt_adapters[adapter].ca_info[index];
memset(cai, 0, sizeof(*cai));
cai->seq = seq;
for (i = 0, j = -1; i < MAX_PIDS; i++) {
if (cai->pids[i] == pid)
break;
if (j < 0 && cai->pids[i] == 0)
j = i;
}
if (i >= MAX_PIDS && j >= 0)
cai->pids[j] = pid;
} else if (index < 0) {
for (index = 0; index < MAX_INDEX; index++) {
cai = &capmt->capmt_adapters[adapter].ca_info[index];
if (cai->seq == seq) {
memset(cai, 0, sizeof(*cai));
break;
}
for (i = 0; i < MAX_PIDS; i++)
if (cai->pids[i] == pid)
cai->pids[i] = 0;
}
} else
} else {
tvhlog(LOG_ERR, "capmt", "%s: Invalid index %d in CA_SET_PID (%d) for adapter %d", capmt_name(capmt), index, MAX_INDEX, adapter);
}

} else if (cmd == CA_SET_DESCR) {

int32_t index = sbuf_peek_s32(sb, offset + 4);
int32_t parity = sbuf_peek_s32(sb, offset + 8);
uint8_t *cw = sbuf_peek (sb, offset + 12);
ca_info_t *cai;

tvhlog(LOG_DEBUG, "capmt", "%s, CA_SET_DESCR adapter %d par %d idx %d %02x%02x%02x%02x%02x%02x%02x%02x",
capmt_name(capmt), adapter, parity, index,
Expand All @@ -1226,11 +1244,10 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
return;
if (adapter >= MAX_CA || index >= MAX_INDEX)
return;
cai = &capmt->capmt_adapters[adapter].ca_info[index];
if (parity == 0) {
capmt_process_key(capmt, adapter, cai->seq, DESCRAMBLER_DES, cw, empty, 1);
capmt_process_key(capmt, adapter, index, DESCRAMBLER_DES, cw, empty, 1);
} else if (parity == 1) {
capmt_process_key(capmt, adapter, cai->seq, DESCRAMBLER_DES, empty, cw, 1);
capmt_process_key(capmt, adapter, index, DESCRAMBLER_DES, empty, cw, 1);
} else
tvhlog(LOG_ERR, "capmt", "%s: Invalid parity %d in CA_SET_DESCR for adapter%d", capmt_name(capmt), parity, adapter);

Expand All @@ -1239,7 +1256,6 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
int32_t index = sbuf_peek_s32(sb, offset + 4);
int32_t parity = sbuf_peek_s32(sb, offset + 8);
uint8_t *cw = sbuf_peek (sb, offset + 12);
ca_info_t *cai;

tvhlog(LOG_DEBUG, "capmt", "%s: CA_SET_DESCR_AES adapter %d par %d idx %d "
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
Expand All @@ -1250,11 +1266,10 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
return;
if (adapter >= MAX_CA || index >= MAX_INDEX)
return;
cai = &capmt->capmt_adapters[adapter].ca_info[index];
if (parity == 0) {
capmt_process_key(capmt, adapter, cai->seq, DESCRAMBLER_AES, cw, empty, 1);
capmt_process_key(capmt, adapter, index, DESCRAMBLER_AES, cw, empty, 1);
} else if (parity == 1) {
capmt_process_key(capmt, adapter, cai->seq, DESCRAMBLER_AES, empty, cw, 1);
capmt_process_key(capmt, adapter, index, DESCRAMBLER_AES, empty, cw, 1);
} else
tvhlog(LOG_ERR, "capmt", "%s: Invalid parity %d in CA_SET_DESCR_AES for adapter%d", capmt_name(capmt), parity, adapter);

Expand Down Expand Up @@ -1606,15 +1621,25 @@ static void *
capmt_thread(void *aux)
{
capmt_t *capmt = aux;
capmt_adapter_t *ca;
capmt_opaque_t *t;
struct timespec ts;
int d, i, fatal;
int d, i, j, fatal;

tvhlog(LOG_INFO, "capmt", "%s active", capmt_name(capmt));

while (capmt->capmt_running) {
fatal = 0;
for (i = 0; i < MAX_CA; i++)
capmt->capmt_adapters[i].ca_sock = -1;
for (i = 0; i < MAX_CA; i++) {
ca = &capmt->capmt_adapters[i];
ca->ca_sock = -1;
memset(&ca->ca_info, 0, sizeof(ca->ca_info));
for (j = 0; j < MAX_PIDS; j++) {
t = &ca->ca_pids[j];
t->pid = PID_UNUSED;
t->pid_refs = 0;
}
}
for (i = 0; i < MAX_SOCKETS; i++) {
capmt->sids[i] = 0;
capmt->adps[i] = -1;
Expand Down Expand Up @@ -1694,15 +1719,9 @@ capmt_thread(void *aux)
#endif
}

caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_DISCONNECTED);

pthread_mutex_lock(&capmt->capmt_mutex);
if (capmt->capmt_reconfigure) {
capmt->capmt_reconfigure = 0;
capmt->capmt_running = 1;
pthread_mutex_unlock(&capmt->capmt_mutex);
continue;
}

caclient_set_status((caclient_t *)capmt, CACLIENT_STATUS_DISCONNECTED);

/* close opened sockets */
for (i = 0; i < MAX_SOCKETS; i++)
Expand All @@ -1712,7 +1731,13 @@ capmt_thread(void *aux)
for (i = 0; i < MAX_CA; i++) {
if (capmt->capmt_adapters[i].ca_sock >= 0)
close(capmt->capmt_adapters[i].ca_sock);
capmt->capmt_adapters[i].ca_tuner = NULL;
}

if (capmt->capmt_reconfigure) {
capmt->capmt_reconfigure = 0;
capmt->capmt_running = 1;
pthread_mutex_unlock(&capmt->capmt_mutex);
continue;
}

if (!capmt->capmt_running) {
Expand Down Expand Up @@ -2083,26 +2108,18 @@ capmt_service_start(caclient_t *cac, service_t *s)
}
}

tvhlog(LOG_INFO, "capmt",
"%s: Starting CAPMT server for service \"%s\" on adapter %d seq 0x%04x",
capmt_name(capmt), t->s_dvb_svcname, tuner, capmt->capmt_seq);

capmt->capmt_adapters[tuner].ca_tuner = t->s_dvb_active_input;

/* create new capmt service */
ct = calloc(1, sizeof(capmt_service_t));
ct->ct_capmt = capmt;
ct->ct_seq = capmt->capmt_seq;
ct->ct_seq = 0;
ct->ct_adapter = tuner;

/* update the sequence (oscam calls it pid?) to a safe value */
capmt->capmt_seq++;
capmt->capmt_seq &= 0x1fff;
if (capmt->capmt_seq == 8191 || capmt->capmt_seq == 0)
capmt->capmt_seq = 1;

TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
caid_t *c;
if (ct->ct_seq == 0 && SCT_ISAV(st->es_type))
ct->ct_seq = st->es_pid;
if (t->s_dvb_prefcapid_lock == PREFCAPID_FORCE &&
t->s_dvb_prefcapid != st->es_pid)
continue;
Expand All @@ -2126,6 +2143,11 @@ capmt_service_start(caclient_t *cac, service_t *s)
}
}

tvhlog(LOG_INFO, "capmt",
"%s: Starting CAPMT server for service \"%s\" on adapter %d seq 0x%04x",
capmt_name(capmt), t->s_dvb_svcname, tuner, ct->ct_seq);


td = (th_descrambler_t *)ct;
if (capmt->capmt_oscam == CAPMT_OSCAM_TCP ||
capmt->capmt_oscam == CAPMT_OSCAM_NET_PROTO) {
Expand Down Expand Up @@ -2270,7 +2292,6 @@ caclient_t *capmt_create(void)

pthread_mutex_init(&capmt->capmt_mutex, NULL);
pthread_cond_init(&capmt->capmt_cond, NULL);
capmt->capmt_seq = 1;
TAILQ_INIT(&capmt->capmt_writeq);
tvh_pipe(O_NONBLOCK, &capmt->capmt_pipe);

Expand Down
2 changes: 2 additions & 0 deletions src/tvheadend.h
Expand Up @@ -254,6 +254,8 @@ typedef enum {
(t) == SCT_AAC || (t) == SCT_MP4A || \
(t) == SCT_EAC3 || (t) == SCT_VORBIS)

#define SCT_ISAV(t) (SCT_ISVIDEO(t) || SCT_ISAUDIO(t))

#define SCT_ISSUBTITLE(t) ((t) == SCT_TEXTSUB || (t) == SCT_DVBSUB)

/*
Expand Down

0 comments on commit 2ddbb07

Please sign in to comment.