]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
csa: started to rework the descrambling support
authorAdam Sutton <dev@adamsutton.me.uk>
Mon, 17 Jun 2013 11:28:17 +0000 (12:28 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Mon, 17 Jun 2013 11:38:36 +0000 (12:38 +0100)
Makefile
src/descrambler/capmt.c
src/descrambler/cwc.c
src/dvr/dvr_autorec.c

index fe5a3e920ed5cc383ae481abc8cc7d2038d17d50..f4ce7ded9586c56fb496f414b2d1c33d8163fb91 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -215,8 +215,9 @@ SRCS-$(CONFIG_LIBAV) += src/libav.c \
 
 # CWC
 SRCS-${CONFIG_CWC} += \
-       src/cwc.c \
-       src/capmt.c
+       src/descrambler/tvhcsa.c \
+       src/descrambler/cwc.c \
+       src/descrambler/capmt.c
 
 # FFdecsa
 ifneq ($(CONFIG_DVBCSA),yes)
index 3977efd00029d44c203f50b5a98a16668da4316a..a3b0dabc60eaf71205bccd54fa4bb931184013db 100644 (file)
 #include <fcntl.h>
 
 #include "tvheadend.h"
-#include "dvb/dvb.h"
+#include "input/mpegts.h"
 #include "tcp.h"
-#include "psi.h"
-#include "tsdemux.h"
 #include "capmt.h"
 #include "notify.h"
 #include "subscriptions.h"
 #include "dtable.h"
-
-#if ENABLE_DVBCSA
-#include <dvbcsa/dvbcsa.h>
-#else
-#include "ffdecsa/FFdecsa.h"
-#endif
+#include "tvhcsa.h"
+#include "input/mpegts/linuxdvb/linuxdvb_private.h"
 
 // ca_pmt_list_management values:
 #define CAPMT_LIST_MORE   0x00    // append a 'MORE' CAPMT object the list and start receiving the next object
@@ -148,7 +142,7 @@ typedef struct capmt_caid_ecm {
 typedef struct capmt_service {
   th_descrambler_t ct_head;
 
-  service_t *ct_service;
+  mpegts_service_t *ct_service;
 
   struct capmt *ct_capmt;
 
@@ -166,24 +160,7 @@ typedef struct capmt_service {
     CT_FORBIDDEN
   } ct_keystate;
 
-  /* buffers for keystructs */
-#if ENABLE_DVBCSA
-  struct dvbcsa_bs_key_s *ct_key_even;
-  struct dvbcsa_bs_key_s *ct_key_odd;
-#else
-  void                   *ct_keys;
-#endif
-
-  /* CSA */
-  int      ct_cluster_size;
-  uint8_t *ct_tsbcluster;
-  int      ct_fill;
-#if ENABLE_DVBCSA
-  struct dvbcsa_bs_batch_s *ct_tsbbatch_even;
-  struct dvbcsa_bs_batch_s *ct_tsbbatch_odd;
-  int      ct_fill_even;
-  int      ct_fill_odd;
-#endif
+  tvhcsa_t ct_csa;
 
   /* current sequence number */
   uint16_t ct_seq;
@@ -388,22 +365,14 @@ capmt_service_destroy(th_descrambler_t *td)
 
   LIST_REMOVE(ct, ct_link);
 
-#if ENABLE_DVBCSA
-  dvbcsa_bs_key_free(ct->ct_key_odd);
-  dvbcsa_bs_key_free(ct->ct_key_even);
-  free(ct->ct_tsbbatch_odd);
-  free(ct->ct_tsbbatch_even);
-#else
-  free_key_struct(ct->ct_keys);
-#endif
-  free(ct->ct_tsbcluster);
+  tvhcsa_destroy(&ct->ct_csa);
   free(ct);
 }
 
 static void 
 handle_ca0(capmt_t* capmt) {
   capmt_service_t *ct;
-  service_t *t;
+  mpegts_service_t *t;
   int ret, bufsize;
   int *request;
   ca_descr_t *ca;
@@ -522,7 +491,7 @@ handle_ca0(capmt_t* capmt) {
 
       if(ret < bufsize) {
         if(ct->ct_keystate != CT_FORBIDDEN) {
-          tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_svcname);
+          tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_dvb_svcname);
 
           ct->ct_keystate = CT_FORBIDDEN;
         }
@@ -534,20 +503,12 @@ handle_ca0(capmt_t* capmt) {
         continue;
 
       if (memcmp(even, invalid, 8))
-#if ENABLE_DVBCSA
-        dvbcsa_bs_key_set(even, ct->ct_key_even);
-#else
-        set_even_control_word(ct->ct_keys, even);
-#endif
+        tvhcsa_set_key_even(&ct->ct_csa, even);
       if (memcmp(odd, invalid, 8))
-#if ENABLE_DVBCSA
-        dvbcsa_bs_key_set(odd, ct->ct_key_odd);
-#else
-        set_odd_control_word(ct->ct_keys, odd);
-#endif
+        tvhcsa_set_key_odd(&ct->ct_csa, odd);
 
       if(ct->ct_keystate != CT_RESOLVED)
-        tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
+        tvhlog(LOG_DEBUG, "capmt", "Obtained key for service \"%s\"",t->s_dvb_svcname);
 
       ct->ct_keystate = CT_RESOLVED;
     }
@@ -617,21 +578,22 @@ capmt_thread(void *aux)
       if (!capmt->capmt_oscam) {
         bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0], capmt->capmt_port);
       } else {
-#if TODO_FIX_THIS //ENABLE_LINUXDVB
-        th_dvb_adapter_t *tda;
-        TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
-          if (!tda->tda_enabled)
+        int i;
+        extern const idclass_t linuxdvb_adapter_class;
+        linuxdvb_adapter_t *la;
+        idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class);
+        for (i = 0; i < is->is_count; i++) {
+          la = (linuxdvb_adapter_t*)is->is_array[i];
+          if (!la->mi_enabled)  continue;
+          if (!la->la_rootpath) continue;
+          if (la->la_number > MAX_CA) {
+            tvhlog(LOG_ERR, "capmt", "adapter number > MAX_CA");
             continue;
-          if (tda->tda_rootpath) {          //if rootpath is NULL then can't rely on tda_adapter_num because it is always 0
-            if (tda->tda_adapter_num > MAX_CA) {
-              tvhlog(LOG_ERR, "capmt", "adapter number > MAX_CA");
-              continue;
-            }
-            tvhlog(LOG_INFO, "capmt", "Creating capmt UDP socket for adapter %d", tda->tda_adapter_num);
-            bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[tda->tda_adapter_num], 9000 + tda->tda_adapter_num);
           }
+          tvhlog(LOG_INFO, "capmt", "Creating capmt UDP socket for adapter %d",
+                 la->la_number);
+          bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[la->la_number], 9000 + la->la_number);
         }
