]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
cclient, cwc: fixes for the recent update
authorJaroslav Kysela <perex@perex.cz>
Wed, 3 Jan 2018 14:47:08 +0000 (15:47 +0100)
committerJaroslav Kysela <perex@perex.cz>
Thu, 4 Jan 2018 14:03:22 +0000 (15:03 +0100)
src/descrambler/cccam.c
src/descrambler/cclient.c
src/descrambler/cwc.c

index 75c47cb368afcc72da3a4d982f1af0a0017b452c..bfcc08e2085d667b48229cf6677b006aa864d8ba 100644 (file)
@@ -667,15 +667,20 @@ cccam_read(void *cc, sbuf_t *rbuf)
 {
   cccam_t *cccam = cc;
   const int ka_interval = cccam->cc_keepalive_interval * 2 * 1000;
-  int r = cccam_read_message0(cccam, "Decoderloop", rbuf, ka_interval);
-  if (r < 0)
-    return -1;
-  if (r > 0) {
-    int ret = cccam_running_reply(cccam, rbuf->sb_data, r);
-    if (ret > 0)
-      sbuf_cut(rbuf, r);
-    if (ret < 0)
+  int r;
+
+  while (1) {
+    r = cccam_read_message0(cccam, "Decoderloop", rbuf, ka_interval);
+    if (r == 0)
+      break;
+    if (r < 0)
       return -1;
+    if (r > 0) {
+      int ret = cccam_running_reply(cccam, rbuf->sb_data, r);
+      if (ret < 0)
+        return -1;
+      sbuf_cut(rbuf, r);
+    }
   }
   return 0;
 }
index ea546cb9c0dfa1f73467c606b4dd7ea1fee19821..0ec734dd7fb47294bb48f50ed967e331938bdde2 100644 (file)
@@ -232,7 +232,8 @@ forbid:
       descrambler_change_keystate((th_descrambler_t *)ct, DS_FORBIDDEN, 1);
       ct->ecm_state = ECM_RESET;
       /* this pid is not valid, force full scan */
-      if (t->s_dvb_prefcapid == ct->cs_capid && t->s_dvb_prefcapid_lock == PREFCAPID_OFF)
+      if (t->s_dvb_prefcapid == ct->cs_capid &&
+          t->s_dvb_prefcapid_lock == PREFCAPID_OFF)
         t->s_dvb_prefcapid = 0;
     }
     return;
@@ -336,6 +337,8 @@ cc_read(cclient_t *cc, void *buf, size_t len, int timeout)
   if (cc_must_break(cc))
     return ECONNABORTED;
 
+  tvhtrace(cc->cc_subsys, "%s: read len %zd", cc->cc_name, len);
+  tvhlog_hexdump(cc->cc_subsys, buf, len);
   return r;
 }
 
