#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
* 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;
/**
int capmt_running;
int capmt_reconfigure;
- /* next sequence number */
- uint16_t capmt_seq;
-
/* runtime status */
tvhpoll_t *capmt_poll;
th_pipe_t capmt_pipe;
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) {
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,
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);
descrambler_close_pid(mux, o, pid);
pthread_mutex_lock(&capmt->capmt_mutex);
}
- o->pid = 0;
+ o->pid = PID_UNUSED;
}
static void
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;
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;
}
}
}
{
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);
}
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) {
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);
}
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,
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);
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",
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);
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;
#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++)
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) {
}
}
- 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;
}
}
+ 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) {
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);