-#endif
       }
       if (bind_ok)
         handle_ca0(capmt);
@@ -672,14 +634,27 @@ capmt_thread(void *aux)
  *
  */
 static void
-capmt_table_input(struct th_descrambler *td, struct service *t,
+capmt_table_input(struct th_descrambler *td, struct service *s,
     struct elementary_stream *st, const uint8_t *data, int len)
 {
+  extern const idclass_t mpegts_service_class;
+  extern const idclass_t linuxdvb_frontend_class; 
   capmt_service_t *ct = (capmt_service_t *)td;
   capmt_t *capmt = ct->ct_capmt;
-  int adapter_num = t->s_dvb_mux->dm_current_tdmi->tdmi_adapter->tda_adapter_num;
+  mpegts_service_t *t = (mpegts_service_t*)s;
+  linuxdvb_frontend_t *lfe;
+  int adapter_num;
   int total_caids = 0, current_caid = 0;
 
+  /* Validate */
+  if (!idnode_is_instance(&s->s_id, &mpegts_service_class))
+    return;
+  if (!t->s_dvb_active_input) return;
+  lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
+  if (!idnode_is_instance(&lfe->mi_id, &linuxdvb_frontend_class))
+    return;
+  adapter_num = ((linuxdvb_adapter_t*)lfe->lh_parent)->la_number;
+
   caid_t *c;
 
   LIST_FOREACH(c, &st->es_caids, link) {
@@ -713,7 +688,7 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
           if (!cce) 
           {
             tvhlog(LOG_DEBUG, "capmt",
-              "New caid 0x%04X for service \"%s\"", c->caid, t->s_svcname);
+              "New caid 0x%04X for service \"%s\"", c->caid, t->s_dvb_svcname);
 
             /* ecmpid not already seen, add it to list */
             cce             = calloc(1, sizeof(capmt_caid_ecm_t));
@@ -734,12 +709,8 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
 
           uint16_t sid = t->s_dvb_service_id;
           uint16_t ecmpid = st->es_pid;
-#if TODO_FIX_THIS
-          uint16_t transponder = t->s_dvb_mux_instance->tdmi_transport_stream_id;
-          uint16_t onid = t->s_dvb_mux_instance->tdmi_network_id;
-#else
-          uint16_t transponder = 0, onid = 0;
-#endif
+          uint16_t transponder = t->s_dvb_mux->mm_tsid;
+          uint16_t onid = t->s_dvb_mux->mm_onid;
 
           /* don't do too much requests */
           if (current_caid == total_caids && caid != ct->ct_caid_last)
@@ -857,7 +828,7 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
 
           if(ct->ct_keystate != CT_RESOLVED)
             tvhlog(LOG_DEBUG, "capmt",
-              "Trying to obtain key for service \"%s\"",t->s_svcname);
+              "Trying to obtain key for service \"%s\"",t->s_dvb_svcname);
 
           buf[9] = pmtversion;
           pmtversion = (pmtversion + 1) & 0x1F;
@@ -876,100 +847,12 @@ capmt_table_input(struct th_descrambler *td, struct service *t,
 /**
  *
  */
-#if ENABLE_DVBCSA
-static int
-capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
-     const uint8_t *tsb)
-{
-  capmt_service_t *ct = (capmt_service_t *)td;
-  uint8_t *pkt;
-  int xc0;
-  int ev_od;
-  int len;
-  int offset;
-  int n;
-  // FIXME: //int residue;
-  int i;
-  uint8_t *t0;
-
-  if(ct->ct_keystate == CT_FORBIDDEN)
-    return 1;
-
-  if(ct->ct_keystate != CT_RESOLVED)
-    return -1;
-
-  pkt = ct->ct_tsbcluster + ct->ct_fill * 188;
-  memcpy(pkt, tsb, 188);
-  ct->ct_fill++;
-
-  do { // handle this packet
-    xc0 = pkt[3] & 0xc0;
-    if(xc0 == 0x00) { // clear
-      break;
-    }
-    if(xc0 == 0x40) { // reserved
-      break;
-    }
-    if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
-      ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
-      pkt[3] &= 0x3f;  // consider it decrypted now
-      if(pkt[3] & 0x20) { // incomplete packet
-        offset = 4 + pkt[4] + 1;
-        len = 188 - offset;
-        n = len >> 3;
-        // FIXME: //residue = len - (n << 3);
-        if(n == 0) { // decrypted==encrypted!
-          break; // this doesn't need more processing
-        }
-      } else {
-        len = 184;
-        offset = 4;
-        // FIXME: //n = 23;
-        // FIXME: //residue = 0;
-      }
-      if(ev_od == 0) {
-        ct->ct_tsbbatch_even[ct->ct_fill_even].data = pkt + offset;
-        ct->ct_tsbbatch_even[ct->ct_fill_even].len = len;
-        ct->ct_fill_even++;
-      } else {
-        ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = pkt + offset;
-        ct->ct_tsbbatch_odd[ct->ct_fill_odd].len = len;
-        ct->ct_fill_odd++;
-      }
-    }
-  } while(0);
-
-  if(ct->ct_fill != ct->ct_cluster_size)
-    return 0;
-
-  if(ct->ct_fill_even) {
-    ct->ct_tsbbatch_even[ct->ct_fill_even].data = NULL;
-    dvbcsa_bs_decrypt(ct->ct_key_even, ct->ct_tsbbatch_even, 184);
-    ct->ct_fill_even = 0;
-  }
-  if(ct->ct_fill_odd) {
-    ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = NULL;
-    dvbcsa_bs_decrypt(ct->ct_key_odd, ct->ct_tsbbatch_odd, 184);
-    ct->ct_fill_odd = 0;
-  }
-
-    t0 = ct->ct_tsbcluster;
-    for(i = 0; i < ct->ct_fill; i++) {
-      ts_recv_packet2(t, t0);
-      t0 += 188;
-    }
-  ct->ct_fill = 0;
-  return 0;
-}
-#else
 static int
-capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
-     const uint8_t *tsb)
+capmt_descramble
+  (th_descrambler_t *td, service_t *t, struct elementary_stream *st,
+   const uint8_t *tsb)
 {
   capmt_service_t *ct = (capmt_service_t *)td;
-  int r, i;
-  unsigned char *vec[3];
-  uint8_t *t0;
 
   if(ct->ct_keystate == CT_FORBIDDEN)
     return 1;
@@ -977,31 +860,10 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
   if(ct->ct_keystate != CT_RESOLVED)
     return -1;
 
-  memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
-  ct->ct_fill++;
-
-  if(ct->ct_fill != ct->ct_cluster_size)
-    return 0;
-
-  ct->ct_fill = 0;
-
-  vec[0] = ct->ct_tsbcluster;
-  vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
-  vec[2] = NULL;
+  tvhcsa_descramble(&ct->ct_csa, (mpegts_service_t*)t, st, tsb, 0);
 
-  while(1) {
-    t0 = vec[0];
-    r = decrypt_packets(ct->ct_keys, vec);
-    if(r == 0)
-      break;
-    for(i = 0; i < r; i++) {
-      ts_recv_packet2(t, t0);
-      t0 += 188;
-    }
-  }
   return 0;
 }
