Untitled
unknown
plain_text
3 years ago
33 kB
8
Indexable
diff --git a/CMakeLists.txt b/CMakeLists.txt index dc19535..8d8fe7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -684,7 +684,7 @@ if (CMAKE_COMPILER_IS_GNUCC) list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) list(GET GCC_VERSION_COMPONENTS 0 GCC_MINOR) add_definitions ("-W -Wall ") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O2") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -pipe -ffunction-sections -fdata-sections -funroll-loops -fomit-frame-pointer -fno-schedule-insns") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -ggdb") set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb") diff --git a/Makefile b/Makefile index 1c6c59f..dfdbc5a 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ override STD_DEFS += -D'CS_CONFDIR="$(CONF_DIR)"' CC_WARN = -W -Wall -Wshadow -Wredundant-decls -Wstrict-prototypes -Wold-style-definition # Compiler optimizations -CC_OPTS = -O2 -ggdb -pipe -ffunction-sections -fdata-sections +CC_OPTS = -O3 -ggdb -pipe -ffunction-sections -fdata-sections -funroll-loops -fomit-frame-pointer -fno-schedule-insns CC = $(CROSS_DIR)$(CROSS)gcc STRIP = $(CROSS_DIR)$(CROSS)strip @@ -68,6 +68,8 @@ LDFLAGS = -Wl,--gc-sections TARGETHELP := $(shell $(CC) --target-help 2>&1) ifneq (,$(findstring sse2,$(TARGETHELP))) override CFLAGS += -fexpensive-optimizations -mmmx -msse -msse2 -msse3 +else ifneq (,$(findstring neon,$(TARGETHELP))) +override CFLAGS += -fexpensive-optimizations -mfpu=neon else override CFLAGS += -fexpensive-optimizations endif @@ -287,6 +289,7 @@ SRC-$(CONFIG_WITH_EMU) += module-emulator-director.c SRC-$(CONFIG_WITH_EMU) += module-emulator-irdeto.c SRC-$(CONFIG_WITH_EMU) += module-emulator-nagravision.c SRC-$(CONFIG_WITH_EMU) += module-emulator-powervu.c +SRC-$(CONFIG_WITH_EMU) += module-emulator-icam.c SRC-$(CONFIG_WITH_EMU) += module-emulator-viaccess.c SRC-$(CONFIG_WITH_EMU) += ffdecsa/ffdecsa.c ifeq "$(CONFIG_WITH_EMU)" "y" @@ -449,7 +452,7 @@ $(OBJDIR)/config.o: $(OBJDIR)/config.c $(Q)$(CC) $(STD_DEFS) $(CC_OPTS) $(CC_WARN) $(CFLAGS) -c $< -o $@ $(OBJDIR)/%.o: %.c Makefile - @$(CC) -MP -MM -MT $@ -o $(subst .o,.d,$@) $< + @$(CC) $(CFLAGS) -MP -MM -MT $@ -o $(subst .o,.d,$@) $< $(SAY) "CC $<" $(Q)$(CC) $(STD_DEFS) $(CC_OPTS) $(CC_WARN) $(CFLAGS) -c $< -o $@ diff --git a/config.h b/config.h index 8995af7..567d1d5 100644 --- a/config.h +++ b/config.h @@ -3,11 +3,12 @@ #define WITH_EMU 1 #define WITH_SOFTCAM 1 +#define WITH_ARM_NEON 1 #define WEBIF 1 #define WEBIF_LIVELOG 1 #define WEBIF_JQUERY 1 //#define TOUCH 1 -//#define WITH_SSL 1 +#define WITH_SSL 1 #if defined(__linux__) || defined(__CYGWIN__) #define HAVE_DVBAPI 1 #endif @@ -33,7 +34,7 @@ #define MODULE_CCCAM 1 #define MODULE_CCCSHARE 1 #define MODULE_GBOX 1 -//#define MODULE_RADEGAST 1 +#define MODULE_RADEGAST 1 //#define MODULE_SERIAL 1 //#define MODULE_CONSTCW 1 //#define MODULE_PANDORA 1 diff --git a/config.sh b/config.sh index fd5bb0f..8c3cf9a 100755 --- a/config.sh +++ b/config.sh @@ -1,6 +1,6 @@ #!/bin/sh -addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI WITH_NEUTRINO READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CS_CACHEEX_AIO CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_EMU WITH_SOFTCAM" +addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI WITH_NEUTRINO READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CS_CACHEEX_AIO CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_EMU WITH_SOFTCAM WITH_ARM_NEON" protocols="MODULE_CAMD33 MODULE_CAMD35 MODULE_CAMD35_TCP MODULE_NEWCAMD MODULE_CCCAM MODULE_CCCSHARE MODULE_GBOX MODULE_RADEGAST MODULE_SCAM MODULE_SERIAL MODULE_CONSTCW MODULE_PANDORA MODULE_GHTTP" readers="READER_NAGRA READER_NAGRA_MERLIN READER_IRDETO READER_CONAX READER_CRYPTOWORKS READER_SECA READER_VIACCESS READER_VIDEOGUARD READER_DRE READER_TONGFANG READER_BULCRYPT READER_GRIFFIN READER_DGCRYPT" card_readers="CARDREADER_PHOENIX CARDREADER_INTERNAL CARDREADER_SC8IN1 CARDREADER_MP35 CARDREADER_SMARGO CARDREADER_DB2COM CARDREADER_STAPI CARDREADER_STAPI5 CARDREADER_STINGER CARDREADER_DRECAS" @@ -28,6 +28,7 @@ CONFIG_WITH_LB=y # CONFIG_IPV6SUPPORT=n CONFIG_WITH_EMU=y CONFIG_WITH_SOFTCAM=y +CONFIG_WITH_ARM_NEON=y # CONFIG_MODULE_CAMD33=n CONFIG_MODULE_CAMD35=y CONFIG_MODULE_CAMD35_TCP=y @@ -475,6 +476,7 @@ menu_addons() { IPV6SUPPORT "IPv6 support (experimental)" $(check_test "IPV6SUPPORT") \ WITH_EMU "Emulator support" $(check_test "WITH_EMU") \ WITH_SOFTCAM "Built-in SoftCam.Key" $(check_test "WITH_SOFTCAM") \ + WITH_ARM_NEON "ARM Neon Support" $(check_test "WITH_ARM_NEON") \ 2> ${tempfile} opt=${?} diff --git a/ffdecsa/CMakeLists.txt b/ffdecsa/CMakeLists.txt index d5be555..a703e5a 100644 --- a/ffdecsa/CMakeLists.txt +++ b/ffdecsa/CMakeLists.txt @@ -5,4 +5,15 @@ file (GLOB ffdecsa_hdrs "*.h") set (lib_name "ffdecsa") +if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3") +elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "(arm)|(ARM)") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon") + set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfpu=neon") +endif (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") + +if (CMAKE_COMPILER_IS_GNUCC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -pipe -ffunction-sections -fdata-sections -funroll-loops -fomit-frame-pointer -fno-schedule-insns") +endif (CMAKE_COMPILER_IS_GNUCC) + add_library (${lib_name} STATIC ${ffdecsa_srcs} ${ffdecsa_hdrs}) diff --git a/ffdecsa/ffdecsa.c b/ffdecsa/ffdecsa.c index 2c7169a..ca6d109 100644 --- a/ffdecsa/ffdecsa.c +++ b/ffdecsa/ffdecsa.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include "ffdecsa.h" +#include "../config.h" #ifndef NULL #define NULL 0 @@ -53,6 +54,7 @@ #define PARALLEL_128_2MMX 1284 #define PARALLEL_128_SSE 1285 #define PARALLEL_128_SSE2 1286 +#define PARALLEL_128_NEON 1287 //////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// #ifndef PARALLEL_MODE @@ -61,13 +63,21 @@ #define PARALLEL_MODE PARALLEL_128_SSE2 #elif defined(__mips__) || defined(__mips) || defined(__MIPS__) -#define PARALLEL_MODE PARALLEL_64_LONG +//#define PARALLEL_MODE PARALLEL_64_LONG +#define PARALLEL_MODE PARALLEL_32_INT #elif defined(__sh__) || defined(__SH4__) #define PARALLEL_MODE PARALLEL_32_INT #define COPY_UNALIGNED_PKT #define MEMALIGN_VAL 4 +#elif defined(__arm__) +#ifdef WITH_ARM_NEON +#define PARALLEL_MODE PARALLEL_128_NEON +#else +#define PARALLEL_MODE PARALLEL_32_INT +#endif + #else #define PARALLEL_MODE PARALLEL_32_INT #endif @@ -107,6 +117,8 @@ #include "parallel_128_sse.h" #elif PARALLEL_MODE==PARALLEL_128_SSE2 #include "parallel_128_sse2.h" +#elif PARALLEL_MODE==PARALLEL_128_NEON +#include "parallel_128_neon.h" #else #error "unknown/undefined parallel mode" #endif @@ -278,6 +290,96 @@ static void key_schedule_block( } +static void key_schedule_block_ecm( + unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. + unsigned char *kk, // [Out] kk[0]-kk[55] 56 bytes | Key schedule. + unsigned char ecm) // ecm +{ + static const unsigned char key_perm[0x40] = { + 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40, + 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29, + 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11, + 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37, + }; + + static const unsigned char ecm_perm[0x100] = { + 0x00,0x02,0x80,0x82,0x20,0x22,0xa0,0xa2, 0x04,0x06,0x84,0x86,0x24,0x26,0xa4,0xa6, + 0x40,0x42,0xc0,0xc2,0x60,0x62,0xe0,0xe2, 0x44,0x46,0xc4,0xc6,0x64,0x66,0xe4,0xe6, + 0x01,0x03,0x81,0x83,0x21,0x23,0xa1,0xa3, 0x05,0x07,0x85,0x87,0x25,0x27,0xa5,0xa7, + 0x41,0x43,0xc1,0xc3,0x61,0x63,0xe1,0xe3, 0x45,0x47,0xc5,0xc7,0x65,0x67,0xe5,0xe7, + 0x08,0x0a,0x88,0x8a,0x28,0x2a,0xa8,0xaa, 0x0c,0x0e,0x8c,0x8e,0x2c,0x2e,0xac,0xae, + 0x48,0x4a,0xc8,0xca,0x68,0x6a,0xe8,0xea, 0x4c,0x4e,0xcc,0xce,0x6c,0x6e,0xec,0xee, + 0x09,0x0b,0x89,0x8b,0x29,0x2b,0xa9,0xab, 0x0d,0x0f,0x8d,0x8f,0x2d,0x2f,0xad,0xaf, + 0x49,0x4b,0xc9,0xcb,0x69,0x6b,0xe9,0xeb, 0x4d,0x4f,0xcd,0xcf,0x6d,0x6f,0xed,0xef, + 0x10,0x12,0x90,0x92,0x30,0x32,0xb0,0xb2, 0x14,0x16,0x94,0x96,0x34,0x36,0xb4,0xb6, + 0x50,0x52,0xd0,0xd2,0x70,0x72,0xf0,0xf2, 0x54,0x56,0xd4,0xd6,0x74,0x76,0xf4,0xf6, + 0x11,0x13,0x91,0x93,0x31,0x33,0xb1,0xb3, 0x15,0x17,0x95,0x97,0x35,0x37,0xb5,0xb7, + 0x51,0x53,0xd1,0xd3,0x71,0x73,0xf1,0xf3, 0x55,0x57,0xd5,0xd7,0x75,0x77,0xf5,0xf7, + 0x18,0x1a,0x98,0x9a,0x38,0x3a,0xb8,0xba, 0x1c,0x1e,0x9c,0x9e,0x3c,0x3e,0xbc,0xbe, + 0x58,0x5a,0xd8,0xda,0x78,0x7a,0xf8,0xfa, 0x5c,0x5e,0xdc,0xde,0x7c,0x7e,0xfc,0xfe, + 0x19,0x1b,0x99,0x9b,0x39,0x3b,0xb9,0xbb, 0x1d,0x1f,0x9d,0x9f,0x3d,0x3f,0xbd,0xbf, + 0x59,0x5b,0xd9,0xdb,0x79,0x7b,0xf9,0xfb, 0x5d,0x5f,0xdd,0xdf,0x7d,0x7f,0xfd,0xff + }; + + int i,j,k; + int bit[64]; + int newbit[64]; + int kb[7][8]; + + // 56 steps + // 56 key bytes kk(55)..kk(0) by key schedule from ck + + // kb(6,0) .. kb(6,7) = ck(0) .. ck(7) + if (ecm == 4) + { + kb[6][0] = ecm_perm[ck[0]]; + kb[6][1] = ck[1]; + kb[6][2] = ck[2]; + kb[6][3] = ck[3]; + kb[6][4] = ecm_perm[ck[4]]; + kb[6][5] = ck[5]; + kb[6][6] = ck[6]; + kb[6][7] = ck[7]; + } + else + { + kb[6][0] = ck[0]; + kb[6][1] = ck[1]; + kb[6][2] = ck[2]; + kb[6][3] = ck[3]; + kb[6][4] = ck[4]; + kb[6][5] = ck[5]; + kb[6][6] = ck[6]; + kb[6][7] = ck[7]; + } + + + // calculate kb[5] .. kb[0] + for(i=5; i>=0; i--){ + // 64 bit perm on kb + for(j=0; j<8; j++){ + for(k=0; k<8; k++){ + bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1; + newbit[key_perm[j*8+k]-1] = bit[j*8+k]; + } + } + for(j=0; j<8; j++){ + kb[i][j] = 0; + for(k=0; k<8; k++){ + kb[i][j] |= newbit[j*8+k] << (7-k); + } + } + } + + // xor to give kk + for(i=0; i<7; i++){ + for(j=0; j<8; j++){ + kk[i*8+j] = kb[i][j] ^ i; + } + } + +} + //-----block utils static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){ @@ -395,7 +497,7 @@ static void block_decypher_group( roff=GROUP_PARALLELISM*56; -#define FASTTRASP1 +//#define FASTTRASP1 #ifndef FASTTRASP1 for(g=0;g<count;g++){ // Init registers @@ -476,7 +578,7 @@ static void block_decypher_group( #endif } -#define FASTTRASP2 +//#define FASTTRASP2 #ifndef FASTTRASP2 for(g=0;g<count;g++){ // Copy results @@ -552,6 +654,34 @@ static void schedule_key(struct csa_key_t *key, const unsigned char *pk){ } } +static void schedule_key_ecm(struct csa_key_t *key, const unsigned char *pk, const unsigned char ecm){ + // could be made faster, but is not run often + int bi,by; + int i,j; +// key + memcpy(key->ck,pk,8); +// precalculations for stream + key_schedule_stream(key->ck,key->iA,key->iB); + for(by=0;by<8;by++){ + for(bi=0;bi<8;bi++){ + key->ck_g[by][bi]=(key->ck[by]&(1<<bi))?FF1():FF0(); + } + } + for(by=0;by<8;by++){ + for(bi=0;bi<4;bi++){ + key->iA_g[by][bi]=(key->iA[by]&(1<<bi))?FF1():FF0(); + key->iB_g[by][bi]=(key->iB[by]&(1<<bi))?FF1():FF0(); + } + } +// precalculations for block + key_schedule_block_ecm(key->ck,key->kk,ecm); + for(i=0;i<56;i++){ + for(j=0;j<BYTES_PER_BATCH;j++){ + *(((unsigned char *)&key->kkmulti[i])+j)=key->kk[i]; + } + } +} + void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){ schedule_key(&((struct csa_keys_t *)keys)->even,ev); schedule_key(&((struct csa_keys_t *)keys)->odd,od); @@ -561,10 +691,18 @@ void set_even_control_word(void *keys, const unsigned char *pk){ schedule_key(&((struct csa_keys_t *)keys)->even,pk); } +void set_even_control_word_ecm(void *keys, const unsigned char *pk, const unsigned char ecm){ + schedule_key_ecm(&((struct csa_keys_t *)keys)->even,pk,ecm); +} + void set_odd_control_word(void *keys, const unsigned char *pk){ schedule_key(&((struct csa_keys_t *)keys)->odd,pk); } +void set_odd_control_word_ecm(void *keys, const unsigned char *pk, const unsigned char ecm){ + schedule_key_ecm(&((struct csa_keys_t *)keys)->odd,pk,ecm); +} + //-----get control words void get_control_words(void *keys, unsigned char *even, unsigned char *odd){ diff --git a/ffdecsa/ffdecsa.h b/ffdecsa/ffdecsa.h index 1be08e7..d37c606 100644 --- a/ffdecsa/ffdecsa.h +++ b/ffdecsa/ffdecsa.h @@ -47,9 +47,11 @@ void set_control_words(void *keys, const unsigned char *even, const unsigned cha // -- set even control word, 8 bytes void set_even_control_word(void *keys, const unsigned char *even); +void set_even_control_word_ecm(void *keys, const unsigned char *even, const unsigned char ecm); // -- set odd control word, 8 bytes void set_odd_control_word(void *keys, const unsigned char *odd); +void set_odd_control_word_ecm(void *keys, const unsigned char *odd, const unsigned char ecm); // -- get control words, 8 bytes each //void get_control_words(void *keys, unsigned char *even, unsigned char *odd); diff --git a/ffdecsa/parallel_128_neon.h b/ffdecsa/parallel_128_neon.h new file mode 100644 index 0000000..0265123 --- /dev/null +++ b/ffdecsa/parallel_128_neon.h @@ -0,0 +1,81 @@ +/* FFdecsa -- fast decsa algorithm + * + * Copyright (C) 2007 Dark Avenger + * 2003-2004 fatih89r + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +# include <arm_neon.h> + +#define MEMALIGN_VAL 16 + +union __u128i { + unsigned int u[4]; + uint64x2_t v; +}; + +static const union __u128i ff0 = {{0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}}; +static const union __u128i ff1 = {{0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU}}; + +typedef uint64x2_t group; +#define GROUP_PARALLELISM 128 +#define FF0() ff0.v +#define FF1() ff1.v +#define FFAND(a,b) vandq_u64((a),(b)) +#define FFOR(a,b) vorrq_u64((a),(b)) +#define FFXOR(a,b) veorq_u64((a),(b)) +#define FFNOT(a) vreinterpretq_u64_u8(vmvnq_u8(vreinterpretq_u8_u64(a))) + + +/* BATCH */ + +static const union __u128i ff29 = {{0x29292929U, 0x29292929U, 0x29292929U, 0x29292929U}}; +static const union __u128i ff02 = {{0x02020202U, 0x02020202U, 0x02020202U, 0x02020202U}}; +static const union __u128i ff04 = {{0x04040404U, 0x04040404U, 0x04040404U, 0x04040404U}}; +static const union __u128i ff10 = {{0x10101010U, 0x10101010U, 0x10101010U, 0x10101010U}}; +static const union __u128i ff40 = {{0x40404040U, 0x40404040U, 0x40404040U, 0x40404040U}}; +static const union __u128i ff80 = {{0x80808080U, 0x80808080U, 0x80808080U, 0x80808080U}}; + +typedef uint64x2_t batch; +#define BYTES_PER_BATCH 16 +#define B_FFN_ALL_29() ff29.v +#define B_FFN_ALL_02() ff02.v +#define B_FFN_ALL_04() ff04.v +#define B_FFN_ALL_10() ff10.v +#define B_FFN_ALL_40() ff40.v +#define B_FFN_ALL_80() ff80.v + +#define B_FFAND(a,b) FFAND(a,b) +#define B_FFOR(a,b) FFOR(a,b) +#define B_FFXOR(a,b) FFXOR(a,b) +#define B_FFSH8L(a,n) vshlq_n_u64((a),(n)) +#define B_FFSH8R(a,n) vshrq_n_u64((a),(n)) + +#define M_EMPTY() + +#undef BEST_SPAN +#define BEST_SPAN 16 + +#undef XOR_BEST_BY +inline static void XOR_BEST_BY(unsigned char *d, unsigned char *s1, unsigned char *s2) +{ + uint64x2_t vs1 = vld1q_u64((uint64_t*)s1); + uint64x2_t vs2 = vld1q_u64((uint64_t*)s2); + vs1 = veorq_u64(vs1, vs2); + vst1q_u64((uint64_t*)d, vs1); +} + +#include "fftable.h" diff --git a/module-dvbapi.c b/module-dvbapi.c index 118a1e5..81ad127 100644 --- a/module-dvbapi.c +++ b/module-dvbapi.c @@ -11,6 +11,7 @@ #include "module-dvbapi-coolapi.h" #include "module-dvbapi-stapi.h" #include "module-dvbapi-chancache.h" +#include "module-emulator-streamserver.h" #include "module-stat.h" #include "oscam-chk.h" #include "oscam-client.h" @@ -7847,7 +7848,13 @@ void dvbapi_send_dcw(struct s_client *client, ECM_REQUEST *er) delayer(er, delay); #ifdef WITH_EMU - if(!chk_ctab_ex(er->caid, &cfg.emu_stream_relay_ctab) || !cfg.emu_stream_relay_enabled) + bool set_dvbapi_cw = true; + if(chk_ctab_ex(er->caid, &cfg.emu_stream_relay_ctab) && cfg.emu_stream_relay_enabled) + { + // streamserver set cw + set_dvbapi_cw = !stream_write_cw(er); + } + if (set_dvbapi_cw) #endif switch(selected_api) { diff --git a/module-emulator-icam.c b/module-emulator-icam.c new file mode 100644 index 0000000..aae20c7 --- /dev/null +++ b/module-emulator-icam.c @@ -0,0 +1,153 @@ +#define MODULE_LOG_PREFIX "emu" + +#include "globals.h" +#include "oscam-net.h" +#include "oscam-chk.h" +#include "module-emulator-icam.h" +#include "oscam-ecm.h" +#include "oscam-client.h" +#include "ffdecsa/ffdecsa.h" + +#ifdef WITH_EMU + + +#ifdef MODULE_RADEGAST +static int32_t gRadegastFd = 0; +static uint8_t gLast_ecm_paket[EMU_STREAM_SERVER_MAX_CONNECTIONS][8]; +#endif + + +bool caid_is_icam(uint16_t caid) +{ + if (caid == 0x098C || caid == 0x098D || caid == 0x09C4) + return true; + return false; +} + + +void icam_write_cw(ECM_REQUEST *er, int32_t connid) +{ + SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[connid]); + + if (emu_fixed_key_data[connid].icam_csa_ks == NULL) + { + emu_fixed_key_data[connid].icam_csa_ks = get_key_struct(); + } + + bool icam = (er->ecm[2] - er->ecm[4]) == 4; + if (er->ecm[0] == 0x80) + { + if (icam) + { + set_even_control_word_ecm(emu_fixed_key_data[connid].icam_csa_ks, er->cw, er->ecm[0x15]); + } + else + { + set_even_control_word(emu_fixed_key_data[connid].icam_csa_ks, er->cw); + } + } + else if (icam) + { + set_odd_control_word_ecm(emu_fixed_key_data[connid].icam_csa_ks, er->cw + 8, er->ecm[0x15]); + } + else + { + set_odd_control_word(emu_fixed_key_data[connid].icam_csa_ks, er->cw + 8); + } + + emu_fixed_key_data[connid].icam_csa_used = 1; + + SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[connid]); +} + +#ifdef MODULE_RADEGAST +void icam_ecm(emu_stream_client_data *cdata) +{ + uint16_t section_length = SCT_LEN(cdata->ecm_data); + uint16_t packet_len; + static uint8_t header_len = 2; + static uint8_t payload_static_len = 12; + + if (memcmp(gLast_ecm_paket[cdata->connid], cdata->ecm_data, 8) != 0) + { + memcpy(gLast_ecm_paket[cdata->connid], cdata->ecm_data, 8); + + if (gRadegastFd <= 0) + icam_connect_to_radegast(); + + packet_len = header_len + payload_static_len + section_length; + uint8_t outgoing_data[packet_len]; + outgoing_data[0] = 1; + outgoing_data[1] = payload_static_len + section_length; + outgoing_data[2] = 10; // caid + outgoing_data[3] = 2; + outgoing_data[4] = cdata->caid >> 8; + outgoing_data[5] = cdata->caid & 0xFF; + outgoing_data[6] = 9; // srvid + outgoing_data[7] = 4; + outgoing_data[8] = cdata->srvid & 0xFF; + outgoing_data[10] = cdata->srvid >> 8; + outgoing_data[12] = 3; + outgoing_data[13] = section_length; + + memcpy(outgoing_data + header_len + payload_static_len, cdata->ecm_data, section_length); + + if (!icam_send_to_radegast(outgoing_data, packet_len)) + { + icam_close_radegast_connection(); + if (icam_connect_to_radegast()) + { + icam_send_to_radegast(outgoing_data, packet_len); + } + } + } +} + +bool icam_connect_to_radegast(void) +{ + struct sockaddr_in cservaddr; + + if (gRadegastFd == 0) + gRadegastFd = socket(AF_INET, SOCK_STREAM, 0); + + if (gRadegastFd < 0) + { + gRadegastFd = 0; + return false; + } + + int32_t flags = fcntl(gRadegastFd, F_GETFL); + fcntl(gRadegastFd, F_SETFL, flags | O_NONBLOCK); + + bzero(&cservaddr, sizeof(cservaddr)); + cservaddr.sin_family = AF_INET; + SIN_GET_ADDR(cservaddr) = cfg.rad_srvip; + cservaddr.sin_port = htons(cfg.rad_port); + + connect(gRadegastFd,(struct sockaddr *)&cservaddr, sizeof(cservaddr)); + return true; +} + +void icam_reset(int32_t connid) +{ + memset(gLast_ecm_paket[connid], 0, 8); +} + +void icam_close_radegast_connection(void) +{ + close(gRadegastFd); + gRadegastFd = 0; +} + +bool icam_send_to_radegast(uint8_t* data, int len) +{ + if (send(gRadegastFd, data, len, 0) < 0) + { + cs_log("icam_send_to_radegast: Send failure"); + return false; + } + return true; +} +#endif // MODULE_RADEGAST + +#endif // WITH_EMU diff --git a/module-emulator-icam.h b/module-emulator-icam.h new file mode 100644 index 0000000..3ecc782 --- /dev/null +++ b/module-emulator-icam.h @@ -0,0 +1,21 @@ +#ifndef MODULE_EMULATOR_ICAM_H +#define MODULE_EMULATOR_ICAM_H + +#ifdef WITH_EMU + +#include "module-emulator-streamserver.h" + +bool caid_is_icam(uint16_t caid); +void icam_write_cw(ECM_REQUEST *er, int32_t connid); + +#ifdef MODULE_RADEGAST +void icam_ecm(emu_stream_client_data *cdata); +bool icam_connect_to_radegast(void); +void icam_close_radegast_connection(void); +void icam_reset(int32_t connid); +bool icam_send_to_radegast(uint8_t* data, int len); +#endif // MODULE_RADEGAST + +#endif // WITH_EMU + +#endif // MODULE_EMULATOR_ICAM_H diff --git a/module-emulator-streamserver.c b/module-emulator-streamserver.c index a828a4f..e32c244 100644 --- a/module-emulator-streamserver.c +++ b/module-emulator-streamserver.c @@ -9,6 +9,7 @@ #include "module-emulator-osemu.h" #include "module-emulator-streamserver.h" #include "module-emulator-powervu.h" +#include "module-emulator-icam.h" #include "oscam-config.h" #include "oscam-net.h" #include "oscam-string.h" @@ -378,7 +379,7 @@ static void ParsePmtData(emu_stream_client_data *cdata) { caid = b2i(2, data + i + 2); - if (caid_is_powervu(caid) || caid == 0xA101) // add all supported caids here + if (chk_ctab_ex(caid, &cfg.emu_stream_relay_ctab) && (caid_is_powervu(caid) || caid == 0xA101 || caid_is_icam(caid))) // add all supported caids here { if (cdata->caid == NO_CAID_VALUE) { @@ -537,6 +538,12 @@ static void ParseEcmData(emu_stream_client_data *cdata) powervu_ecm(data, dcw, NULL, cdata->srvid, cdata->caid, cdata->tsid, cdata->onid, cdata->ens, &cdata->key); } } +#ifdef MODULE_RADEGAST + else if (caid_is_icam(cdata->caid)) + { + icam_ecm(cdata); + } +#endif // MODULE_RADEGAST //else if () // All other caids //{ //emu_process_ecm(); @@ -1230,6 +1237,84 @@ static void DescrambleTsPacketsCompel(emu_stream_client_data *data, uint8_t *str } } +static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize) +{ + uint8_t *packetCluster[4]; + uint8_t scrambled_packets = 0, scramblingControl; + uint32_t i, tsHeader; + int8_t odd_even = -1, odd_even_count = 1; + + for (i = 0; i < bufLength; i += packetSize) + { + tsHeader = b2i(4, stream_buf + i); + scramblingControl = (tsHeader & 0xC0) >> 6; + +#ifdef MODULE_RADEGAST + uint16_t pid, offset, payloadStart; + + pid = (tsHeader & 0x1FFF00) >> 8; + payloadStart = (tsHeader & 0x400000) >> 22; + + if (tsHeader & 0x20) + { + offset = 4 + stream_buf[i + 4] + 1; + } + else + { + offset = 4; + } + + if (data->ecm_pid && pid == data->ecm_pid) // Process the ECM data + { + stream_server_has_ecm[data->connid] = 1; + data->key.icam_csa_used = emu_fixed_key_data[data->connid].icam_csa_used; + + ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data), + &data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data); + } +#endif // MODULE_RADEGAST + + if (scramblingControl == 0) + { + continue; + } + + scrambled_packets++; + scramblingControl &= 0x1; + + if (odd_even == -1) + { + odd_even = scramblingControl; + } + + if (odd_even != scramblingControl) + { + odd_even_count++; + odd_even = scramblingControl; + } + } + + if (scrambled_packets == 0) + return; + + SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]); + + if (emu_fixed_key_data[data->connid].icam_csa_used && emu_fixed_key_data[data->connid].icam_csa_ks != NULL) + { + packetCluster[0] = stream_buf; + packetCluster[1] = stream_buf + bufLength; + packetCluster[2] = NULL; + + decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster); + if (odd_even_count > 1) // odd and even packets together cannot be decrypted in one step + { + decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster); + } + } + + SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]); +} + static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path) { struct sockaddr_in cservaddr; @@ -1241,15 +1326,6 @@ static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *str return -1; } - struct timeval tv; - tv.tv_sec = 2; - tv.tv_usec = 0; - if (setsockopt(streamfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv)) - { - cs_log("ERROR: setsockopt() failed for SO_RCVTIMEO"); - return -1; - } - bzero(&cservaddr, sizeof(cservaddr)); cservaddr.sin_family = AF_INET; cs_resolve(emu_stream_source_host, &in_addr, NULL, NULL); @@ -1284,6 +1360,8 @@ static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *str return -1; } + fcntl(streamfd, F_SETFL, fcntl(streamfd, F_GETFL) | O_NONBLOCK); + return streamfd; } @@ -1332,6 +1410,9 @@ static void *stream_client_handler(void *arg) uint16_t packetCount = 0, packetSize = 0, startOffset = 0; uint32_t remainingDataPos, remainingDataLength, tmp_pids[4]; + struct pollfd pfd[2]; + int ret; + cs_log("Stream client %i connected", conndata->connid); if (!cs_malloc(&http_buf, 1024)) @@ -1454,35 +1535,55 @@ static void *stream_client_handler(void *arg) cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_CSA; cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_CSA; } + else if (emu_fixed_key_data[conndata->connid].icam_csa_used) + { + cur_dvb_buffer_size = 188 * cluster_size; + cur_dvb_buffer_wait = 188 * (cluster_size - 3); + } else { cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_DES; cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_DES; } - streamStatus = recv(streamfd, stream_buf + bytesRead, cur_dvb_buffer_size - bytesRead, MSG_WAITALL); - if (streamStatus == 0) // socket closed + pfd[0].fd = streamfd; + pfd[0].events = POLLIN | POLLRDHUP | POLLHUP; + pfd[1].fd = conndata->connfd; + pfd[1].events = POLLRDHUP | POLLHUP; + + ret = poll(pfd, 2, 2000); + + if (ret < 0) // poll error { - cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid); + cs_log("WARNING: stream client %i error receiving data from stream source", conndata->connid); streamConnectErrorCount++; cs_sleepms(100); break; } - - if (streamStatus < 0) // error + else if (ret == 0) // timeout + { + cs_log("WARNING: stream client %i no data from stream source", conndata->connid); + streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close + continue; + } + else { - if ((errno == EWOULDBLOCK) | (errno == EAGAIN)) + if (pfd[0].revents & POLLIN) // new incoming data { - cs_log("WARNING: stream client %i no data from stream source", conndata->connid); - streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close + streamStatus = recv(streamfd, stream_buf + bytesRead, cur_dvb_buffer_size - bytesRead, MSG_DONTWAIT); + } + if ((pfd[0].revents & POLLHUP) || (pfd[0].revents & POLLRDHUP)) // incoming connection closed + { + cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid); + streamConnectErrorCount++; cs_sleepms(100); - continue; + break; + } + if ((pfd[1].revents & POLLHUP) || (pfd[1].revents & POLLRDHUP)) // outgoing connection was closed -> e.g. user zapped to other channel + { + clientStatus = -1; + break; } - - cs_log("WARNING: stream client %i error receiving data from stream source", conndata->connid); - streamConnectErrorCount++; - cs_sleepms(100); - break; } if (streamStatus < cur_dvb_buffer_size - bytesRead) // probably just received header but no stream @@ -1546,6 +1647,10 @@ static void *stream_client_handler(void *arg) { DescrambleTsPacketsCompel(data, stream_buf + startOffset, packetCount * packetSize, packetSize); } + else if (caid_is_icam(data->caid)) //ICAM + { + DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize); + } } else { @@ -1590,6 +1695,13 @@ static void *stream_client_handler(void *arg) free_key_struct(data->key.pvu_csa_ks[i]); } } + if (data->key.icam_csa_ks) + { + free_key_struct(data->key.icam_csa_ks); + } +#ifdef MODULE_RADEGAST + icam_reset(data->connid); +#endif NULLFREE(data); stream_client_disconnect(conndata); @@ -1805,8 +1917,35 @@ void stop_stream_server(void) gconncount = 0; SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); +#ifdef MODULE_RADEGAST + icam_close_radegast_connection(); +#endif + shutdown(glistenfd, 2); close(glistenfd); } +bool stream_write_cw(ECM_REQUEST *er) +{ + int32_t i; + + if (caid_is_icam(er->caid)) + { + bool cw_written = false; + //SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); + for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) + { + if (emu_stream_cur_srvid[i] == er->srvid) + { + icam_write_cw(er, i); + cw_written = true; + // don't return as there might be more connections which for the same channel (recording) + } + } + //SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); + return cw_written; + } + return true; +} + #endif // WITH_EMU diff --git a/module-emulator-streamserver.h b/module-emulator-streamserver.h index 2b1c2ac..5b76d0d 100644 --- a/module-emulator-streamserver.h +++ b/module-emulator-streamserver.h @@ -18,6 +18,8 @@ typedef struct uint32_t pvu_des_ks[8][2][32]; int8_t pvu_csa_used; void* pvu_csa_ks[8]; + int8_t icam_csa_used; + uint32_t* icam_csa_ks; } emu_stream_client_key_data; typedef struct @@ -84,6 +86,7 @@ extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNE extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; void *stream_key_delayer(void *arg); +bool stream_write_cw(ECM_REQUEST *er); #endif // WITH_EMU diff --git a/module-radegast.c b/module-radegast.c index b514203..5b07d2d 100644 --- a/module-radegast.c +++ b/module-radegast.c @@ -7,6 +7,8 @@ #include "oscam-net.h" #include "oscam-string.h" #include "oscam-reader.h" +#include "module-emulator-streamserver.h" +#include "oscam-chk.h" static int32_t radegast_connect(void); @@ -86,6 +88,9 @@ static void radegast_send_dcw(struct s_client *client, ECM_REQUEST *er) mbuf[0] = 0x02; // DCW if(er->rc < E_NOTFOUND) { + if(chk_ctab_ex(er->caid, &cfg.emu_stream_relay_ctab) && cfg.emu_stream_relay_enabled) + stream_write_cw(er); + mbuf[1] = 0x12; // len (overall) mbuf[2] = 0x05; // ACCESS mbuf[3] = 0x10; // len diff --git a/oscam.c b/oscam.c index d014cd1..f948b69 100644 --- a/oscam.c +++ b/oscam.c @@ -385,7 +385,7 @@ static void write_versionfile(bool use_stdout) st.tm_hour, st.tm_min, st.tm_sec); } - fprintf(fp, "Version: oscam-%s-r%s\n", CS_VERSION, CS_SVN_VERSION); + fprintf(fp, "Version: oscam-%s-r%s%s\n", CS_VERSION, CS_SVN_VERSION, "-ICAM-v9"); fprintf(fp, "Compiler: %s\n", CS_TARGET); fprintf(fp, "Box type: %s (%s)\n", boxtype_get(), boxname_get()); fprintf(fp, "PID: %d\n", getppid()); @@ -424,6 +424,10 @@ static void write_versionfile(bool use_stdout) write_conf(WITH_STAPI5, "DVB API with STAPI5 support"); write_conf(WITH_NEUTRINO, "DVB API with NEUTRINO support"); write_conf(READ_SDT_CHARSETS, "DVB API read-sdt charsets"); + if(config_enabled(WITH_EMU)) + { + write_conf(true, "DVB API with ICAM streamrelay support"); + } } write_conf(IRDETO_GUESSING, "Irdeto guessing"); write_conf(CS_ANTICASC, "Anti-cascading support");
Editor is loading...