From: Jaroslav Kysela Date: Wed, 3 Jan 2018 14:47:08 +0000 (+0100) Subject: cclient, cwc: fixes for the recent update X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=25db88ae1cbe611d245753503f3528250a5f4b4b;p=thirdparty%2Ftvheadend.git cclient, cwc: fixes for the recent update --- diff --git a/src/descrambler/cccam.c b/src/descrambler/cccam.c index 75c47cb36..bfcc08e20 100644 --- a/src/descrambler/cccam.c +++ b/src/descrambler/cccam.c @@ -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; } diff --git a/src/descrambler/cclient.c b/src/descrambler/cclient.c index ea546cb9c..0ec734dd7 100644 --- a/src/descrambler/cclient.c +++ b/src/descrambler/cclient.c @@ -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); + } } } diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index e80dd99fc..9e2f0a839 100644 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -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; }