-#endif
 
 /**
  * Check if our CAID's matches, and if so, link
@@ -1009,47 +871,46 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
  * global_lock is held
  */
 void
-capmt_service_start(service_t *t)
+capmt_service_start(service_t *s)
 {
+  extern const idclass_t mpegts_service_class;
+  extern const idclass_t linuxdvb_frontend_class; 
   capmt_t *capmt;
   capmt_service_t *ct;
   capmt_caid_ecm_t *cce;
   th_descrambler_t *td;
+  mpegts_service_t *t = (mpegts_service_t*)s;
+  linuxdvb_frontend_t *lfe;
+  int tuner = 0;
   
   lock_assert(&global_lock);
 
+  /* Validate */
+  if (!idnode_is_instance(&s->s_id, &mpegts_service_class))
+    return;
+  if (!t->s_dvb_active_input) return;
+  lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input;
+  if (!idnode_is_instance(&lfe->mi_id, &linuxdvb_frontend_class))
+    return;
+  tuner = ((linuxdvb_adapter_t*)lfe->lh_parent)->la_number;
+
   TAILQ_FOREACH(capmt, &capmts, capmt_link) {
     /* skip, if we're not active */
     if (!capmt->capmt_enabled)
       continue;
 
-#if TODO_FIX_THIS
-    if (!(t->s_dvb_mux_instance && t->s_dvb_mux_instance->tdmi_adapter))
-      continue;
-#endif
-
     tvhlog(LOG_INFO, "capmt",
       "Starting capmt server for service \"%s\" on tuner %d", 
-      t->s_svcname,
-      t->s_dvb_mux->dm_current_tdmi->tdmi_adapter->tda_adapter_num);
+      t->s_dvb_svcname, tuner);
 
     elementary_stream_t *st;
 
     /* create new capmt service */
-    ct                   = calloc(1, sizeof(capmt_service_t));
-#if ENABLE_DVBCSA
-    ct->ct_cluster_size  = dvbcsa_bs_batch_size();
-#else
-    ct->ct_cluster_size  = get_suggested_cluster_size();
-#endif
-    ct->ct_tsbcluster    = malloc(ct->ct_cluster_size * 188);
-    ct->ct_seq           = capmt->capmt_seq++;
-#if ENABLE_DVBCSA
-    ct->ct_tsbbatch_even = malloc((ct->ct_cluster_size + 1) *
-                             sizeof(struct dvbcsa_bs_batch_s));
-    ct->ct_tsbbatch_odd  = malloc((ct->ct_cluster_size + 1) *
-                             sizeof(struct dvbcsa_bs_batch_s));
-#endif
+    ct              = calloc(1, sizeof(capmt_service_t));
+    tvhcsa_init(&ct->ct_csa);
+    ct->ct_capmt    = capmt;
+    ct->ct_service  = t;
+
 
     TAILQ_FOREACH(st, &t->s_components, es_link) {
       caid_t *c;
@@ -1058,7 +919,7 @@ capmt_service_start(service_t *t)
           continue;
 
         tvhlog(LOG_DEBUG, "capmt",
-          "New caid 0x%04X for service \"%s\"", c->caid, t->s_svcname);
+          "New caid 0x%04X for service \"%s\"", c->caid, t->s_dvb_svcname);
 
         /* add it to list */
         cce             = calloc(1, sizeof(capmt_caid_ecm_t));
@@ -1072,15 +933,6 @@ capmt_service_start(service_t *t)
       }
     }
 
