]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
[PR-54] Switch to libdvbcsa: update code word client and campt
authorAlain Kalker <a.c.kalker@gmail.com>
Sat, 11 Feb 2012 16:35:03 +0000 (17:35 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Wed, 28 Nov 2012 11:20:19 +0000 (11:20 +0000)
As libdvbcsa works on packet payloads instead of full packets, I borrowed
the packet inspection code from FFdecsa.

Tested and found working with Irdeto2 CA system and OSCam's NewCamd emulation.

As the capmt code doesn't use key change notification, there might be a race
between key updates and decryption, when there is undecrypted data batched up.
This has not been tested yet, as I don't have a capmt cardserver.

src/capmt.c
src/cwc.c
src/main.c

index 1bfc030069f2ad9867f15c5c7bec38fbebca4ffa..0f779ed0e8b525894c0a148ad0f69e1125b59180 100644 (file)
@@ -42,7 +42,7 @@
 #include "tcp.h"
 #include "psi.h"
 #include "tsdemux.h"
-#include "ffdecsa/FFdecsa.h"
+#include <dvbcsa/dvbcsa.h>
 #include "capmt.h"
 #include "notify.h"
 #include "subscriptions.h"
@@ -155,13 +155,18 @@ typedef struct capmt_service {
     CT_FORBIDDEN
   } ct_keystate;
 
-  /* buffer for keystruct */
-  void    *ct_keys;
+  /* buffers for keystructs */
+  struct dvbcsa_bs_key_s *ct_key_even;
+  struct dvbcsa_bs_key_s *ct_key_odd;
 
   /* CSA */
   int      ct_cluster_size;
   uint8_t *ct_tsbcluster;
+  struct dvbcsa_bs_batch_s *ct_tsbbatch_even;
+  struct dvbcsa_bs_batch_s *ct_tsbbatch_odd;
   int      ct_fill;
+  int      ct_fill_even;
+  int      ct_fill_odd;
 
   /* current sequence number */
   uint16_t ct_seq;
@@ -359,7 +364,10 @@ capmt_service_destroy(th_descrambler_t *td)
 
   LIST_REMOVE(ct, ct_link);
 
-  free_key_struct(ct->ct_keys);
+  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);
   free(ct->ct_tsbcluster);
   free(ct);
 }
@@ -498,9 +506,9 @@ handle_ca0(capmt_t* capmt) {
         continue;
 
       if (memcmp(even, invalid, 8))
-        set_even_control_word(ct->ct_keys, even);
+        dvbcsa_bs_key_set(even, ct->ct_key_even);
       if (memcmp(odd, invalid, 8))
-        set_odd_control_word(ct->ct_keys, odd);
+        dvbcsa_bs_key_set(odd, ct->ct_key_odd);
 
       if(ct->ct_keystate != CT_RESOLVED)
         tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
@@ -839,8 +847,14 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
      const uint8_t *tsb)
 {
   capmt_service_t *ct = (capmt_service_t *)td;
-  int r, i;
-  unsigned char *vec[3];
+  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)
@@ -849,28 +863,67 @@ 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);
+  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;
 
-  ct->ct_fill = 0;
-
-  vec[0] = ct->ct_tsbcluster;
-  vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
-  vec[2] = NULL;
+  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;
+  }
 
-  while(1) {
-    t0 = vec[0];
-    r = decrypt_packets(ct->ct_keys, vec);
-    if(r == 0)
-      break;
-    for(i = 0; i < r; i++) {
+    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;
 }
 
@@ -898,10 +951,14 @@ capmt_service_start(service_t *t)
     elementary_stream_t *st;
 
     /* create new capmt service */
-    ct                  = calloc(1, sizeof(capmt_service_t));
-    ct->ct_cluster_size = get_suggested_cluster_size();
-    ct->ct_tsbcluster   = malloc(ct->ct_cluster_size * 188);
-    ct->ct_seq          = capmt->capmt_seq++;
+    ct                   = calloc(1, sizeof(capmt_service_t));
+    ct->ct_cluster_size  = dvbcsa_bs_batch_size();
+    ct->ct_tsbcluster    = malloc(ct->ct_cluster_size * 188);
+    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));
+    ct->ct_seq           = capmt->capmt_seq++;
 
     TAILQ_FOREACH(st, &t->s_components, es_link) {
       caid_t *c;
@@ -924,7 +981,8 @@ capmt_service_start(service_t *t)
       }
     }
 
