From: Jaroslav Kysela Date: Wed, 25 Nov 2015 15:39:51 +0000 (+0100) Subject: capmt: fix some wrong assumptions - improve support for recent OSCAM X-Git-Tag: v4.2.1~1465 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2ddbb073c2215ff4b8036e000253496a79ef076f;p=thirdparty%2Ftvheadend.git capmt: fix some wrong assumptions - improve support for recent OSCAM --- diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 67aab3cbe..97876a27e 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -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 @@ -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; /** @@ -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; @@ -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) { @@ -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, @@ -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); @@ -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 @@ -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; @@ -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; } } } @@ -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); @@ -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) { @@ -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); } @@ -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, @@ -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); @@ -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", @@ -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); @@ -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; @@ -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++) @@ -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) { @@ -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; @@ -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) { @@ -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); diff --git a/src/tvheadend.h b/src/tvheadend.h index e8b749ac7..e9acd6544 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -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) /*