-#if ENABLE_DVBCSA
-    ct->ct_key_even   = dvbcsa_bs_key_alloc();
-    ct->ct_key_odd    = dvbcsa_bs_key_alloc();
-#else
-    ct->ct_keys       = get_key_struct();
-#endif
-    ct->ct_capmt      = capmt;
-    ct->ct_service  = t;
-
     td = &ct->ct_head;
     td->td_stop       = capmt_service_destroy;
     td->td_table      = capmt_table_input;
index 60d2cb116d59ce11d57476a71a978090bd286dd3..7be929ea13ac5ffc65dfc4190cf744bf5bf90c9a 100644 (file)
 
 #include "tvheadend.h"
 #include "tcp.h"
-#include "psi.h"
-#include "tsdemux.h"
 #include "cwc.h"
 #include "notify.h"
 #include "atomic.h"
 #include "dtable.h"
 #include "subscriptions.h"
 #include "service.h"
-
-#if ENABLE_DVBCSA
-#include <dvbcsa/dvbcsa.h>
-#else
-#include "ffdecsa/FFdecsa.h"
-#endif
+#include "input/mpegts.h"
+#include "input/mpegts/tsdemux.h"
+#include "tvhcsa.h"
 
 /**
  *
@@ -143,7 +138,7 @@ typedef struct ecm_pid {
 typedef struct cwc_service {
   th_descrambler_t cs_head;
 
-  service_t *cs_service;
+  mpegts_service_t *cs_service;
 
   struct cwc *cs_cwc;
 
@@ -170,29 +165,11 @@ typedef struct cwc_service {
     CS_IDLE
   } cs_keystate;
 
-#if ENABLE_DVBCSA
-  struct dvbcsa_bs_key_s *cs_key_even;
-  struct dvbcsa_bs_key_s *cs_key_odd;
-#else
-  void *cs_keys;
-#endif
-
   uint8_t cs_cw[16];
   int cs_pending_cw_update;
 
-  /**
-   * CSA
-   */
-  int cs_cluster_size;
-  uint8_t *cs_tsbcluster;
-  int cs_fill;
-#if ENABLE_DVBCSA
-  struct dvbcsa_bs_batch_s *cs_tsbbatch_even;
-  struct dvbcsa_bs_batch_s *cs_tsbbatch_odd;
-  int cs_fill_even;
-  int cs_fill_odd;
-#endif
-
+  tvhcsa_t cs_csa;
+  
   LIST_HEAD(, ecm_pid) cs_pids;
 
 } cwc_service_t;
