diff --git a/src/descrambler.h b/src/descrambler.h index 758c1dc1..41504ad8 100755 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -73,15 +73,33 @@ typedef struct descrambler_table { /** * List of CA ids */ +#define CAID_REMOVE_ME ((uint16_t)-1) + typedef struct caid { LIST_ENTRY(caid) link; - uint8_t delete_me; + uint16_t pid; uint16_t caid; uint32_t providerid; } caid_t; +/** + * List of EMM subscribers + */ +#define EMM_PID_UNKNOWN ((uint16_t)-1) + +typedef struct descrambler_emm { + TAILQ_ENTRY(descrambler_emm) link; + + uint16_t caid; + uint16_t pid; + unsigned int to_be_removed:1; + + descrambler_section_callback_t callback; + void *opaque; +} descrambler_emm_t; + /** * cards for which emm updates are handled */ @@ -112,8 +130,14 @@ int descrambler_open_pid ( struct mpegts_mux *mux, void *opaque, int pid, descrambler_section_callback_t callback ); int descrambler_close_pid ( struct mpegts_mux *mux, void *opaque, int pid ); void descrambler_flush_tables ( struct mpegts_mux *mux ); +void descrambler_cat_data ( struct mpegts_mux *mux, const uint8_t *data, int len ); +int descrambler_open_emm ( struct mpegts_mux *mux, void *opaque, int caid, + descrambler_section_callback_t callback ); +int descrambler_close_emm ( struct mpegts_mux *mux, void *opaque, int caid ); + 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__ */ diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 8b05132f..eb6c539f 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -1281,7 +1281,7 @@ capmt_thread(void *aux) memset(&capmt->capmt_demuxes, 0, sizeof(capmt->capmt_demuxes)); /* Accessible */ - if (!access(capmt->capmt_sockfile, R_OK | W_OK)) + if (capmt->capmt_sockfile && !access(capmt->capmt_sockfile, R_OK | W_OK)) capmt_set_connected(capmt, 1); else capmt_set_connected(capmt, 0); @@ -1392,7 +1392,7 @@ capmt_table_input(void *opaque, int pid, const uint8_t *data, int len) dmx_filter_t *f; /* Validate */ - if (len > 4096) return; + if (data == NULL || len > 4096) return; for (demux_index = 0; demux_index < capmt->capmt_demuxes.max; demux_index++) { cf = &capmt->capmt_demuxes.filters[demux_index]; diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index 3a1534fb..51dcf658 100755 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -171,6 +171,17 @@ typedef struct cwc_message { } cwc_message_t; +/** + * + */ +struct cwc; +struct cs_card_data; +typedef struct cwc_opaque_emm { + struct cs_card_data *pcard; + struct cwc *cwc; + mpegts_mux_t *mux; +} cwc_opaque_emm_t; + /** * */ @@ -198,6 +209,8 @@ typedef struct cs_card_data { uint8_t cwc_ua[8]; + cwc_opaque_emm_t cwc_opaque; + } cs_card_data_t; /** @@ -282,15 +295,15 @@ typedef struct cwc { */ static void cwc_service_destroy(th_descrambler_t *td); -void cwc_emm_conax(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_irdeto(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_dre(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_seca(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_nagra(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_nds(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_cryptoworks(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); -void cwc_emm_bulcrypt(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len); +void cwc_emm_conax(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_irdeto(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_dre(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_seca(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_nagra(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_nds(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_cryptoworks(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); +void cwc_emm_bulcrypt(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len); /** @@ -1223,8 +1236,9 @@ cwc_thread(void *aux) } while((cd = LIST_FIRST(&cwc->cwc_cards)) != NULL) { - free(cd->cwc_providers); LIST_REMOVE(cd, cs_card); + descrambler_close_emm(cd->cwc_opaque.mux, &cd->cwc_opaque, cd->cwc_caid); + free(cd->cwc_providers); free(cd); } free((void *)cwc->cwc_password); @@ -1285,61 +1299,67 @@ cwc_emm_cache_lookup(cwc_t *cwc, uint32_t crc) /** * */ -void -cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id) +static void +cwc_emm(void *opaque, int pid, const uint8_t *data, int len) { - cwc_t *cwc; - + cwc_opaque_emm_t *o = opaque; struct cs_card_data *pcard; - pthread_mutex_lock(&cwc_mutex); + cwc_t *cwc; + void *ca_update_id; - TAILQ_FOREACH(cwc, &cwcs, cwc_link) { - LIST_FOREACH(pcard,&cwc->cwc_cards, cs_card){ - if(pcard->cwc_caid == caid && - cwc->cwc_forward_emm && cwc->cwc_writer_running) { - if (cwc->cwc_emmex) { - if (cwc->cwc_update_id != ca_update_id) { - int64_t delta = getmonoclock() - cwc->cwc_update_time; - if (delta < 25000000UL) /* 25 seconds */ - continue; - } - cwc->cwc_update_time = getmonoclock(); - } - cwc->cwc_update_id = ca_update_id; - switch (pcard->cwc_card_type) { - case CARD_CONAX: - cwc_emm_conax(cwc, pcard, data, len); - break; - case CARD_IRDETO: - cwc_emm_irdeto(cwc, pcard, data, len); - break; - case CARD_SECA: - cwc_emm_seca(cwc, pcard, data, len); - break; - case CARD_VIACCESS: - cwc_emm_viaccess(cwc, pcard, data, len); - break; - case CARD_DRE: - cwc_emm_dre(cwc, pcard, data, len); - break; - case CARD_NAGRA: - cwc_emm_nagra(cwc, pcard, data, len); - break; - case CARD_NDS: - cwc_emm_nds(cwc, pcard, data, len); - break; - case CARD_CRYPTOWORKS: - cwc_emm_cryptoworks(cwc, pcard, data, len); - break; - case CARD_BULCRYPT: - cwc_emm_bulcrypt(cwc, pcard, data, len); - break; - case CARD_UNKNOWN: - break; - } + if (data == NULL) { /* end-of-data */ + o->mux = NULL; + return; + } + if (o->mux == NULL) + return; + pthread_mutex_lock(&cwc_mutex); + pcard = o->pcard; + cwc = o->cwc; + ca_update_id = o->mux; + if (cwc->cwc_forward_emm && cwc->cwc_writer_running) { + if (cwc->cwc_emmex) { + if (cwc->cwc_update_id != ca_update_id) { + int64_t delta = getmonoclock() - cwc->cwc_update_time; + if (delta < 25000000UL) /* 25 seconds */ + goto end_of_job; } + cwc->cwc_update_time = getmonoclock(); + } + cwc->cwc_update_id = ca_update_id; + switch (pcard->cwc_card_type) { + case CARD_CONAX: + cwc_emm_conax(cwc, pcard, data, len); + break; + case CARD_IRDETO: + cwc_emm_irdeto(cwc, pcard, data, len); + break; + case CARD_SECA: + cwc_emm_seca(cwc, pcard, data, len); + break; + case CARD_VIACCESS: + cwc_emm_viaccess(cwc, pcard, data, len); + break; + case CARD_DRE: + cwc_emm_dre(cwc, pcard, data, len); + break; + case CARD_NAGRA: + cwc_emm_nagra(cwc, pcard, data, len); + break; + case CARD_NDS: + cwc_emm_nds(cwc, pcard, data, len); + break; + case CARD_CRYPTOWORKS: + cwc_emm_cryptoworks(cwc, pcard, data, len); + break; + case CARD_BULCRYPT: + cwc_emm_bulcrypt(cwc, pcard, data, len); + break; + case CARD_UNKNOWN: + break; } } +end_of_job: pthread_mutex_unlock(&cwc_mutex); } @@ -1348,7 +1368,7 @@ cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id) * conax emm handler */ void -cwc_emm_conax(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_conax(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { if (data[0] == 0x82) { int i; @@ -1367,7 +1387,7 @@ cwc_emm_conax(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) * inspired by opensasc-ng, https://opensvn.csie.org/traccgi/opensascng/ */ void -cwc_emm_irdeto(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_irdeto(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int emm_mode = data[3] >> 3; int emm_len = data[3] & 0x07; @@ -1400,7 +1420,7 @@ cwc_emm_irdeto(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) * inspired by opensasc-ng, https://opensvn.csie.org/traccgi/opensascng/ */ void -cwc_emm_seca(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_seca(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int match = 0; @@ -1432,7 +1452,7 @@ cwc_emm_seca(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) * inspired by opensasc-ng, https://opensvn.csie.org/traccgi/opensascng/ */ static -uint8_t * nano_start(uint8_t * data) +const uint8_t * nano_start(const uint8_t * data) { switch(data[0]) { case 0x88: return &data[8]; @@ -1446,14 +1466,14 @@ uint8_t * nano_start(uint8_t * data) } static -uint8_t * nano_checknano90fromnano(uint8_t * data) +const uint8_t * nano_checknano90fromnano(const uint8_t * data) { if(data && data[0]==0x90 && data[1]==0x03) return data; return 0; } static -uint8_t * nano_checknano90(uint8_t * data) +const uint8_t * nano_checknano90(const uint8_t * data) { return nano_checknano90fromnano(nano_start(data)); } @@ -1488,7 +1508,7 @@ int sort_nanos(uint8_t *dest, const uint8_t *src, int len) return 0; } -static int via_provider_id(uint8_t * data) +static int via_provider_id(const uint8_t * data) { const uint8_t * tmp; tmp = nano_checknano90(data); @@ -1498,7 +1518,7 @@ static int via_provider_id(uint8_t * data) void -cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int mlen) +cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int mlen) { /* Get SCT len */ int len = 3 + ((data[1] & 0x0f) << 8) + data[2]; @@ -1552,7 +1572,7 @@ cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int mlen if (!match) break; uint8_t * tmp = alloca(len + cwc->cwc_viaccess_emm.shared_len); - uint8_t * ass = nano_start(data); + const uint8_t * ass = nano_start(data); len -= (ass - data); if((data[6] & 2) == 0) { int addrlen = len - 8; @@ -1570,31 +1590,31 @@ cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int mlen int l = cwc->cwc_viaccess_emm.shared_len - (ass - cwc->cwc_viaccess_emm.shared_emm); memcpy(&tmp[len], ass, l); len += l; - ass = (uint8_t*) alloca(len+7); - if(ass) { + uint8_t *ass2 = (uint8_t*) alloca(len+7); + if(ass2) { uint32_t crc; - memcpy(ass, data, 7); - if (sort_nanos(ass + 7, tmp, len)) { + memcpy(ass2, data, 7); + if (sort_nanos(ass2 + 7, tmp, len)) { return; } /* Set SCT len */ len += 4; - ass[1] = (len>>8) | 0x70; - ass[2] = len & 0xff; + ass2[1] = (len>>8) | 0x70; + ass2[2] = len & 0xff; len += 3; - crc = tvh_crc32(ass, len, 0xffffffff); + crc = tvh_crc32(ass2, len, 0xffffffff); if (!cwc_emm_cache_lookup(cwc, crc)) { tvhlog(LOG_DEBUG, "cwc", "Send EMM " "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x" "...%02x.%02x.%02x.%02x", - ass[0], ass[1], ass[2], ass[3], - ass[4], ass[5], ass[6], ass[7], - ass[len-4], ass[len-3], ass[len-2], ass[len-1]); - cwc_send_msg(cwc, ass, len, 0, 1, 0, 0); + ass2[0], ass2[1], ass2[2], ass2[3], + ass2[4], ass2[5], ass2[6], ass2[7], + ass2[len-4], ass2[len-3], ass2[len-2], ass2[len-1]); + cwc_send_msg(cwc, ass2, len, 0, 1, 0, 0); cwc_emm_cache_insert(cwc, crc); } } @@ -1622,6 +1642,9 @@ cwc_table_input(void *opaque, int pid, const uint8_t *data, int len) char chaninfo[32]; caid_t *c; + if (data == NULL) + return; + if (ct->td_keystate == DS_IDLE) return; @@ -1754,7 +1777,7 @@ cwc_table_input(void *opaque, int pid, const uint8_t *data, int len) * dre emm handler */ void -cwc_emm_dre(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_dre(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int match = 0; @@ -1779,7 +1802,7 @@ cwc_emm_dre(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) } void -cwc_emm_nagra(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_nagra(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int match = 0; unsigned char hexserial[4]; @@ -1801,7 +1824,7 @@ cwc_emm_nagra(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) } void -cwc_emm_nds(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_nds(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int match = 0; int i; @@ -1825,7 +1848,7 @@ cwc_emm_nds(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) } void -cwc_emm_cryptoworks(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_cryptoworks(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int match = 0; @@ -1886,7 +1909,7 @@ cwc_emm_cryptoworks(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int l } void -cwc_emm_bulcrypt(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int len) +cwc_emm_bulcrypt(cwc_t *cwc, struct cs_card_data *pcard, const uint8_t *data, int len) { int match = 0; @@ -2016,6 +2039,40 @@ cwc_destroy(cwc_t *cwc) pthread_cond_signal(&cwc->cwc_cond); } +/** + * + */ +void +cwc_caid_update(mpegts_mux_t *mux, uint16_t caid, uint16_t pid, int valid) +{ + cwc_t *cwc; + struct cs_card_data *pcard; + + tvhtrace("cwc", + "caid update event - mux %p caid %04x (%i) pid %04x (%i) valid %i", + mux, caid, caid, pid, pid, valid); + pthread_mutex_lock(&cwc_mutex); + TAILQ_FOREACH(cwc, &cwcs, cwc_link) { + if (cwc->cwc_running) { + LIST_FOREACH(pcard, &cwc->cwc_cards, cs_card) { + if (pcard->cwc_caid == caid) { + if (pcard->cwc_opaque.mux != mux) continue; + if (valid) { + pcard->cwc_opaque.cwc = cwc; + pcard->cwc_opaque.pcard = pcard; + pcard->cwc_opaque.mux = mux; + descrambler_open_emm(mux, &pcard->cwc_opaque, caid, cwc_emm); + } else { + pcard->cwc_opaque.mux = NULL; + descrambler_close_emm(mux, &pcard->cwc_opaque, caid); + } + } + } + } + } + pthread_mutex_unlock(&cwc_mutex); +} + /** * diff --git a/src/descrambler/cwc.h b/src/descrambler/cwc.h index ace3c657..a256c1a2 100644 --- a/src/descrambler/cwc.h +++ b/src/descrambler/cwc.h @@ -19,12 +19,15 @@ #ifndef CWC_H_ #define CWC_H_ +struct mpegts_mux; + void cwc_init(void); void cwc_done(void); void cwc_service_start(struct service *t); -void cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id); +void cwc_caid_update(struct mpegts_mux *mux, + uint16_t caid, uint16_t pid, int valid); #endif /* CWC_H_ */ diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index 6cd9bb4b..d20cfb3e 100755 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -205,6 +205,8 @@ descrambler_open_pid( mpegts_mux_t *mux, void *opaque, int pid, descrambler_table_t *dt; descrambler_section_t *ds; + if (mux == NULL) + return 0; pthread_mutex_lock(&mux->mm_descrambler_lock); TAILQ_FOREACH(dt, &mux->mm_descrambler_tables, link) { if (dt->table->mt_pid == pid) { @@ -228,6 +230,7 @@ descrambler_open_pid( mpegts_mux_t *mux, void *opaque, int pid, ds->opaque = opaque; TAILQ_INSERT_TAIL(&dt->sections, ds, link); pthread_mutex_unlock(&mux->mm_descrambler_lock); + tvhtrace("descrambler", "open pid %04X (%i)", pid, pid); return 1; } @@ -237,6 +240,8 @@ descrambler_close_pid( mpegts_mux_t *mux, void *opaque, int pid ) descrambler_table_t *dt; descrambler_section_t *ds; + if (mux == NULL) + return 0; pthread_mutex_lock(&mux->mm_descrambler_lock); TAILQ_FOREACH(dt, &mux->mm_descrambler_tables, link) { if (dt->table->mt_pid == pid) { @@ -250,6 +255,7 @@ descrambler_close_pid( mpegts_mux_t *mux, void *opaque, int pid ) free(dt); } pthread_mutex_unlock(&mux->mm_descrambler_lock); + tvhtrace("descrambler", "close pid %04X (%i)", pid, pid); return 1; } } @@ -264,7 +270,11 @@ descrambler_flush_tables( mpegts_mux_t *mux ) { descrambler_table_t *dt; descrambler_section_t *ds; + descrambler_emm_t *emm; + if (mux == NULL) + return; + tvhtrace("descrambler", "flush tables for %p", mux); pthread_mutex_lock(&mux->mm_descrambler_lock); while ((dt = TAILQ_FIRST(&mux->mm_descrambler_tables)) != NULL) { while ((ds = TAILQ_FIRST(&dt->sections)) != NULL) { @@ -275,9 +285,151 @@ descrambler_flush_tables( mpegts_mux_t *mux ) mpegts_table_destroy(dt->table); free(dt); } + while ((emm = TAILQ_FIRST(&mux->mm_descrambler_emms)) != NULL) { + TAILQ_REMOVE(&mux->mm_descrambler_emms, emm, link); + free(emm); + } pthread_mutex_unlock(&mux->mm_descrambler_lock); } +void +descrambler_cat_data( mpegts_mux_t *mux, const uint8_t *data, int len ) +{ + descrambler_emm_t *emm; + uint8_t dtag, dlen; + uint16_t caid = 0, pid = 0; + descrambler_section_callback_t callback = NULL; + void *opaque = NULL; + TAILQ_HEAD(,descrambler_emm) removing; + + pthread_mutex_lock(&mux->mm_descrambler_lock); + TAILQ_FOREACH(emm, &mux->mm_descrambler_emms, link) + emm->to_be_removed = 1; + pthread_mutex_unlock(&mux->mm_descrambler_lock); + while (len > 2) { + if (len > 2) { + dtag = *data++; + dlen = *data++; + len -= 2; + if (dtag != DVB_DESC_CA || len < 4 || dlen < 4) + goto next; + caid = (data[0] << 8) | data[1]; + pid = ((data[2] << 8) | data[3]) & 0x1fff; + if (pid == 0) + goto next; +#if ENABLE_CWC + cwc_caid_update(mux, caid, pid, 1); +#endif + pthread_mutex_lock(&mux->mm_descrambler_lock); + TAILQ_FOREACH(emm, &mux->mm_descrambler_emms, link) + if (emm->caid == caid) { + emm->to_be_removed = 0; + if (emm->pid == EMM_PID_UNKNOWN) { + tvhtrace("descrambler", "attach emm caid %04X (%i) pid %04X (%i)", caid, caid, pid, pid); + emm->pid = pid; + callback = emm->callback; + opaque = emm->opaque; + break; + } + } + pthread_mutex_unlock(&mux->mm_descrambler_lock); + if (emm) + descrambler_open_pid(mux, opaque, pid, callback); +next: + data += dlen; + len -= dlen; + } + } + TAILQ_INIT(&removing); + pthread_mutex_lock(&mux->mm_descrambler_lock); + TAILQ_FOREACH(emm, &mux->mm_descrambler_emms, link) + if (emm->to_be_removed) { + TAILQ_REMOVE(&mux->mm_descrambler_emms, emm, link); + TAILQ_INSERT_TAIL(&removing, emm, link); + } + pthread_mutex_unlock(&mux->mm_descrambler_lock); + while ((emm = TAILQ_FIRST(&removing)) != NULL) { + if (emm->pid != EMM_PID_UNKNOWN) { + caid = emm->caid; + pid = emm->pid; + tvhtrace("descrambler", "close emm caid %04X (%i) pid %04X (%i)", caid, caid, pid, pid); + descrambler_close_pid(mux, emm->opaque, pid); +#if ENABLE_CWC + cwc_caid_update(mux, caid, pid, 0); +#endif + } + TAILQ_REMOVE(&removing, emm, link); + free(emm); + } +} + +int +descrambler_open_emm( mpegts_mux_t *mux, void *opaque, int caid, + descrambler_section_callback_t callback ) +{ + descrambler_emm_t *emm; + caid_t *c; + int pid = EMM_PID_UNKNOWN; + + if (mux == NULL) + return 0; + pthread_mutex_lock(&mux->mm_descrambler_lock); + TAILQ_FOREACH(emm, &mux->mm_descrambler_emms, link) { + if (emm->caid == caid && emm->opaque == opaque) { + pthread_mutex_unlock(&mux->mm_descrambler_lock); + return 0; + } + } + emm = calloc(1, sizeof(*emm)); + emm->caid = caid; + emm->pid = EMM_PID_UNKNOWN; + emm->opaque = opaque; + emm->callback = callback; + LIST_FOREACH(c, &mux->mm_descrambler_caids, link) { + if (c->caid == caid) { + emm->pid = pid = c->pid; + break; + } + } + TAILQ_INSERT_TAIL(&mux->mm_descrambler_emms, emm, link); + pthread_mutex_unlock(&mux->mm_descrambler_lock); + if (pid != EMM_PID_UNKNOWN) { + tvhtrace("descrambler", + "attach emm caid %04X (%i) pid %04X (%i) - direct", + caid, caid, pid, pid); + descrambler_open_pid(mux, opaque, pid, callback); + } + return 1; +} + +int +descrambler_close_emm( mpegts_mux_t *mux, void *opaque, int caid ) +{ + descrambler_emm_t *emm; + int pid; + + if (mux == NULL) + return 0; + pthread_mutex_lock(&mux->mm_descrambler_lock); + TAILQ_FOREACH(emm, &mux->mm_descrambler_emms, link) + if (emm->caid == caid && emm->opaque == opaque) + break; + if (!emm) { + pthread_mutex_unlock(&mux->mm_descrambler_lock); + return 0; + } + TAILQ_REMOVE(&mux->mm_descrambler_emms, emm, link); + pthread_mutex_unlock(&mux->mm_descrambler_lock); + caid = emm->caid; + pid = emm->pid; + free(emm); + if (pid != EMM_PID_UNKNOWN) { + tvhtrace("descrambler", "close emm caid %04X (%i) pid %04X (%i) - direct", caid, caid, pid, pid); + descrambler_close_pid(mux, opaque, pid); + } + return 1; +} + // TODO: might actually put const char* into caid_t const char * descrambler_caid2name(uint16_t caid) diff --git a/src/input/mpegts.h b/src/input/mpegts.h index a20ab9db..83480f0c 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -347,7 +347,9 @@ struct mpegts_mux LIST_HEAD(, mpegts_table) mm_tables; TAILQ_HEAD(, mpegts_table) mm_table_queue; + LIST_HEAD(, caid) mm_descrambler_caids; TAILQ_HEAD(, descrambler_table) mm_descrambler_tables; + TAILQ_HEAD(, descrambler_emm) mm_descrambler_emms; pthread_mutex_t mm_descrambler_lock; /* diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index 41878d2d..df662c6f 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -618,20 +618,6 @@ dvb_pat_callback /* * CAT processing */ - -// TODO: might be a better way of handling this -#include "descrambler/cwc.h" -static int -dvb_ca_callback - (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid) -{ - (void)dvb_table_begin(mt, ptr, len, tableid, 0, 0, NULL, NULL, NULL, NULL); -#if ENABLE_CWC - cwc_emm((uint8_t*)ptr, len, (uintptr_t)mt->mt_opaque, mt->mt_mux); -#endif - return 0; -} - int dvb_cat_callback (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid) @@ -649,6 +635,9 @@ dvb_cat_callback ptr += 5; len -= 5; + /* Send CAT data for descramblers */ + descrambler_cat_data(mm, ptr, len); + while(len > 2) { dtag = *ptr++; dlen = *ptr++; @@ -656,13 +645,12 @@ dvb_cat_callback switch(dtag) { case DVB_DESC_CA: - caid = ( ptr[0] << 8) | ptr[1]; - pid = ((ptr[2] & 0x1f) << 8) | ptr[3]; - tvhdebug("cat", " caid %04X (%d) pid %04X (%d)", - (uint16_t)caid, (uint16_t)caid, pid, pid); - if(pid != 0) - mpegts_table_add(mm, 0, 0, dvb_ca_callback, - (void*)caid, "ca", MT_FULL | MT_SKIPSUBS, pid); + if (len >= 4 && dlen >= 4) { + caid = ( ptr[0] << 8) | ptr[1]; + pid = ((ptr[2] & 0x1f) << 8) | ptr[3]; + tvhdebug("cat", " caid %04X (%d) pid %04X (%d)", + (uint16_t)caid, (uint16_t)caid, pid, pid); + } break; default: break; @@ -1155,7 +1143,7 @@ psi_desc_add_ca LIST_FOREACH(c, &st->es_caids, link) { if(c->caid == caid) { - c->delete_me = 0; + c->pid = pid; if(c->providerid != provid) { c->providerid = provid; @@ -1169,8 +1157,7 @@ psi_desc_add_ca c->caid = caid; c->providerid = provid; - - c->delete_me = 0; + c->pid = pid; LIST_INSERT_HEAD(&st->es_caids, c, link); r |= PMT_UPDATE_NEW_CAID; return r; @@ -1327,7 +1314,7 @@ psi_parse_pmt st->es_delete_me = 1; LIST_FOREACH(c, &st->es_caids, link) - c->delete_me = 1; + c->pid = CAID_REMOVE_ME; } // Common descriptors @@ -1516,7 +1503,7 @@ psi_parse_pmt for(c = LIST_FIRST(&st->es_caids); c != NULL; c = cn) { cn = LIST_NEXT(c, link); - if(c->delete_me) { + if (c->pid == CAID_REMOVE_ME) { LIST_REMOVE(c, link); free(c); update |= PMT_UPDATE_CAID_DELETED; diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index cfdbe4cd..28b5dd2f 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -769,7 +769,9 @@ mpegts_mux_create0 mm->mm_open_table = mpegts_mux_open_table; mm->mm_close_table = mpegts_mux_close_table; TAILQ_INIT(&mm->mm_table_queue); + LIST_INIT(&mm->mm_descrambler_caids); TAILQ_INIT(&mm->mm_descrambler_tables); + TAILQ_INIT(&mm->mm_descrambler_emms); pthread_mutex_init(&mm->mm_descrambler_lock, NULL); mm->mm_last_pid = -1; diff --git a/src/service.c b/src/service.c index 479977ea..c797041d 100644 --- a/src/service.c +++ b/src/service.c @@ -1549,7 +1549,7 @@ add_caid(elementary_stream_t *st, uint16_t caid, uint32_t providerid) caid_t *c = malloc(sizeof(caid_t)); c->caid = caid; c->providerid = providerid; - c->delete_me = 0; + c->pid = 0; LIST_INSERT_HEAD(&st->es_caids, c, link); }