]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
capmt/cwc/mpegts: change emm processing
authorJaroslav Kysela <perex@perex.cz>
Fri, 6 Jun 2014 21:47:40 +0000 (23:47 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 10 Jun 2014 12:02:36 +0000 (14:02 +0200)
src/descrambler.h
src/descrambler/capmt.c
src/descrambler/cwc.c
src/descrambler/cwc.h
src/descrambler/descrambler.c
src/input/mpegts.h
src/input/mpegts/dvb_psi.c
src/input/mpegts/mpegts_mux.c
src/service.c

index 758c1dc19f68c9400d27ba13a6876431d3e30a4b..41504ad8b48079eb3521fcb54310a44c58e4499d 100755 (executable)
@@ -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__ */
index 8b05132ff1bd0e2e0ca49b7ffb4255fa75f4a248..eb6c539f6df3e5b7db125048ce80577ae49c4407 100644 (file)
@@ -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];
index 3a1534fb9ae591265a4e1edba60fcf9b4043ecbe..51dcf65840a9f6c418931430c68b6b831089a0bf 100755 (executable)
@@ -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_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);
 }
 
@@ -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);
+}
+
 
 /**
  *
index ace3c65716ed3e4410d87becba8d691ffd6c2ae6..a256c1a294c46a1539c0eed4070b02a77079c5b4 100644 (file)
 #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_ */
index 6cd9bb4bbbd8b71a015d662c7a3e8be521f97abc..d20cfb3ec87f694ea84eb1c3302e211ba0cf26cb 100755 (executable)
@@ -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,7 +285,149 @@ 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
index a20ab9dbb1f0e8cf7cd1b41f161bf25a5060a880..83480f0c328eff036bf0512e6b206b3282057cdc 100644 (file)
@@ -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;
 
   /*
index 41878d2d8b7859211ddf2653757f12c325805a7c..df662c6f4548f95e1e1b34c615d03e3c2a071685 100644 (file)
@@ -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;
index cfdbe4cd7c865c943ca48c685e812a64cdc3162f..28b5dd2f0df8105d2d29ed01db82a54965a0eff1 100644 (file)
@@ -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;
index 479977ea827d9f8fe12b4347048ee4ff8a201bf6..c797041d963a5ae813f9df4054a019048f2f3540 100644 (file)
@@ -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);
 }