@@ -612,7 +589,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
   cwc->cwc_connected = 1;
   cwc_comet_status_update(cwc);
   cwc->cwc_caid = (msg[4] << 8) | msg[5];
-  n = psi_caid2name(cwc->cwc_caid & 0xff00) ?: "Unknown";
+  n = descrambler_caid2name(cwc->cwc_caid & 0xff00) ?: "Unknown";
 
   memcpy(cwc->cwc_ua, &msg[6], 8);
 
@@ -776,7 +753,7 @@ static void
 handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
                 int len, int seq)
 {
-  service_t *t = ct->cs_service;
+  mpegts_service_t *t = ct->cs_service;
   ecm_pid_t *ep, *epn;
   cwc_service_t *ct2;
   cwc_t *cwc2;
@@ -800,7 +777,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
     if (es->es_nok > 2) {
       tvhlog(LOG_DEBUG, "cwc",
              "Too many NOKs for service \"%s\"%s from %s:%i",
-             t->s_svcname, chaninfo, ct->cs_cwc->cwc_hostname,
+             t->s_dvb_svcname, chaninfo, ct->cs_cwc->cwc_hostname,
              ct->cs_cwc->cwc_port);
       goto forbid;
     }
@@ -812,7 +789,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
           tvhlog(LOG_DEBUG, "cwc",
            "NOK from %s:%i: Already has a key for service \"%s\", from %s:%i",
             ct->cs_cwc->cwc_hostname, ct->cs_cwc->cwc_port,
-           t->s_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
+           t->s_dvb_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
           es->es_nok = 3; /* do not send more ECM requests */
           goto forbid;
         }
@@ -820,7 +797,7 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
     }
 
     tvhlog(LOG_DEBUG, "cwc", "Received NOK for service \"%s\"%s (seqno: %d "
-          "Req delay: %"PRId64" ms)", t->s_svcname, chaninfo, seq, delay);
+          "Req delay: %"PRId64" ms)", t->s_dvb_svcname, chaninfo, seq, delay);
 
 forbid:
     LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
@@ -837,7 +814,7 @@ forbid:
     tvhlog(LOG_ERR, "cwc",
           "Can not descramble service \"%s\", access denied (seqno: %d "
           "Req delay: %"PRId64" ms)",
-          t->s_svcname, seq, delay);
+          t->s_dvb_svcname, seq, delay);
 
     ct->cs_keystate = CS_FORBIDDEN;
     ct->ecm_state = ECM_RESET;
@@ -853,7 +830,7 @@ forbid:
     if(t->s_prefcapid == 0 || t->s_prefcapid != ct->cs_channel) {
       t->s_prefcapid = ct->cs_channel;
       tvhlog(LOG_DEBUG, "cwc", "Saving prefered PID %d", t->s_prefcapid);
-      service_request_save(t, 0);
+      service_request_save((service_t*)t, 0);
     }
 
     tvhlog(LOG_DEBUG, "cwc",
@@ -862,7 +839,7 @@ forbid:
           " odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d "
           "Req delay: %"PRId64" ms)",
           chaninfo,
-          t->s_svcname,
+          t->s_dvb_svcname,
           msg[3 + 0], msg[3 + 1], msg[3 + 2], msg[3 + 3], msg[3 + 4],
           msg[3 + 5], msg[3 + 6], msg[3 + 7], msg[3 + 8], msg[3 + 9],
           msg[3 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14],
@@ -875,7 +852,7 @@ forbid:
           ct->cs_keystate = CS_IDLE;
           tvhlog(LOG_DEBUG, "cwc",
             "Already has a key for service \"%s\", from %s:%i",
-            t->s_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
+            t->s_dvb_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
           return;
         }
       }
