]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
capmt: fix some wrong assumptions - improve support for recent OSCAM
authorJaroslav Kysela <perex@perex.cz>
Wed, 25 Nov 2015 15:39:51 +0000 (16:39 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 25 Nov 2015 15:39:56 +0000 (16:39 +0100)
src/descrambler/capmt.c
src/tvheadend.h

index 67aab3cbe3258fed9156915b8981646ab123f770..97876a27e2c28fb7ffdb3ed6acde2070eaf0d4fd 100644 (file)
@@ -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);
 
index e8b749ac7c938639488a6697e562e8e90fe18aab..e9acd6544a9285c72df5fff5d64b3ef4072ccd53 100644 (file)
@@ -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)
 
 /*