@@ -345,22 +348,20 @@ cc_read(cclient_t *cc, void *buf, size_t len, int timeout)
 void
 cc_write_message(cclient_t *cc, cc_message_t *msg, int enq)
 {
-  tvhtrace(cc->cc_subsys, "%s: sending message len %u enq %d",
-           cc->cc_name, msg->cm_len, enq);
-  tvhlog_hexdump(cc->cc_subsys, msg->cm_data, msg->cm_len);
-
   if (enq) {
-    pthread_mutex_lock(&cc->cc_mutex);
+    lock_assert(&cc->cc_mutex);
     if (cc->cc_write_running) {
       TAILQ_INSERT_TAIL(&cc->cc_writeq, msg, cm_link);
       tvh_nonblock_write(cc->cc_pipe.wr, "w", 1);
     } else {
       free(msg);
     }
-    pthread_mutex_unlock(&cc->cc_mutex);
   } else {
+    tvhtrace(cc->cc_subsys, "%s: sending message len %u",
+             cc->cc_name, msg->cm_len);
+    tvhlog_hexdump(cc->cc_subsys, msg->cm_data, msg->cm_len);
     if (tvh_write(cc->cc_fd, msg->cm_data, msg->cm_len))
-      tvhinfo(cc->cc_subsys, "%s: write error %s",
+      tvhinfo(cc->cc_subsys, "%s: write error: %s",
               cc->cc_name, strerror(errno));
     free(msg);
   }
@@ -408,20 +409,36 @@ cc_session(cclient_t *cc)
     pthread_mutex_unlock(&cc->cc_mutex);
     r = tvhpoll_wait(poll, &ev, 1, 1000);
     pthread_mutex_lock(&cc->cc_mutex);
+    if (r == 0)
+      continue;
     if (r < 0 && ERRNO_AGAIN(errno))
       continue;
-    if (ev.ptr == &cc->cc_pipe)
+    if (r < 0)
+      break;
+    if (ev.ptr == &cc->cc_pipe) {
       read(cc->cc_pipe.rd, buf, sizeof(buf));
-    else if (ev.ptr == &cc->cc_fd) {
+    } else if (ev.ptr == &cc->cc_fd) {
+      sbuf_alloc(&rbuf, 1024);
       len = sbuf_read(&rbuf, cc->cc_fd);
-      if (len > 0 && cc->cc_read(cc, &rbuf))
-        break;
+      if (len > 0) {
+        tvhtrace(cc->cc_subsys, "%s: read len %zd", cc->cc_name, len);
+        tvhlog_hexdump(cc->cc_subsys, rbuf.sb_data + rbuf.sb_ptr - len, len);
+        if (cc->cc_read(cc, &rbuf))
+          break;
+      }
     } else {
       abort();
     }
     if ((cm = TAILQ_FIRST(&cc->cc_writeq)) != NULL) {
-      if (tvh_nonblock_write(cc->cc_fd, cm->cm_data, cm->cm_len))
+      TAILQ_REMOVE(&cc->cc_writeq, cm, cm_link);
+      tvhtrace(cc->cc_subsys, "%s: sending queued message len %u",
+               cc->cc_name, cm->cm_len);
+      tvhlog_hexdump(cc->cc_subsys, cm->cm_data, cm->cm_len);
+      if (tvh_nonblock_write(cc->cc_fd, cm->cm_data, cm->cm_len)) {
+        free(cm);
         break;
+      }
+      free(cm);
     }
     if (mono < mclk()) {
       mono = mclk();
@@ -519,6 +536,7 @@ cc_thread(void *aux)
 
   tvhinfo(cc->cc_subsys, "%s: Inactive, thread exit", cc->cc_name);
   cc_free_cards(cc);
+  cc->cc_name = NULL;
   pthread_mutex_unlock(&cc->cc_mutex);
   return NULL;
 }
@@ -639,7 +657,7 @@ cc_table_input(void *opaque, int pid, const uint8_t *data, int len, int emm)
   if (data == NULL)
     return;
 
-  if(len > 4096)
+  if (len > 4096)
     return;
 
   pthread_mutex_lock(&cc->cc_mutex);
@@ -653,7 +671,7 @@ cc_table_input(void *opaque, int pid, const uint8_t *data, int len, int emm)
     cc_service_pid_free(ct);
     /* move to init state */
     ct->ecm_state = ECM_INIT;
-    ct->cs_capid = -1;
+    ct->cs_capid = 0xffff;
     t->s_dvb_prefcapid = 0;
     tvhdebug(cc->cc_subsys, "%s: Reset after unexpected or no reply for service \"%s\"",
              cc->cc_name, t->s_dvb_svcname);
@@ -711,7 +729,7 @@ found:
   caid = c->caid;
   provid = c->providerid;
 
-  ecm = data[0] == 0x80 || data[1] == 0x81;
+  ecm = data[0] == 0x80 || data[0] == 0x81;
   if (pcard->cs_ra.caid == 0x4a30) ecm |= data[0] == 0x50; /* DVN */
 
   if (ecm) {
@@ -750,16 +768,17 @@ found:
     es->es_pending = 1;
     es->es_resolved = 0;
 
-    if(ct->cs_capid >= 0 && capid > 0 && ct->cs_capid != capid) {
-      tvhdebug(cc->cc_subsys, "%s: Filtering ECM (PID %d)",
-               cc->cc_name, capid);
+    if (ct->cs_capid != 0xffff && ct->cs_capid > 0 &&
+       capid > 0 && ct->cs_capid != capid) {
+      tvhdebug(cc->cc_subsys, "%s: Filtering ECM (PID %d), using PID %d",
+               cc->cc_name, capid, ct->cs_capid);
       goto end;
     }
 
     es->es_seq = cc->cc_send_ecm(cc, ct, es, pcard, data, len);
 
     tvhdebug(cc->cc_subsys,
-             "%s: Sending ECM%s section=%d/%d, for service \"%s\" (seqno: %d)",
+             "%s: Sending ECM%s section=%d/%d for service \"%s\" (seqno: %d)",
              cc->cc_name, chaninfo, section,
              ep->ep_last_section, t->s_dvb_svcname, es->es_seq);
     es->es_time = getfastmonoclock();
@@ -808,6 +827,7 @@ cc_service_destroy0(th_descrambler_t *td)
 
   for (i = 0; i < ct->cs_epids.count; i++)
     descrambler_close_pid(ct->cs_mux, ct, ct->cs_epids.pids[i].pid);
+  mpegts_pid_done(&ct->cs_epids);
 
   cc_service_pid_free(ct);
 
@@ -907,7 +927,7 @@ cc_service_start(caclient_t *cac, service_t *t)
     ct = calloc(1, sizeof(*ct));
   }
   ct->cs_client        = cc;
-  ct->cs_capid         = -1;
+  ct->cs_capid         = 0xffff;
   ct->cs_mux           = ((mpegts_service_t *)t)->s_dvb_mux;
   ct->ecm_state        = ECM_INIT;
 
@@ -943,7 +963,7 @@ add:
                          cc_table_input, t);
 
   if (reuse & 2) {
-    ct->cs_capid = -1;
+    ct->cs_capid = 0xffff;
     ct->ecm_state = ECM_INIT;
   }
 
@@ -1013,6 +1033,7 @@ cc_conf_changed(caclient_t *cac)
 {
   cclient_t *cc = (cclient_t *)cac;
   pthread_t tid;
+  cc_message_t *cm;
 
   if (cac->cac_enabled) {
     if (cc->cc_hostname == NULL || cc->cc_hostname[0] == '\0') {
@@ -1046,10 +1067,10 @@ cc_conf_changed(caclient_t *cac)
     pthread_join(tid, NULL);
     tvh_pipe_close(&cc->cc_pipe);
     caclient_set_status(cac, CACLIENT_STATUS_NONE);
-    pthread_mutex_lock(&cc->cc_mutex);
-    free(cc->cc_name);
-    cc->cc_name = NULL;
-    pthread_mutex_unlock(&cc->cc_mutex);    
+    while ((cm = TAILQ_FIRST(&cc->cc_writeq)) != NULL) {
+      TAILQ_REMOVE(&cc->cc_writeq, cm, cm_link);
+      free(cm);
+    }
   }
 }
 
index e80dd99fc4f70d10f487a8783cd062304a74ef50..9e2f0a8397e7ecf6a36d32c713e82707b8dd8630 100644 (file)
@@ -123,11 +123,9 @@ des_key_spread(uint8_t *normal, uint8_t *spread)
 static int
 des_encrypt(uint8_t *buffer, int len, cwc_t *cwc)
 {
-  uint8_t checksum = 0;
-  uint8_t noPadBytes;
-  uint8_t padBytes[7];
+  uint8_t checksum = 0, *ptr, noPadBytes, padBytes[7];
   DES_cblock ivec;
-  uint16_t i;
+  int i;
 
   noPadBytes = (8 - ((len - 1) % 8)) % 8;
   if (len + noPadBytes + 1 >= CWS_NETMSGSIZE-8) return -1;
@@ -138,17 +136,13 @@ des_encrypt(uint8_t *buffer, int len, cwc_t *cwc)
   uuid_random((uint8_t *)ivec, 8);
   memcpy(buffer+len, ivec, 8);
   for (i = 2; i < len; i += 8) {
-    DES_ncbc_encrypt(buffer+i, buffer+i, 8,  &cwc->cwc_k1, &ivec, 1);
-
-    DES_ecb_encrypt((DES_cblock *)(buffer+i), (DES_cblock *)(buffer+i),
-                    &cwc->cwc_k2, 0);
-
-    DES_ecb_encrypt((DES_cblock *)(buffer+i), (DES_cblock *)(buffer+i),
-                    &cwc->cwc_k1, 1);
-    memcpy(ivec, buffer+i, 8);
+    ptr = buffer + i;
+    DES_ncbc_encrypt(ptr, ptr, 8, &cwc->cwc_k1, &ivec, 1);
+    DES_ecb_encrypt((DES_cblock *)ptr, (DES_cblock *)ptr, &cwc->cwc_k2, 0);
+    DES_ecb_encrypt((DES_cblock *)ptr, (DES_cblock *)ptr, &cwc->cwc_k1, 1);
+    memcpy(ivec, ptr, 8);
   }
-  len += 8;
-  return len;
+  return len + 8;
 }
 
 /**
@@ -157,26 +151,22 @@ des_encrypt(uint8_t *buffer, int len, cwc_t *cwc)
 static int 
 des_decrypt(uint8_t *buffer, int len, cwc_t *cwc)
 {
-  DES_cblock ivec;
-  DES_cblock nextIvec;
+  DES_cblock ivec, nextIvec;
+  uint8_t *ptr, checksum = 0;;
   int i;
-  uint8_t checksum = 0;
 
   if ((len-2) % 8 || (len-2) < 16) return -1;
   len -= 8;
   memcpy(nextIvec, buffer+len, 8);
-  for (i = 2; i < len; i += 8)
-    {
-      memcpy(ivec, nextIvec, 8);
-      memcpy(nextIvec, buffer+i, 8);
-
-      DES_ecb_encrypt((DES_cblock *)(buffer+i), (DES_cblock *)(buffer+i),
-                      &cwc->cwc_k1, 0);
-      DES_ecb_encrypt((DES_cblock *)(buffer+i), (DES_cblock *)(buffer+i),
-                      &cwc->cwc_k2, 1);
-
-      DES_ncbc_encrypt(buffer+i, buffer+i, 8,  &cwc->cwc_k1, &ivec, 0);
-    } 
+  for (i = 2; i < len; i += 8) {
+    ptr = buffer + i;
+    memcpy(ivec, nextIvec, 8);
+    memcpy(nextIvec, ptr, 8);
+    DES_ecb_encrypt((DES_cblock *)ptr, (DES_cblock *)ptr, &cwc->cwc_k1, 0);
+    DES_ecb_encrypt((DES_cblock *)ptr, (DES_cblock *)ptr, &cwc->cwc_k2, 1);
+    DES_ncbc_encrypt(ptr, ptr, 8, &cwc->cwc_k1, &ivec, 0);
+  } 
+  tvhlog_hexdump(cwc->cc_subsys, buffer, len);
   for (i = 2; i < len; i++) checksum ^= buffer[i];
   if (checksum) return -1;
   return len;
@@ -234,7 +224,8 @@ cwc_send_msg(void *cc, const uint8_t *msg, size_t len,
   if (len < 3)
     return -1;
 
-  cm = malloc(sizeof(cc_message_t) + 12 + len);
+  /* note: the last 10 bytes is pad/checksum for des_encrypt() */
+  cm = malloc(sizeof(cc_message_t) + 12 + len + 10);
 
   if (cm == NULL)
     return -1;
@@ -402,9 +393,9 @@ handle_ecm_reply(cc_service_t *ct, cc_ecm_section_t *es,
     cc_ecm_reply(ct, es, DESCRAMBLER_NONE, NULL, NULL, seq);
   } else {
     type = DESCRAMBLER_CSA_CBC;
-    if (len == 3 + 8 + 8) {
+    if (len <= 22) {
       off = 8;
-    } else if (len == 3 + 16 + 16) {
+    } else if (len <= 40) {
       off = 16;
       type = DESCRAMBLER_AES128_ECB;
     } else {
@@ -498,7 +489,7 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len)
  */
 static int
 cwc_read_message0
-  (cwc_t *cwc, const char *state, sbuf_t *rbuf, int timeout)
+  (cwc_t *cwc, const char *state, sbuf_t *rbuf, int *rsize, int timeout)
 {
   int msglen;
 
@@ -509,12 +500,16 @@ cwc_read_message0
   if(rbuf->sb_ptr < 2 + msglen)
     return 0;
 
+  *rsize = msglen + 2;
   if((msglen = des_decrypt(rbuf->sb_data, msglen + 2, cwc)) < 15) {
     tvhinfo(cwc->cc_subsys, "%s: %s: Decrypt failed",
             cwc->cc_name, state);
     return -1;
   }
 
+  tvhtrace(LS_CWC, "%s: decrypted message", cwc->cc_name);
+  tvhlog_hexdump(cwc->cc_subsys, rbuf->sb_data, msglen + 2);
+
   return msglen;
 }
 
@@ -558,6 +553,9 @@ cwc_read_message
     return -1;
   }
 
+  tvhtrace(LS_CWC, "%s: decrypted message", cwc->cc_name);
+  tvhlog_hexdump(cwc->cc_subsys, buf, msglen + 2);
+
   return msglen;
 }
 
@@ -623,19 +621,22 @@ cwc_read(void *cc, sbuf_t *rbuf)
 {
   cwc_t *cwc = cc;
   const int ka_interval = cwc->cc_keepalive_interval * 2 * 1000;
-  int r = cwc_read_message0(cwc, "DecoderLoop", rbuf, ka_interval);
-  if (r < 0)
-    return -1;
-  if (r > 12) {
-    int ret = cwc_running_reply(cwc, rbuf->sb_data[12], rbuf->sb_data, r);
-    if (ret > 0)
-      sbuf_cut(rbuf, r);
-    if (ret < 0)
+  int r, rsize;
+
+  while (1) {
+    r = cwc_read_message0(cwc, "DecoderLoop", rbuf, &rsize, ka_interval);
+    if (r == 0)
+      break;
+    if (r < 0)
       return -1;
-    return 0;
+    if (r > 12) {
+      if (cwc_running_reply(cwc, rbuf->sb_data[12], rbuf->sb_data, r) < 0)
+        return -1;
+      sbuf_cut(rbuf, rsize);
+    } else if (r > 0) {
+      return -1;
+    }
   }
-  if (r > 0)
-    return -1;
   return 0;
 }