@@ -884,7 +861,7 @@ forbid:
     if(ct->cs_keystate != CS_RESOLVED)
       tvhlog(LOG_DEBUG, "cwc",
             "Obtained key for service \"%s\" in %"PRId64" ms, from %s:%i",
-            t->s_svcname, delay, ct->cs_cwc->cwc_hostname,
+            t->s_dvb_svcname, delay, ct->cs_cwc->cwc_hostname,
             ct->cs_cwc->cwc_port);
 
     ct->cs_keystate = CS_RESOLVED;
@@ -901,7 +878,7 @@ forbid:
         for(i = 0; i < 256; i++)
           free(ep->ep_sections[i]);
         LIST_REMOVE(ep, ep_link);
-        tvhlog(LOG_WARNING, "cwc", "Delete ECM (PID %d) for service \"%s\"", ep->ep_pid, t->s_svcname);
+        tvhlog(LOG_WARNING, "cwc", "Delete ECM (PID %d) for service \"%s\"", ep->ep_pid, t->s_dvb_svcname);
         free(ep);
         ep = epn;
       }
@@ -1162,7 +1139,7 @@ cwc_thread(void *aux)
   cwc_t *cwc = aux;
   int fd, d;
   char errbuf[100];
-  service_t *t;
+  mpegts_service_t *t;
   char hostname[256];
   int port;
   struct timespec ts;
@@ -1609,10 +1586,11 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen)
  * t->s_streaming_mutex is held
  */
 static void
-cwc_table_input(struct th_descrambler *td, struct service *t,
+cwc_table_input(struct th_descrambler *td, service_t *s,
                struct elementary_stream *st, const uint8_t *data, int len)
 {
   cwc_service_t *ct = (cwc_service_t *)td;
+  mpegts_service_t *t = (mpegts_service_t*)s;
   uint16_t sid = t->s_dvb_service_id;
   cwc_t *cwc = ct->cs_cwc;
   int channel;
@@ -1641,15 +1619,16 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
       ct->ecm_state = ECM_INIT;
       ct->cs_channel = -1;
       t->s_prefcapid = 0;
-      tvhlog(LOG_DEBUG, "cwc", "Reset after unexpected or no reply for service \"%s\"", t->s_svcname);
+      tvhlog(LOG_DEBUG, "cwc", "Reset after unexpected or no reply for service \"%s\"", t->s_dvb_svcname);
     }
 
     if (ct->ecm_state == ECM_INIT) {
       // Validate prefered ECM PID
       if(t->s_prefcapid != 0) {
-        struct elementary_stream *prefca = service_stream_find(t, t->s_prefcapid);
+        struct elementary_stream *prefca
+          = service_stream_find((service_t*)t, t->s_prefcapid);
         if (!prefca || prefca->es_type != SCT_CA) {
-          tvhlog(LOG_DEBUG, "cwc", "Invalid prefered ECM (PID %d) found for service \"%s\"", t->s_prefcapid, t->s_svcname);
+          tvhlog(LOG_DEBUG, "cwc", "Invalid prefered ECM (PID %d) found for service \"%s\"", t->s_prefcapid, t->s_dvb_svcname);
           t->s_prefcapid = 0;
         }
       }
@@ -1658,13 +1637,13 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
         ep = calloc(1, sizeof(ecm_pid_t));
         ep->ep_pid = t->s_prefcapid;
         LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
-        tvhlog(LOG_DEBUG, "cwc", "Insert prefered ECM (PID %d) for service \"%s\"", t->s_prefcapid, t->s_svcname);
+        tvhlog(LOG_DEBUG, "cwc", "Insert prefered ECM (PID %d) for service \"%s\"", t->s_prefcapid, t->s_dvb_svcname);
       }
       else if(t->s_prefcapid == 0) {
           ep = calloc(1, sizeof(ecm_pid_t));
           ep->ep_pid = st->es_pid;
           LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
-          tvhlog(LOG_DEBUG, "cwc", "Insert new ECM (PID %d) for service \"%s\"", st->es_pid, t->s_svcname);
+          tvhlog(LOG_DEBUG, "cwc", "Insert new ECM (PID %d) for service \"%s\"", st->es_pid, t->s_dvb_svcname);
       }
     }
   }