-    ct->ct_keys       = get_key_struct();
+    ct->ct_key_even   = dvbcsa_bs_key_alloc();
+    ct->ct_key_odd    = dvbcsa_bs_key_alloc();
     ct->ct_capmt      = capmt;
     ct->ct_service  = t;
 
index 52a4489e74c3e381a5d9fa7014d164a31f74d58d..242478ca8460a990dbe28c212fb5d374645cc2f6 100644 (file)
--- a/src/cwc.c
+++ b/src/cwc.c
@@ -31,7 +31,7 @@
 #include "tcp.h"
 #include "psi.h"
 #include "tsdemux.h"
-#include "ffdecsa/FFdecsa.h"
+#include <dvbcsa/dvbcsa.h>
 #include "cwc.h"
 #include "notify.h"
 #include "atomic.h"
@@ -155,7 +155,8 @@ typedef struct cwc_service {
     CS_IDLE
   } cs_keystate;
 
-  void *cs_keys;
+  struct dvbcsa_bs_key_s *cs_key_even;
+  struct dvbcsa_bs_key_s *cs_key_odd;
 
 
   uint8_t cs_cw[16];
@@ -166,7 +167,11 @@ typedef struct cwc_service {
    */
   int cs_cluster_size;
   uint8_t *cs_tsbcluster;
+  struct dvbcsa_bs_batch_s *cs_tsbbatch_even;
+  struct dvbcsa_bs_batch_s *cs_tsbbatch_odd;
   int cs_fill;
+  int cs_fill_even;
+  int cs_fill_odd;
 
   LIST_HEAD(, ecm_pid) cs_pids;
 
@@ -1884,13 +1889,13 @@ update_keys(cwc_service_t *ct)
   ct->cs_pending_cw_update = 0;
   for(i = 0; i < 8; i++)
     if(ct->cs_cw[i]) {
-      set_even_control_word(ct->cs_keys, ct->cs_cw);
+      dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
       break;
     }
   
   for(i = 0; i < 8; i++)
     if(ct->cs_cw[8 + i]) {
-      set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
+      dvbcsa_bs_key_set(ct->cs_cw + 8, ct->cs_key_odd);
       break;
     }
 }
@@ -1904,8 +1909,13 @@ 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];
+  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;
@@ -1916,42 +1926,72 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
   if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
     update_keys(ct);
 
-  memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
+  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;
 
-  while(1) {
+  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;
+  }
 
-    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++) {
+      for(i = 0; i < ct->cs_fill; 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;
   }
+  ct->cs_fill = 0;
+
   if(ct->cs_pending_cw_update)
     update_keys(ct);
 
@@ -1980,7 +2020,10 @@ cwc_service_destroy(th_descrambler_t *td)
 
   LIST_REMOVE(ct, cs_link);
 
-  free_key_struct(ct->cs_keys);
+  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);
   free(ct->cs_tsbcluster);
   free(ct);
 }
@@ -2025,10 +2068,15 @@ cwc_service_start(service_t *t)
       continue;
 
     ct = calloc(1, sizeof(cwc_service_t));
-    ct->cs_cluster_size = get_suggested_cluster_size();
+    ct->cs_cluster_size = dvbcsa_bs_batch_size();
     ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188);
+    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_keys = get_key_struct();
+    ct->cs_key_even = dvbcsa_bs_key_alloc();
+    ct->cs_key_odd = dvbcsa_bs_key_alloc();
     ct->cs_cwc = cwc;
     ct->cs_service = t;
     ct->cs_okchannel = -3;
index 580a151cf97a2a11e76d622cf40381eb676d852d..7ee0e70fa623efbfdd8b01b62e50e2664c4d5ab3 100644 (file)
@@ -468,8 +468,6 @@ main(int argc, char **argv)
 
   htsp_init();
 
-  ffdecsa_init();
-  
   if(rawts_input != NULL)
     rawts_init(rawts_input);