diff --git a/Makefile b/Makefile index 3da26556..8c6b2936 100644 --- a/Makefile +++ b/Makefile @@ -166,20 +166,22 @@ SRCS-${CONFIG_V4L} += \ src/v4l.c \ src/webui/extjs_v4l.c \ -# CWC -SRCS-${CONFIG_CWC} += src/cwc.c \ - src/capmt.c \ - src/ffdecsa/ffdecsa_interface.c \ - src/ffdecsa/ffdecsa_int.c - # Avahi SRCS-$(CONFIG_AVAHI) += src/avahi.c -# Optimised code +# CWC +SRCS-${CONFIG_CWC} += src/cwc.c \ + src/capmt.c + +# FFdecsa +ifneq ($(CONFIG_DVBCSA),yes) +SRCS-${CONFIG_CWC} += src/ffdecsa/ffdecsa_interface.c \ + src/ffdecsa/ffdecsa_int.c SRCS-${CONFIG_MMX} += src/ffdecsa/ffdecsa_mmx.c SRCS-${CONFIG_SSE2} += src/ffdecsa/ffdecsa_sse2.c ${BUILDDIR}/src/ffdecsa/ffdecsa_mmx.o : CFLAGS += -mmmx ${BUILDDIR}/src/ffdecsa/ffdecsa_sse2.o : CFLAGS += -msse2 +endif # File bundles SRCS-${CONFIG_BUNDLE} += bundle.c diff --git a/configure b/configure index cd493750..8e02c1b4 100755 --- a/configure +++ b/configure @@ -23,6 +23,7 @@ OPTIONS=( "avahi:auto" "zlib:auto" "bundle:no" + "dvbcsa:no" ) # @@ -116,6 +117,17 @@ if enabled linuxdvb && enabled dvbscan; then fi fi +# +# libdvbcsa +# +if enabled cwc && enabled dvbcsa; then + (check_cc_header "dvbcsa/dvbcsa" dvbcsa_h &&\ + check_cc_lib dvbcsa dvbcsa_l) ||\ + die "Failed to find dvbcsa support (use --disable-dvbcsa)" + LDFLAGS="$LDFLAGS -ldvbcsa" +fi + + # ########################################################################### # Write config # ########################################################################### diff --git a/src/capmt.c b/src/capmt.c index 0f779ed0..f10778b3 100644 --- a/src/capmt.c +++ b/src/capmt.c @@ -42,12 +42,17 @@ #include "tcp.h" #include "psi.h" #include "tsdemux.h" -#include #include "capmt.h" #include "notify.h" #include "subscriptions.h" #include "dtable.h" +#if ENABLE_DVBCSA +#include +#else +#include "ffdecsa/FFdecsa.h" +#endif + // ca_pmt_list_management values: #define CAPMT_LIST_MORE 0x00 // append a 'MORE' CAPMT object the list and start receiving the next object #define CAPMT_LIST_FIRST 0x01 // clear the list when a 'FIRST' CAPMT object is received, and start receiving the next object @@ -156,17 +161,23 @@ typedef struct capmt_service { } 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; int ct_fill_even; int ct_fill_odd; +#endif /* current sequence number */ uint16_t ct_seq; @@ -364,10 +375,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); free(ct); } @@ -506,9 +521,17 @@ 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 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 if(ct->ct_keystate != CT_RESOLVED) tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->s_svcname); @@ -842,6 +865,7 @@ 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) @@ -926,6 +950,47 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s 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_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; + + 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; + + 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 @@ -952,13 +1017,19 @@ capmt_service_start(service_t *t) /* 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)); - ct->ct_seq = capmt->capmt_seq++; +#endif TAILQ_FOREACH(st, &t->s_components, es_link) { caid_t *c; @@ -981,8 +1052,12 @@ 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; diff --git a/src/cwc.c b/src/cwc.c index 242478ca..b90cc8fe 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -27,18 +27,24 @@ #include #include #include +#include + #include "tvheadend.h" #include "tcp.h" #include "psi.h" #include "tsdemux.h" -#include #include "cwc.h" #include "notify.h" #include "atomic.h" #include "dtable.h" #include "subscriptions.h" #include "service.h" -#include + +#if ENABLE_DVBCSA +#include +#else +#include "ffdecsa/FFdecsa.h" +#endif /** * @@ -155,9 +161,12 @@ 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; @@ -167,11 +176,13 @@ typedef struct cwc_service { */ 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; int cs_fill_even; int cs_fill_odd; +#endif LIST_HEAD(, ecm_pid) cs_pids; @@ -1889,13 +1900,21 @@ 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 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 break; } } @@ -1904,6 +1923,7 @@ 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) @@ -1997,6 +2017,66 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st, 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) + update_keys(ct); + + memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188); + ct->cs_fill++; + + 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 @@ -2020,10 +2100,14 @@ 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); free(ct); } @@ -2067,19 +2151,26 @@ cwc_service_start(service_t *t) if(cwc_find_stream_by_caid(t, cwc->cwc_caid) == NULL) continue; - ct = calloc(1, sizeof(cwc_service_t)); - ct->cs_cluster_size = dvbcsa_bs_batch_size(); - ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188); + 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(); - ct->cs_cwc = cwc; - ct->cs_service = t; - ct->cs_okchannel = -3; + 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 + ct->cs_cwc = cwc; + ct->cs_service = t; + ct->cs_okchannel = -1; td = &ct->cs_head; td->td_stop = cwc_service_destroy; diff --git a/src/main.c b/src/main.c index 7ee0e70f..acc757d8 100644 --- a/src/main.c +++ b/src/main.c @@ -468,6 +468,10 @@ main(int argc, char **argv) htsp_init(); +#if (!ENABLE_DVBCSA) + ffdecsa_init(); +#endif + if(rawts_input != NULL) rawts_init(rawts_input);