@@ -1733,7 +1712,7 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
 
     tvhlog(LOG_DEBUG, "cwc", 
           "Sending ECM%s section=%d/%d, for service \"%s\" (seqno: %d)",
-          chaninfo, section, ep->ep_last_section, t->s_svcname, es->es_seq);
+          chaninfo, section, ep->ep_last_section, t->s_dvb_svcname, es->es_seq);
     es->es_time = getmonoclock();
     break;
 
@@ -1909,21 +1888,13 @@ update_keys(cwc_service_t *ct)
   ct->cs_pending_cw_update = 0;
   for(i = 0; i < 8; i++)
     if(ct->cs_cw[i]) {
-#if ENABLE_DVBCSA
-      dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
-#else
-      set_even_control_word(ct->cs_keys, ct->cs_cw);
-#endif
+      tvhcsa_set_key_even(&ct->cs_csa, ct->cs_cw);
       break;
     }
   
   for(i = 0; i < 8; i++)
     if(ct->cs_cw[8 + i]) {
-#if ENABLE_DVBCSA
-      dvbcsa_bs_key_set(ct->cs_cw + 8, ct->cs_key_odd);
-#else
-      set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
-#endif
+      tvhcsa_set_key_odd(&ct->cs_csa, ct->cs_cw);
       break;
     }
 }
@@ -1932,160 +1903,30 @@ update_keys(cwc_service_t *ct)
 /**
  *
  */
-#if ENABLE_DVBCSA
 static int
-cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
-              const uint8_t *tsb)
+cwc_descramble
+  (th_descrambler_t *td, service_t *t, struct elementary_stream *st,
+        const uint8_t *tsb)
 {
   cwc_service_t *ct = (cwc_service_t *)td;
-  uint8_t *pkt;
-  int xc0;
-  int ev_od;
-  int len;
-  int offset;
-  int n;
-  // FIXME: //int residue;
 
   if(ct->cs_keystate == CS_FORBIDDEN)
     return 1;
 
   if(ct->cs_keystate != CS_RESOLVED)
     return -1;
-
-  if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
-    update_keys(ct);
-
-  pkt = ct->cs_tsbcluster + ct->cs_fill * 188;
-  memcpy(pkt, tsb, 188);
-  ct->cs_fill++;
-
-  do { // handle this packet
-    xc0 = pkt[3] & 0xc0;
-    if(xc0 == 0x00) { // clear
-      break;
-    }
-    if(xc0 == 0x40) { // reserved
-      break;
-    }
-    if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
-      ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
-      pkt[3] &= 0x3f;  // consider it decrypted now
-      if(pkt[3] & 0x20) { // incomplete packet
-        offset = 4 + pkt[4] + 1;
-        len = 188 - offset;
-        n = len >> 3;
-        // FIXME: //residue = len - (n << 3);
-        if(n == 0) { // decrypted==encrypted!
-          break; // this doesn't need more processing
-        }
-      } else {
-        len = 184;
-        offset = 4;
-        // FIXME: //n = 23;
-        // FIXME: //residue = 0;
-      }
-      if(ev_od == 0) {
-        ct->cs_tsbbatch_even[ct->cs_fill_even].data = pkt + offset;
-        ct->cs_tsbbatch_even[ct->cs_fill_even].len = len;
-        ct->cs_fill_even++;
-      } else {
-        ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = pkt + offset;
-        ct->cs_tsbbatch_odd[ct->cs_fill_odd].len = len;
-        ct->cs_fill_odd++;
-      }
-    }
-  } while(0);
-
-  if(ct->cs_fill != ct->cs_cluster_size)
-    return 0;
-
-  if(ct->cs_fill_even) {
-    ct->cs_tsbbatch_even[ct->cs_fill_even].data = NULL;
-    dvbcsa_bs_decrypt(ct->cs_key_even, ct->cs_tsbbatch_even, 184);
-    ct->cs_fill_even = 0;
-  }
-  if(ct->cs_fill_odd) {
-    ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = NULL;
-    dvbcsa_bs_decrypt(ct->cs_key_odd, ct->cs_tsbbatch_odd, 184);
-    ct->cs_fill_odd = 0;
-  }
-
-  {
-      int i;
-      const uint8_t *t0 = ct->cs_tsbcluster;
-
-      for(i = 0; i < ct->cs_fill; i++) {
-       ts_recv_packet2(t, t0);
-       t0 += 188;
-      }
-  }
-  ct->cs_fill = 0;
-
-  if(ct->cs_pending_cw_update)
-    update_keys(ct);
-
-  return 0;
-}
-#else
-static int
-cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
-              const uint8_t *tsb)
-{
-  cwc_service_t *ct = (cwc_service_t *)td;
-  int r;
-  unsigned char *vec[3];
-
-  if(ct->cs_keystate == CS_FORBIDDEN)
-    return 1;
-
-  if(ct->cs_keystate != CS_RESOLVED)
-    return -1;
-
-  if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
+  
+  if(ct->cs_csa.csa_fill == 0 && ct->cs_pending_cw_update)
     update_keys(ct);
 
-  memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
-  ct->cs_fill++;
+  tvhcsa_descramble(&ct->cs_csa, (mpegts_service_t*)t, st, tsb,
+                    ct->cs_pending_cw_update);
 
-  if(ct->cs_fill != ct->cs_cluster_size)
-    return 0;
-
-  while(1) {
-
-    vec[0] = ct->cs_tsbcluster;
-    vec[1] = ct->cs_tsbcluster + ct->cs_fill * 188;
-    vec[2] = NULL;
-    
-    r = decrypt_packets(ct->cs_keys, vec);
-    if(r > 0) {
-      int i;
-      const uint8_t *t0 = ct->cs_tsbcluster;
-
-      for(i = 0; i < r; i++) {
-       ts_recv_packet2(t, t0);
-       t0 += 188;
-      }
-
-      r = ct->cs_fill - r;
-      assert(r >= 0);
-
-      if(r > 0)
-       memmove(ct->cs_tsbcluster, t0, r * 188);
-      ct->cs_fill = r;
-
-      if(ct->cs_pending_cw_update && r > 0)
-       continue;
-    } else {
-      ct->cs_fill = 0;
-    }
-    break;
-  }
   if(ct->cs_pending_cw_update)
     update_keys(ct);
 
   return 0;
 }
