} 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;
+
/**
*
*/
uint8_t cwc_ua[8];
+ cwc_opaque_emm_t cwc_opaque;
+
} cs_card_data_t;
/**
*/
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);
/**
}
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);
/**
*
*/
-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_opaque_emm_t *o = opaque;
+ struct cs_card_data *pcard;
cwc_t *cwc;
+ void *ca_update_id;
- struct cs_card_data *pcard;
+ if (data == NULL) { /* end-of-data */
+ o->mux = NULL;
+ return;
+ }
+ if (o->mux == NULL)
+ return;
pthread_mutex_lock(&cwc_mutex);
-
- 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;
- }
+ 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);
}
* 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;
* 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;
* 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;
* 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];
}
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));
}
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);
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];
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;
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);
}
}
char chaninfo[32];
caid_t *c;
+ if (data == NULL)
+ return;
+
if (ct->td_keystate == DS_IDLE)
return;
* 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;
}
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];
}
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;
}
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;
}
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;
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);
+}
+
/**
*
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) {
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;
}
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) {
free(dt);
}
pthread_mutex_unlock(&mux->mm_descrambler_lock);
+ tvhtrace("descrambler", "close pid %04X (%i)", pid, pid);
return 1;
}
}
{
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) {
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