-#endif
 
 /**
  * cwc_mutex is held
@@ -2109,15 +1950,7 @@ cwc_service_destroy(th_descrambler_t *td)
 
   LIST_REMOVE(ct, cs_link);
 
-#if ENABLE_DVBCSA
-  dvbcsa_bs_key_free(ct->cs_key_odd);
-  dvbcsa_bs_key_free(ct->cs_key_even);
-  free(ct->cs_tsbbatch_odd);
-  free(ct->cs_tsbbatch_even);
-#else
-  free_key_struct(ct->cs_keys);
-#endif
-  free(ct->cs_tsbcluster);
+  tvhcsa_destroy(&ct->cs_csa);
   free(ct);
 }
 
@@ -2152,6 +1985,10 @@ cwc_service_start(service_t *t)
   cwc_service_t *ct;
   th_descrambler_t *td;
 
+  extern const idclass_t mpegts_service_class;
+  if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
+    return;
+
   pthread_mutex_lock(&cwc_mutex);
   TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
     if(cwc->cwc_caid == 0)
@@ -2161,24 +1998,9 @@ cwc_service_start(service_t *t)
       continue;
 
     ct                   = calloc(1, sizeof(cwc_service_t));
-#if ENABLE_DVBCSA
-    ct->cs_cluster_size  = dvbcsa_bs_batch_size();
-#else
-    ct->cs_cluster_size  = get_suggested_cluster_size();
-#endif
-    ct->cs_tsbcluster    = malloc(ct->cs_cluster_size * 188);
-#if ENABLE_DVBCSA
-    ct->cs_tsbbatch_even = malloc((ct->cs_cluster_size + 1) *
-                                   sizeof(struct dvbcsa_bs_batch_s));
-    ct->cs_tsbbatch_odd  = malloc((ct->cs_cluster_size + 1) *
-                                   sizeof(struct dvbcsa_bs_batch_s));
-    ct->cs_key_even      = dvbcsa_bs_key_alloc();
-    ct->cs_key_odd       = dvbcsa_bs_key_alloc();
-#else
-    ct->cs_keys          = get_key_struct();
-#endif
+    tvhcsa_init(&ct->cs_csa);
     ct->cs_cwc           = cwc;
-    ct->cs_service       = t;
+    ct->cs_service       = (mpegts_service_t*)t;
     ct->cs_channel       = -1;
     ct->ecm_state        = ECM_INIT;
 
index 09cd228f7114c032c74743ea37f750fd5dba42d9..57609ef83950f63f5cd7ac2d0b4868b225974381 100644 (file)
@@ -88,8 +88,10 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
 
   // Note: we always test season first, though it will only be set
   //       if configured
-  if(dae->dae_serieslink)
+  if(dae->dae_serieslink) {
     if (!e->serieslink || dae->dae_serieslink != e->serieslink) return 0;
+    return 1;
+  }
   if(dae->dae_season)
     if (!e->episode->season || dae->dae_season != e->episode->season) return 0;
   if(dae->dae_brand)