From 464073a27f8eb3f76aefe80f1a1d2c47370acb26 Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Sun, 8 Apr 2018 22:06:51 +0800 Subject: [PATCH] add dvb software: oscam and tvheadend --- package/lean/dvb/dvb-firmware/Makefile | 40 + .../dvb-firmware/src/dvb-demod-mn88472-02.fw | Bin 0 -> 2012 bytes .../dvb-firmware/src/dvb-demod-mn88473-01.fw | Bin 0 -> 2271 bytes .../dvb-firmware/src/dvb-demod-si2168-01.fw | Bin 0 -> 2720 bytes .../dvb-firmware/src/dvb-demod-si2168-02.fw | Bin 0 -> 2728 bytes .../src/dvb-demod-si2168-a20-01.fw | Bin 0 -> 28656 bytes .../src/dvb-demod-si2168-a30-01.fw | Bin 0 -> 17576 bytes .../src/dvb-demod-si2168-b40-01.fw | Bin 0 -> 15827 bytes .../src/dvb-demod-si2168-d60-01.fw | Bin 0 -> 3349 bytes .../src/dvb-demod-si2183-b60-01.fw | Bin 0 -> 3349 bytes .../dvb/dvb-firmware/src/dvb-fe-ds3000.fw | Bin 0 -> 8192 bytes .../src/dvb-tuner-si2141-a10-01.fw | Bin 0 -> 1666 bytes .../src/dvb-tuner-si2158-a20-01.fw | Bin 0 -> 5015 bytes .../dvb/dvb-firmware/src/dvb-usb-dw2101.fw | Bin 0 -> 8192 bytes .../dvb/dvb-firmware/src/dvb-usb-dw2102.fw | Bin 0 -> 8192 bytes .../dvb/dvb-firmware/src/dvb-usb-dw2104.fw | Bin 0 -> 8192 bytes .../dvb/dvb-firmware/src/dvb-usb-dw3101.fw | Bin 0 -> 8192 bytes .../src/dvb-usb-tbsqbox-id5521.fw | Bin 0 -> 8192 bytes package/lean/dvb/libdvbcsa/Makefile | 57 + package/lean/dvb/oscam/Makefile | 89 + package/lean/dvb/oscam/files/SoftCam.Key | 1462 ++ package/lean/dvb/oscam/files/oscam.conf | 43 + package/lean/dvb/oscam/files/oscam.dvbapi | 31 + package/lean/dvb/oscam/files/oscam.init | 23 + package/lean/dvb/oscam/files/oscam.server | 61 + package/lean/dvb/oscam/files/oscam.user | 27 + .../lean/dvb/oscam/patches/002-config.patch | 41 + .../lean/dvb/oscam/patches/003-fix_ver.patch | 121 + .../dvb/oscam/patches/004-oscam_emu.patch | 12988 ++++++++++++++++ package/lean/dvb/tvheadend/Config.in | 17 + package/lean/dvb/tvheadend/Makefile | 131 + .../lean/dvb/tvheadend/files/tvheadend.config | 13 + .../lean/dvb/tvheadend/files/tvheadend.init | 71 + .../dvb/tvheadend/patches/001-config.patch | 12 + .../tvheadend/patches/002-add-cflags.patch | 33 + .../patches/006-satip_rtsp_fix.patch | 314 + .../tvheadend/patches/008-delete-docs.patch | 10 + package/lean/luci-app-oscam/Makefile | 19 - .../luasrc/controller/admin/sattv.lua | 16 - .../luasrc/model/cbi/sattv/epg.lua | 50 - .../luasrc/model/cbi/sattv/oscam.lua | 67 - .../lean/luci-app-oscam/root/etc/config/epg | 13 - .../lean/luci-app-oscam/root/etc/config/oscam | 4 - .../lean/luci-app-oscam/root/etc/init.d/epg | 23 - .../lean/luci-app-oscam/root/etc/init.d/oscam | 70 - .../luci-app-oscam/root/etc/oscam/oscam.conf | 39 - .../root/etc/oscam/oscam.server | 28 - .../luci-app-oscam/root/etc/oscam/oscam.user | 6 - .../root/etc/uci-defaults/luci-sattv | 14 - package/lean/luci-app-oscam/root/usr/bin/epg | 199 - .../luci-app-oscam/root/usr/oscam/oscam.conf | 37 - package/lean/oscam/Config.in | 240 - package/lean/oscam/Makefile | 204 - package/lean/oscam/files/oscam.init | 12 - 54 files changed, 15584 insertions(+), 1041 deletions(-) create mode 100644 package/lean/dvb/dvb-firmware/Makefile create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-mn88472-02.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-mn88473-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-02.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a20-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a30-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-b40-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-d60-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-demod-si2183-b60-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-fe-ds3000.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-tuner-si2141-a10-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-tuner-si2158-a20-01.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-usb-dw2101.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-usb-dw2102.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-usb-dw2104.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-usb-dw3101.fw create mode 100644 package/lean/dvb/dvb-firmware/src/dvb-usb-tbsqbox-id5521.fw create mode 100644 package/lean/dvb/libdvbcsa/Makefile create mode 100755 package/lean/dvb/oscam/Makefile create mode 100644 package/lean/dvb/oscam/files/SoftCam.Key create mode 100755 package/lean/dvb/oscam/files/oscam.conf create mode 100644 package/lean/dvb/oscam/files/oscam.dvbapi create mode 100755 package/lean/dvb/oscam/files/oscam.init create mode 100644 package/lean/dvb/oscam/files/oscam.server create mode 100644 package/lean/dvb/oscam/files/oscam.user create mode 100644 package/lean/dvb/oscam/patches/002-config.patch create mode 100644 package/lean/dvb/oscam/patches/003-fix_ver.patch create mode 100644 package/lean/dvb/oscam/patches/004-oscam_emu.patch create mode 100644 package/lean/dvb/tvheadend/Config.in create mode 100644 package/lean/dvb/tvheadend/Makefile create mode 100644 package/lean/dvb/tvheadend/files/tvheadend.config create mode 100644 package/lean/dvb/tvheadend/files/tvheadend.init create mode 100644 package/lean/dvb/tvheadend/patches/001-config.patch create mode 100755 package/lean/dvb/tvheadend/patches/002-add-cflags.patch create mode 100644 package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch create mode 100644 package/lean/dvb/tvheadend/patches/008-delete-docs.patch delete mode 100644 package/lean/luci-app-oscam/Makefile delete mode 100644 package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua delete mode 100644 package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua delete mode 100644 package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua delete mode 100644 package/lean/luci-app-oscam/root/etc/config/epg delete mode 100644 package/lean/luci-app-oscam/root/etc/config/oscam delete mode 100755 package/lean/luci-app-oscam/root/etc/init.d/epg delete mode 100755 package/lean/luci-app-oscam/root/etc/init.d/oscam delete mode 100644 package/lean/luci-app-oscam/root/etc/oscam/oscam.conf delete mode 100644 package/lean/luci-app-oscam/root/etc/oscam/oscam.server delete mode 100644 package/lean/luci-app-oscam/root/etc/oscam/oscam.user delete mode 100644 package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv delete mode 100755 package/lean/luci-app-oscam/root/usr/bin/epg delete mode 100644 package/lean/luci-app-oscam/root/usr/oscam/oscam.conf delete mode 100644 package/lean/oscam/Config.in delete mode 100644 package/lean/oscam/Makefile delete mode 100644 package/lean/oscam/files/oscam.init diff --git a/package/lean/dvb/dvb-firmware/Makefile b/package/lean/dvb/dvb-firmware/Makefile new file mode 100644 index 000000000..8c6d0f0b4 --- /dev/null +++ b/package/lean/dvb/dvb-firmware/Makefile @@ -0,0 +1,40 @@ +# +# Copyright (C) 2017 McMCC +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=dvb-firmware +PKG_VERSION:=1.0 +PKG_RELEASE:=2 + +include $(INCLUDE_DIR)/package.mk + +define Package/dvb-firmware + SECTION:=dvb-firmware + CATEGORY:=Firmware + TITLE:=dvb-firmware megapack +endef + +define Package/dvb-firmware/description + dvb-firmware is specialised software that is both specific to some hardware + and also integral for its proper functioning. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR)/firmware + $(CP) ./src/* $(PKG_BUILD_DIR)/firmware +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/dvb-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware + $(CP) $(PKG_BUILD_DIR)/firmware/* $(1)/lib/firmware +endef + +$(eval $(call BuildPackage,dvb-firmware)) diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88472-02.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88472-02.fw new file mode 100644 index 0000000000000000000000000000000000000000..1f0177813bc4e7eb7c8ad335b1ea3a91055ad084 GIT binary patch literal 2012 zcma)7PfQ$D7@t48`=&I&Tc8%{ZaY{d&xrD{LFqxINn1TMsaL|GNdw84w#g$5DNvD_ z^`K2WFlsd%>YrO_JxFXC4^28TL!u^46BFwJa05%Ay=Yb_EG!Ve@6Al1jWJyI?fd@x zzTfxnjjQaXich9|GVPNYpA>vD=aU7WEc)axpA>ykrqw>#pesIk$hH(VuCVJ@*p|w5 zpZsa*p6)2$@=pcW%<|9iSmvLJw|ue$2l2^DK$h`bfBfg0~ zn>qD%PJ1(_iCm&4mv|$W_$8NW&Z+NzcsPJ4ny0yy5S)+5IJs0QM@EoLvC&apQv3>RNBq@WF2^;f#!1d zk-%i8Z@sc!nvG%Wd|3!+~^G)W#d-b5i#UyQjl^D9F2cIku+1}Z%Rc&!4j=fWQ6 z2QrX*ejqDzj&zuVVYWm$>yCaDic3ee-vTl>pn7k!a}DhLINQ?LN)kA+OP}x!NUD|% zE0R%?U7)VcF4Vgz_{W9~-fEj>D{mEfvlY{t!!!zx{yG9`qj+Mk@hm`D3RX2#@*Q@r zhMj*A5in9hM!LICHa1#q&I3C(>zY*jYql)PNSZ}A_6;ZuFAIN51T&r8Vhv+S&_rh z%uhkAQ@qp8n4SDIz@O$#AZZH7s+EB1Bw24gj7hKJq+UWNe1zIjnSww2d7tf=eG!KA zL-T#SPmG{gYyfl<{5FLEk)%@;Fc_>C1Ve3TACLzCuREy*-VJNe&3nX8(19L&UH8S~ zA?v;;zQM47U}EUL!$ zD`qjVi C<-GL( literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88473-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88473-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..1b2eceabb00f0ff077c1e6384ab55cff7d2bf7ca GIT binary patch literal 2271 zcmah~TZmOv7(Q$5efD0Hid&t7nvR_jtL;;3@I`8@Q3!%C5otgSlEKLH5NzpK6O{fQ zdKj(7jYv%wrRZhqLB|YXKxv45Ah56m)0mn$b8&9YIL^hn&zZh|ov}$sgUz?r`quid z>tFw-n6=1@HK`VcR)!oy8$&xo2SX>rO@=OpZf|Lm>fu=*!!3q>h5?4#41)}J7={>z z8AiOZCN;{lyWaXHHO8}Xh6#pAZ$p!s;@LFA48tr#o?#A96k`w!lEGrI{k+td(#hl{ zKQFWuxNtsFZ3!zC#@a}{t3L?fY=@rZp;v#%2L|*u^^3RO5B4bTt>}N9ZFyjosHFi_NMh%JDj0?86;bT6h*U>n3ATSCF{@7o7RM~Ek!aCn!Qo^Xi7EXRhuaycPNQ~+#3-|6 zX~MR&3g?9WIPh@2x-LlKg6Fl$btK=9R4$OAJQAtyY7xpqk-Eta$#P^xK8vhGs>=}D znb_e8Bqfw@;7a@!p_|hp*{qv`e6ksLL-H-dE6h2^-6Ri@JVNp)u2FS!G}TK&`30Ps zMO~2mU59)qS$nx;$t@6y`}F=`61m#%Kk1QuBT_@0Yx^~_zl_u!+}|J< ztNk{zV82tS6#E!tS!N&ECmy6`LG(Ko{eE6FyCC`trqj4X_JButu-pV_r|RQ7$-Y@A zmp@sxMrVO@L^#aALu|5g%F`dfGU+iJ4vZt0_3v?COM z$?V0<-pg4vR=O>#MzIS;*gdXm0};m44^eRZAqs>(r_bXxnzmMW5%E^Pr@|kpU;_(H z(e%jw>5Sy`;=xwOLLPH)%jt@WY+g4&@)?h3W{>TQ9MX0Jd z85QA?q|j<3mB#{24+~5zG|W0@D>*;#+{SzdF2~u)Tc-L5Lket&d=15JW`8XH+o)}-jG&vW@X(Z<& zTQ~Yb=Q24r_^|n5%wR!I2hzqA&UYabg^KOvhTu$+E4)?sg<*_TFW0HNgxmzTZEy+Z z(3ss)ayNSAhTB-EAvcF+DMPm^QhkW0FH%zop)XbAzDn+PJ%M(WRqdtbht@|-e$77g zL28*XlP33cr1~M-AE_S5_Cxk_a*y6G+fPgyS)99tx@>UIA;a!@(@;#`cYkCeD!d2x zy0OCm+3P4B{Flki2^5YIc#T#5tJal&c1HgVgJb_~vqvYC+&F z82Epyh*S+Xog7By9szff)HU{}#am$nS|QLHsa7L!j#Q(!(g-v%#{yYWS6QIdd(3QH Ng#uE4F_ja0{ss)~B`N>_ literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..5882a214243881da49e3ea3dc20d4e4fb85d022b GIT binary patch literal 2720 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 F`2Pid(kB1_ literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-02.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-02.fw new file mode 100644 index 0000000000000000000000000000000000000000..62d627625e930948c4f74cfbed3f0d902c4b77a9 GIT binary patch literal 2728 zcmV~$2OyMf003ay_vxcV$>todap$!wNtcY2jLagXGehM>W=0{Ig^cVO%IvJH>|M!T zEi3Cnlz#C)4>MiSB{LEo9d_$M5zS~KTv{M?4gZ*V0wX^7c9k~C1w*cr5F7FYp2YRg zTJ6{X)`{>SZgy_C_aB_*2Bkug&&haUQ~g$yv?y9OP>aVBf>MR!+si5<8X<2cCP>lwb1S zgBJg7I~J>Vg3+&kCtcet;6wbG`zGV;&?|8B9RuGlpte8l7AnaLGls~j`hr`qcx|z? z$V3F@$7V`%^YX$zfvE89O+Db(Qk2lnR0w&V#H6fyNx=yBM^V}rXJ9(DsJH?*3(tLz z97z>0ge~a~ZeNA;Fh_^7<{eEY_(lD14jLID z(!Jvx?gmOocO8RZy_^)55~>+kDkhKrCq3=l^h*s3dL~(~bI1#SK;=Sm7;8K>bGV`B z(v4C4(8HQD`qOW*^tHzeXARp4ip`m7b!~iDH0oqB+{jJ%_Do!k{`(;IqpGxP<4^#e zPUVw-@lY0q_cDCrtr$np`Pqs>ffcbQZAfYRAqG7C!o%n@mX5p7`1Es~npbEa@HnD}}e+{mvD5@;63qZnwN_ z^b^S3UI@ZTo)iCoG+J`<-^I8r3vUh@yAopT99{A)Bd{iVrLG&VH3==(88>PBQP@u( z+q7RKZ^C08&G+S}Xd&7#MCZ^do z0*|NQ@bp`#(e)Q**GzF!D$~F-tGVa?luOOp zn@>Tk9b_LWK1m$-0cG{n$Lh4AKtWHNUsAYRm4?Ps7UPz;^We}#*>N5mow!^$;D{OQKpFMxC9&6Yh;YWgW9^<+ z$lc8l0cVjug00Q2TmPUNY9tuSCN#f`OwN8Y;QVg{%!-&E&A4C(?y{#f@&+YBgUEpo z7a#D!EydYbT-Y6$KT-98&o2lnz4P#tKC~x6w+9@85{wZOZ2$7$*f0USeDCS2=7p+; zPPkqidIY+<3toK=jRqW}Wz~x;r-0x~R<%t5AxNMOblRP}0CH;_Qt=z{V4})_vQ)4E zg$5O@$GEkD??*?z6Z=U(MY*f0E z_Mq^d`I~>^kMF4+Ir>w8@q*Vs z+UyP}O&H={Vj;s1Sq46N8*5M@&vt;c*9N%MJrM=z7a;dl>zSUeNWjTsB}Qstl4T?r zUfUw4Acc}qPrcWMpvn4-SHqwV3}BVst)=uyn6e<+<_qrVSFcJ-$FK>gsI?UPJGoct zlxY%TdAJ>!eEXIAz#j$3xujUqagGI$8aT*PC)jb(H7;5l{nt^MN@~_|#v8CYL@&gY zxe-KbElq|qzlHm~Zo8(PR^SzI%WL-KfSgUM%zUc(Q15z%M34C%E=#Rvd`og1t%*7c z@AKXQUU|`Ov@thv!awKJtc>aCKsdR@PlF6X--}j=QFxYrTXE=- zGxb9@g$8eSw3NRsc`3UTR5~_K&_V6xyaSZTgGi_kCNWA zKLMNWi@MpObeNRn%}hSBf`S#>&LA2EOKDC4*^sntx0(71?PCszas z*05{nw+Bqa&>MA6MzlL|eIF0@b<|WMy7l_TF?QKN@J+z@sC=;ad~5Se_&F<7!(g1( zWfB1%Vz1SG1T{h4?VUFlWul->kyqRL*&*0+)by0+0|1p)q%$0hZJ_6NV}aCu8jebJ z=3>3fi{}6E!nM&QB8yRB_8U&Opq<%Ycdv(1Ffmqgu69!kT662z+@VmxXBT&GlH^(Z zXN{KjM*UZ4NJ(7KZ}+qK;%aSSoq!T#6H%~zChw2U@WlvK;xJH3ZyS)la#X6YNJJc$ Ou#e?fblwUYKmI?xbJMv1 literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a20-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a20-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..13f09efe220021de2773c27ee369523921372a39 GIT binary patch literal 28656 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 B6Jh`W literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-b40-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-b40-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..9f892cea60fca0973352af9e08e409a104237777 GIT binary patch literal 15827 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 JffpnU{|9$^^Hl%< literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-d60-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-d60-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..2a47ab5354eb597843221123126712ab41253846 GIT binary patch literal 3349 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 bAY@*K3tc?AZ?6zb0KG_%_OY&oiY@;Fe{p$H literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2183-b60-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2183-b60-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..2a47ab5354eb597843221123126712ab41253846 GIT binary patch literal 3349 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 bAY@*K3tc?AZ?6zb0KG_%_OY&oiY@;Fe{p$H literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-fe-ds3000.fw b/package/lean/dvb/dvb-firmware/src/dvb-fe-ds3000.fw new file mode 100644 index 0000000000000000000000000000000000000000..e239559d9b4078e2a067d5b78bd9da6418e92703 GIT binary patch literal 8192 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 literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2141-a10-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2141-a10-01.fw new file mode 100644 index 0000000000000000000000000000000000000000..b7be881fb50087587f6d5aa9a8b2d826a1eb54c8 GIT binary patch literal 1666 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%0A(gpk=21m%yQf7L5q%t#m==kl zuu)Q5#MO-0nibdh#Wp1ROmwT&Y$dgKbb==jShFhijum^CoC3%28M!^*((vX-S%srX)@>Nt8?`!^uce zYL8}6$f_XiHZBjD41x_&jev5{zO4Q=>t9_mt&!0T6Z(@u)P`&t0f)NIU@SGzG6Rv& zsp7QDV7LubZ6F+a-5^Y%8w|n^8)ewL!(ccJZmb(&w5!mU ztp*$Li)NaPK)^o_brw0rNIjuLnkpv$SzKFef=fVUrRPR=%;aC%o^GAbT{|c4K;m{J zFCS&h;&Oz`rHPMXI2W__m~ilhHBCb15Ikhm0y%aFd$T#{X|%RXkFSn9_adZxX-9XnNs zxDVh*0BaF;#sCfhy#u0}2gm~y5O!GsYyf2dl}_&Q%4p1HcJD09*iWfa;Qh;RukVRKLKm$M{KofumfCpFs;00&~SPAeouvLx5P2*@Bk27g? zw|a_{Rl=qQ74d*S_4pt(u|kT9Wvp0^M8b+LB3fC|wp?_uqVsCe&5G3oRvdX`;e_Fb!y#-rfB9~soMsJbc57=jUqnj9Dgdcvv=oAYFldW z`0mt*W~J#pF2xe3TcZP?DZM*q$4$}9t`Mj2j|`^IoR}9M^WnnU^nnUiT+&S2K+X!6r2c`m(`85YLkg}_>$ zYzs8zK~Z4re+?v>C1JP!FbqG}YynKZ5uSYOjmTTd7u3n=e`V>b$CwH^yh;trkt@}R z#P^t|o5Qmi{#afo-sdk&ric02V@%}*#wo=RpF9KN9OzAc%>VmYRr&BYUCQ*YyOi8! zI=Pwt@;ZfwizEzA1WAY)4pzqF!?QrB;U^;LheCMxUSTF4kJFQSV=8tUzV~V9a(D62 zz#+{?p%?K5t(o7Vz^jUfcg%X|*|!6}P2m@A7Qb+>c;lU*bx~ff^`0t(nB5kuW>b3z zDRF+MXBYHyBn4`NMCQFrA^i={giH0zxKy528#9I19OW|KEUCQg=}Prw;>kJResDW2#!F;|!f6`uY6Qn_|2w!}~5rGhD~))D(V#%$Lzu2!xc zZL-4A)lYHJM%5x4T}AaJ7poh_zhq-Sx6kqt)EM-(%vsr|^-*X86nY+$3*@zaw6kUJ zsy&xM^QWm>?T&x z9}}B&{j};)d36P`Z_%5w@4eOB3VB5kbNqh3aJu8?()?Vyzo&2F?Cb=wU)5ttYto!Y z_DsdF|1Yo^+QnQ0H!l1ZUCi)SFR~Wg%vxorjZ^$Sz5N+cuPFMR>xOIoQDsNVh-r`I zg4@t(wK#J(=Rdl|`??wqk!#gRdbj|t9iRp&0nzTk*eNtuc!1`Be1kb$$eUMj>P*y@ELvC5ZXz+Yzh z&$F0X#MB{XIm6T=rU5ZfFCnBp9-V)23m2Ee*F}P7dHCCkO(vG*IJr^((>2A*ONzt` z>@$xKVodaZU+NM)0jcTK2u~`;aQP=&5w=hFo|u77_`iQ&y?^c{k4hORWuTOSQU*#H WC}p6Ofl>xa87O6-l!5;*1OEjm)R%ey literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2104.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2104.fw new file mode 100644 index 0000000000000000000000000000000000000000..b1fc1c95dbc3f4c7ebb617264c4c93af66eb13e4 GIT binary patch literal 8192 zcmeGfZERcB^}hSw^G81XaqXl@+I;xcE~IH1(-att4<}6-69TfuEeuNcM2p0j1lH!a zK|`90tuSb5d61y(&j!Pq)Mjlnb!k=l0bT-H#$fXjsj8-JeIP%(Woh#SxTG|(ciwx> z+LUVAPkz|adFR~obdUBZNYu9Opxb!H6ldm>dS#aT8(~M3J3C2p2%j%EvHBt^9KstQO>Ju8=c0 zWT-KKIM&X&*e`Da@#B2r1a~6I^MA11HD>w2IDhYZFv}`Ab6oL?Ua#o)L5ox0`;dz2XY+(*a6(;>Z%m zr|S+fGyua(FbpUG2oP8tCBXUuSnciY;aP)cQ*spZe~~j!D_tQ?r?O9i_7taK>uTcq z4$P?(_bZ7*{s2NxEJ@az)j1U9T47T1zR39>^l@t z15PL4hXJnxya{j@;70(j2fSG`%)ms>P#A}TSw4z2%0?N`=!m{W?<3?1;Lm7@=n>jM zoPlkb-s61?A$RD(6}Dx2JN40Z#QDwWVcL|Ivs*M!Ioikcr$EV+_y4V^afmohf`4;~ zhOV*Bgfg!yg1)(m%uYka8IUt?EB<^@c%43yL1xDM-!%D8ip~DKxYj=>J_(ow??u-g z#Q-sQ?)MUplSa${v%MXCxIaa2G17yOnI5Ds8q$NXnI6Ofz6-`2;4OMe5CV^=m+9lc zBV7)=`VM#iX@?Tw6Z%f-4s#UB0KODY3FCrZrx6J1q!+%n8~u45{mg$!=cT;jHm~?Y zF9gm*;I<=j<`^tk6ue@)e_nKZMZs^0+^v?$ncr(_IlWmW2IZlxYK1{nLKF^za?)C3 zONe{Juw}2cm-*z|_lT9}b=i!Z8P%}uU2Ho+$T=VgDd=C9Y|v@=%9$gIzhA8Lij7dw z_r8hJ?E$6mCQi5C4_loLO1nK!6|xa&e(A472;BCd;yd6Gb{LoBDz8+w_>q@RxNf%ZG?NF+X`VTU9gclqMDFYlJR6LnUYc{iIPkb zC)uPW30hAp!H>)I{gi?hTxQc5O&_gLgW$SJ&OW7#j#}WrLP-FN5i5(wSPEJ}Sq&O{ zY#;H8kC@a2{~YXg8Sl5j>cLy~skHXnRl}`&SC6#uZ7;`iapJgJ&OD>3ZI87WDpHV# zlG9gW8f;c_Ez&ARYRyWkLsA=(f-K#xwu~}HtdJ70R!o-%+IGjJI3f;73S#;_T?tCX zxMrjvq77<`KYyrg!A@=Q9%_T~T99AM58pUrgK%9^sI*c47NDU?d3 zVySpaStDmq)TSZ*f-aA;Cc#CiPCz;6U(WbijIW`Y)=4?TME`6OHBq}xz&Woq8FeOF zY9bOnQxtnlhSx+@Cc@EoO@fWyZ4x2aDAV6VCc|YSck~UD*lflmXJSRYZ6@CcW8Da& z-;Tj-75IRkoM|!_0`d8%yT~c7)E7Ohn_`c3acyx)J_(hTo*UUUli$BH-8w&g$DFha zNjs6cY?QG`%MdRAZ2a61o*uGwv$#A9^sCcD_U>}ER{Rm)K%DF8Pl5Nr^pGp`C=i>b zhe)>_gd2$SMY;(%%ch4O2z?8PebYk^cKbkdYt$8J$TjfQYV|0#jVvW@DpezC86(vo z+6RKL$94A?6N zT#f;^lU5A4DhAw@12)Hi-8p$?-Ki!y^SIJwhuYqxblt8=FS^HGn%v#9duDRS{udl_zDq=aiCL>2r@A$_B7+>`Uocya=* zG9`s~T;-||P;!FmYtQ*qp-MR5i{L8XeIifDpXhlZ$jlRKaEzfBNQDJgXqc2EOrS}S zK7b7fyN3Zj06GENUIS1IPzSIS0Jhar56}S62+#!J1JLyZfaL&wfB?V>fa?IR2himU z&RE?9`^W(uu9~7wa_vZloA2F+!ruV5BmU7@P$n7keR|{&5r!J}%BA5(#?R z=y1iBCG@-k?eY=9=_&Y&sn zT*}v|HKR>7IK9R}F8XjT^3ho|Uvjm%>HI4`4)FV|`{BGmd&^u@gL*54PC%jUG1K9^ z-ja5=3^(sx3B6}W>x-+?xi)A7=imjFeG*=Tqni1^S+H)uY&~OI?`ql0UbcOwq3i^7 ztn3y}Gu{(h4EuD>mlJZ!iQ|;fmxCXz;+Lz-BbXNs2!-?QuPO6$>E7;b;}>VgiR0(p z*0iq8`&8f55Dt9^CtSaqtKrgx-=e!2UhqZM6_>OAK*%*t3Hyu=Xs&vBG4AOuxaptK zcD0PKd##tlhGwg;bNasgx%>Tp&&8tTj$AxFSb)&-GyY!}&achrJscu|=gRiNcBD)V z(Pxnv8P9i>!GpTXruF}0J5MTxp}3+2Sn2mQqtc99OW5b#U$ratQaqt-Wh1o*tc~X* z{0M)56LhAs4YkgHa@!pJXF3n{R6jn%hAN-{iDN!7qe=Cw!RmHKHwNl+vGm$(EaVSw2%%^9GC(d%p5@$`ZSDQUb*U(=O*U}j9HxC3>66c5Ts`*m1dqs=i8u@HW zNauo6S4^NksSfEct4XHlnz;UWEfeB$UyFS?5Sup17G3lg)cObmr)Hy4NWfyNu3QqQ zePs>!tE|uhi>X0OEn=22Og&;65CioRMY-qY`QJRtC)C*bc;uo0e`YbuavaaAjmBTG zDM4LQB;Mp+eZC)KkJG51B}M`!&rXgA+Yzo9?m0EH=KuJ8{r=3CA}VE|lz~zPN*O3+ Wpp=1921*$yWuTOSQU?A<2L1z%>5fwX literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-dw3101.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw3101.fw new file mode 100644 index 0000000000000000000000000000000000000000..92d6b0e841e8d8109bcce7309c4c42a85570cc89 GIT binary patch literal 8192 zcmeGfZEzda@!iv%KKvm|PqJet@rN#Q+Tb`AHf^VTMRp9O!vJnA0)>#?kT9h%1Dc{M zV8`)8su@T~BCy)&kG6bhm?mk6OK{SBIH1}vV`xiNnW6d7HV5dWn2PucTyTgjb?;6g zcF1(5|M(%z?CrjNyZd(c?R)!#D}}um{cy$Mi#Usi*u^el;0mOVvGs_7i{nK?r9mkJ zr3`%aGC&xF5kme^mbn}u1|z1-Y;YK4!%c``P~vkNix4h=n1u^tn6+?^VbChh)Aj}P z4EF0{3?SBIV;!b$v>tV#R@9B|K|e(`rdv@jjN8!~tGE<(}F5sBEpXWn+eTz`<8 zJH*W#=H5NR-FB4Qbc~CPaq;8q@dU^H(R}^5`NtF7O>e*|b*00d!-UH`gz-j}@xvO4F^emr0TZaSLT2JUT?u=#FX zzf%G+;B*1L6Yx5~8vu6$z6 zeIrC&R*y3-&1-@nZ$y#Vu8Y{;jAmYyy!qm!QyWEL&hYt*G5Y z(QaqaI}BzA-GmgVV0f49?;OB`N&0O)HwYQIL0ZI+8-$JAAQRy0Vax*Fq~!x4u!#DZ z0TwJ$7vx6@vMHA0abQRkPw^AHR+K>#woJI;YvsWmKq2orjd$EF^tpxm-NFN2P5}0c z(abT3PT<`_hj(6Zx&_{A4&ES_MKiA`ayk8$OmxacTjdI!s-!DqyG~V6C}qe$ajxBK z-ec)!KK$;DLgi^~ZYG);Rj~DCY~4%9-+>@xTKhWsboy=hMl**c@1U^MEi^*;-t+=W zcQi|d7jU}c7T6CZO*zPvUx`z%R(wG&nt6`eiIerS0}RCjh&VowjAH|Gor+$0neE!f z>dWfp^FoamYhl7_N2O7Q8%O77k4nMS7hB7Nl`$zmU2yao3sRt}Et-iaQg@R=*V1nm zE!KgzmmB8T6rw9Nax)ehX!T-q)JoVVdMx0!)D0V_A*%2RDG^D86G<_N5-7nWaKe-@ zCqU{E$@hMlb__+I8QWBi(e&O**$1YZqS*(f(NQy;PACCjF+yeW%!)n>2+KZwk8Qtl z3wIgR2i`f@ZQI9QD?|_0vJa+}->u%;x@XNu8`rigtVT#>E}D5%k=yQR(M3cb2PLLO zVkm5s)E03yBerJ6HGZ)Ti9QqEDz}U>y04HD(3T97``dPg#RwwyI?;#e4>Tbt75z>T zeTX*5E#CaWw)1*&i~C?3l-K$BOWEPtDABwL+KO@%)8Lneb@LsTQ69JDX1f6e+=mrQG9G{c1cWDvC>n?}H)t}_@*4YbTa zBy_4c?J^i{163Ochh8@bQ|JbR@WVzK_U4E_T$JlG__`bGMi}iX z^ku8T2K=I#CL<8=&qJL>PBBtX=#Zw0$$u8t7MtJ_P+94@ksUMnm$s){=X2N2i93+E z9m&f_8MC+?;c{u>qZrP`tUV@N{tnR3K)Q&)x@%?)Y;S0mSqV(Z8<;=E6+LE>^otVMJc zNd7(-yVvgq!k>%X*HbPwIK(;zM5sxuLm(tBMdC7~?=zQV7woc+nJ1R|afY60Z*Rv= z6(a5f_z}Qbgq<;fLqP9xt0qp>A0uTTffE%E? zXh*XJ;Hm*w0#FN32e1@i831I_RS(br&qjA$X8pq>I zTHURlB4w4ZsX;|N;7>h12u-YzqGA~_gUy zAzS5;!#?D!q7_4qiXms^kkvk9t4f_(ccLkpxmW78!6Drsbzh^1Pddk+O6~03Ig{F! z+B?2GHKJK*dXG!7#Oc=Pz-LPD&e?HOG_xzjDf}aY=`$zh#m9WO^0%0rO%KOs0sN*j zl=;|t@>9A>;{+_;iphzN*8^4EO_LEn`{{bhTz}?dnwB$|wK|&oG)kUJZ)Jvsv3Mb{ z)+gHnjd@TM82euXiDpUI?LQ2|&ox^BlW&A4-+CkRmhuI4a{6Cc`sy*JLJqG|!*b+G zH6rmn=IQ3}Y=%FU*NOM}3zO+#e)bqsd4X|CF~ld&fH((wlOOZ{epXdJ{7siK{p&6z zx0z0EroX&S;o%|)gA+j#Vupj2@%Zp85Nh~|Ncy1=9==zYiO1vgq~4f{ordpy8oJzF zJT!1f^HJzUd_imGwex_OExI!??LCPIa0zrR$jor*2-6M3m%N~?9m{*E!*wT!Ek zYe$=`aCG%kT(nWO$VOLDeaXe@hVd`i*w5{=yaY7{y)AQA_Gx_-+5m-~$K(Qetsm`d z*}H1bWzcxGwLZBft+qiI_z2!w*$3e5H>wz~oAcTo7qn*#?Hw(9Oc!)tYbZMo?JB#8 zRrJTiCS5af=LF`xcSkjs_ z=aD^AG3@^fY=(9**T9VnzeN`_yw!`W1vj%+8EWGczfW&}M${{ce&@R3ntxQ;(K2G% zW4YiqbXqOW+|BuqZt=dZhC}39HIg1KfNS{~@AHMzS7fvX4xYeUWouz8lBQyG3o<-o zx$ZJ}I(J)@!GCP!h0cA|=&&OvJvEHP!da6R}o9oqZ`iiU?nNhg<;?suM ze-?7UdRmrX{Sj&+_OW84HX4*Bp*Y(xa87O7o|I5IC0s2#z!vFvP literal 0 HcmV?d00001 diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-tbsqbox-id5521.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-tbsqbox-id5521.fw new file mode 100644 index 0000000000000000000000000000000000000000..969a642b4b3a217f19ef1f56d6c4ce13d95071d8 GIT binary patch literal 8192 zcmeHKeQZfpsAv(C&I)kO|r`K z#P~=q_V_3ic#zO_YfCAnB(xftAQhCt$Q)=hHbLf09n-4unBIHgtMSv?m!@4~@7(v| z0Nbjqh<_&eS-*SFJNN7Och9}&JnYEf(hH)Rkb)8``Bax7UappcLsgK|%3uD*Cp^&84 zb0y`sEb_k$aQ*R14k%giF9QNPulr4#YN<`sqQiV%{(Nk0cun7@qkUY-yJ5RbdszcY zV6dYs^aswh=WfhWI-kx$XYNz{d+HUw1BLJH_6sv-jjFeiTCj`!sX(n#ugQ8n4Bu~; z8-YBn(7#=V=W= z{hp}4BL#9%-WzQUj72NFQ9fXcJ)w9+^{A$lkw=tChBTSXP|6Ldg7_8AkSa;FsGgAW zTxseJ+adc}=Gr&E9d!@Wwydc3XfQiwdpS=C1kUpeE!_tUd8Sd4aRb1^+oDz8XmtR` zmhZ=MV~v#G&&rL9$YV04mOLt|C#6Vhz79b_E}vFjOv*P|N?b001WJgg@KG*?f` z?fJ$%QZ5^KEkFE_x-+3Cr3hneO$v^Td2H~6QHh(2=c1DWn34iyoRE4LYZ`+LrqkEh zk~>~J2g`!pq_VOyGA%Df%4UgbQj?l|8u<}v;XFSL|G+rjIpd!{X)exYFoE0Tgw%qg z-yn1EaB_bhfO z(|ddtxWSF;t?8*bhhn4gg*U90Zs6KYREzY+;&BTV%aUzrwK>;zxcTC+FjDIpV)^#68Y<+1B_Z zXMFO@@lt2peK78I#;e|qPjSYp)s3a)8{HKfz1+sC%FLDd7k#3-QfhL-pP?9ptQfQ5zbGOuRj@LKVC|h$44&7#KmCNQSJ*7 z5ryPdragKxm5)3cRGg7%IT#paJQpIpHBz)IbR1qkqjLfJ&nEiMolTz8CZtPO|2jl| z%`xC02!+10>b@lmBv^bhBF%7-7b4-2hdgec!F^3=SFH z7^ql_ljSTCG!HeS87P8Qpyg;KDrkIY4*VL>Y?zmGpAv`Waqi!WL-T2=u9ljJMvp4X zxzCB}Pb5gm`u5a^D>(Og`kJG;#6epbxoY(FX@(v~g|xIi(*;u^{^q22WxDKk?Le1y z;d$*q?RgMq=J@Nc>e{uv^R%n4%+qePkp33(;sT8yNDd@`@fasC?J;*M)jkS>p4gI< zR|&X%Wi*>grN|{8a%DQ(23qZKe`Zk7V&(9gX-m*n$DwdIkhXE|dwdvD1jvwwAVa92_+F`3>rM71dI#bI z=tyU}D+AkFP95<`=fJ=~0$f5HkQxTF9cZ`%h04~U^(|aUPd4xwWK{WFc45?sP8+e?Dcill#*DGjD1R1g!OK{q72iYf;7ZfPHOnV z9=_Xqi0WH3!e=bw6EKBlSXWeiX1ZV`1T=ZlXAIuLJU9Tb52mh$@3?|d8Qb_wj>1f) zDdSr9KWcG78=2QUXHG+~dBM`z!5On34mLJ?4S_c*GbYk_RvUyM9#S5>O#}D3nT2tV zXRr%rA;c%ap@2;=`oTe-DiVD2#cabMd@Y*4hX3}wQGALF6d5QoP-LLUK#_qW14Rak Y3=|nCGEiio$Uu>SA_GMR?u>zd0w5EyEdT%j literal 0 HcmV?d00001 diff --git a/package/lean/dvb/libdvbcsa/Makefile b/package/lean/dvb/libdvbcsa/Makefile new file mode 100644 index 000000000..1bdb22213 --- /dev/null +++ b/package/lean/dvb/libdvbcsa/Makefile @@ -0,0 +1,57 @@ +# +# Copyright (C) 2014 nanpuyue +# Copyright (C) 2017 Tomasz Maciej Nowak +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +PKG_NAME := libdvbcsa +PKG_RELEASE := 1 + +PKG_SOURCE_PROTO := git +PKG_SOURCE_URL := https://github.com/glenvt18/libdvbcsa.git +PKG_SOURCE_VERSION := 2a1e61e569a621c55c2426f235f42c2398b7f18f + +PKG_VERSION := 1.1.0-$(shell printf '%.8s' $(PKG_SOURCE_VERSION)) +#PKG_SOURCE := $(PKG_NAME)-$(PKG_VERSION).tar.gz +#PKG_SOURCE_URL := http://download.videolan.org/pub/videolan/libdvbcsa/$(PKG_VERSION)/ +#PKG_HASH := 4db78af5cdb2641dfb1136fe3531960a477c9e3e3b6ba19a2754d046af3f456d + +PKG_LICENSE := GPL-2.0 +PKG_LICENSE_FILE := COPYING + +PKG_MAINTAINER := Tomasz Maciej Nowak + +PKG_INSTALL := 1 + +include $(INCLUDE_DIR)/package.mk + +define Package/libdvbcsa + SECTION := libs + CATEGORY := Libraries + TITLE := DVB Common Scrambling Algorithm library + URL := https://www.videolan.org/developers/libdvbcsa.html +endef + +define Package/libdvbcsa/description + libdvbcsa is a free implementation of the DVB Common Scrambling + Algorithm - DVB/CSA - with encryption and decryption capabilities +endef + +define Build/Configure + (cd $(PKG_BUILD_DIR); ./bootstrap) + $(call Build/Configure/Default) +endef + +define Build/InstallDev + $(CP) $(PKG_INSTALL_DIR)/usr $(1)/ +endef + +define Package/libdvbcsa/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libdvbcsa.so* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libdvbcsa)) diff --git a/package/lean/dvb/oscam/Makefile b/package/lean/dvb/oscam/Makefile new file mode 100755 index 000000000..f35f90be4 --- /dev/null +++ b/package/lean/dvb/oscam/Makefile @@ -0,0 +1,89 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=oscam +PKG_REV:=11402 +PKG_VERSION:=1.20-$(PKG_REV) +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_VERSION:=175e3c61ebf8df3611f980f88ff8b153c4f456d7 +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_URL:=http://repo.or.cz/oscam.git +PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.bz2 +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_MAINTAINER:=OSCam developers +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILES:=COPYING + + +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 + +include $(INCLUDE_DIR)/package.mk + +define Package/oscam + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libopenssl +libusb-1.0 +kmod-usb-serial +kmod-usb-serial-ch341 +kmod-usb-serial-ftdi +kmod-usb-serial-pl2303 +libpcsclite +pcscd +ccid + TITLE:=OSCam is an Open Source Conditional Access Module software + URL:=http://www.streamboard.tv/oscam/ +endef + +define Package/oscam/description + OSCam is an Open Source Conditional Access Module software, + based on the very good MpCS version 0.9d created by ​dukat. +endef + +define Package/oscam/conffiles +/etc/oscam/oscam.conf +/etc/oscam/oscam.server +/etc/oscam/oscam.user +/etc/oscam/SoftCam.Key +/etc/oscam/oscam.dvbapi +endef + +CONFIGURE_CMD = ./config.sh +CONFIGURE_ARGS = \ + --enable all + +MAKE_FLAGS += \ + CONF_DIR=/etc/oscam \ + OSCAM_BIN=Distribution/oscam \ + USE_SSL=1 \ + USE_LIBUSB=1 \ + USE_PCSC=1 \ + USE_LIBCRYPTO=1 + + +define Package/oscam/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/Distribution/oscam $(1)/usr/bin/oscam + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/oscam.init $(1)/etc/init.d/oscam + + $(INSTALL_DIR) $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.conf $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.server $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.user $(1)/etc/oscam + $(INSTALL_CONF) ./files/SoftCam.Key $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.dvbapi $(1)/etc/oscam + + +endef + + +define Package/$(PKG_NAME)/prerm + #!/bin/sh + # if run within buildroot exit + [ -n "$${IPKG_INSTROOT}" ] && exit 0 + + # stop running scripts + /etc/init.d/oscam disable + /etc/init.d/oscam stop + + exit 0 +endef + +$(eval $(call BuildPackage,oscam)) diff --git a/package/lean/dvb/oscam/files/SoftCam.Key b/package/lean/dvb/oscam/files/SoftCam.Key new file mode 100644 index 000000000..8a660e921 --- /dev/null +++ b/package/lean/dvb/oscam/files/SoftCam.Key @@ -0,0 +1,1462 @@ +# :::::::::: sat-life.info 17.06.2016 ::::::::::::::: +# <><><><><> by Serjoga latvia <><><><><><> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: NAGRA ::::::::: +#^^^^^^^^^^^^^^^^^^^^^^^ +::::::: UNity Media ::::::: +N 1102 00 F8780ECD862D143B9B23ECFFCBB872A4 ; UnityMedia Cable TV (german) +N 1102 01 FAD9E99827B3D66B624FA382E52615E1 ; UnityMedia Cable TV (german) +N 1102 M1 C75C2FECF494F6DD71BBF898C63F7FEBA11345DF14C71EE656 BC23016C2F90A881429B82A68C095E472C997752D5890341CF 9E06691672482718750B918AAE92 ; UnityMedia Cable TV (german) +#^^^^^^^^^^^^^^^^^^^^^^^^ +::::::: Cablecom Swiss Cable TV ::::::: +N 7301 00 950B684C48CAC1B9DBBCC03162FA4726 ;Cablecom Swiss Cable TV (Switzerland) +N 7301 01 FE0C200B4B1D3302CA107133D7771D79 ;Cablecom Swiss Cable TV (Switzerland) +N 7301 M1 7544E982065D53E7CF049AF2E725544A50268DA1462F15D8A197ECE4B80FE221122F92AD56324380A04878EBF563427DD85C38645907583E23AC5153E300CF84 ;Cablecom Swiss Cable TV (switzerland) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: IRDETO2 ::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +I 060400 02 2D265F5993B812E4A73BA29A2778BEC5 ### Bulsat 39.0E +I 060400 03 B3A283325BF7A18BA8B4084BFB5F9370 ### Bulsat 39.0E +I 060400 04 1E98FD1658E5414BC32E3D37775646DF ### Bulsat 39.0E +I 060400 06 78A6823BF854E0F8886FF60C0FAA6528 ### Bulsat 39.0E +I 060400 M1 98B4DCAD44E8C9504C3F4E51692A7047 ### Bulsat 39.0E +I 060400 M2 AE652B210BF89FC69507609842FD303E ### Bulsat 39.0E +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Viacess ::::::: +V 023800 08 955CF3C92800F39F54B93005DF826DBF , SSR/SRG Swiss (13.0E) +V 023800 D1 0B552C11AF0A2FB8 ; Des1_Key +V 023800 X1 3D1229C2ED29C130 ; XORArray +V 023800 P1 0304000207050106 ; PermArray +V 023800 C1 DA4E0B42134F433B ; ChainArray +V 023800 T1 495EE3839DD6544AF23FC1EC7C684D973CF873926F1CF0F586DA31A1156BA69A3461A28A965DCB2A5B932757B3D34640CF1A654C20A548C3E6B97DBD104363092FC89C3D67D82EAE3600075C330E8D946AE8AD5F06E7F42BB79FAC284B250153BE217A3EFD3291440D8F501DC5A8A7147BBBED12C4BF89DBDCD162700C3A95AFB4F6B103C6FB18DDC77623E4FC4EF169AA6613294F7E240FB59E1FAB42049959D91B22B6F9351E6E6DC2909B5A52477FC082FE2C8098A358D739DE71D23B6075B00AA937746C848841CAC926F7EAE230DF79BC2DEEF305B845A019777887BAD0FAE5CE028BE1385551EFCDFF0B72D4E9168E08D5561781CC11A4E0858C64B2EB1E84CC47F20C8155 ;TransformTable +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +V 007400 08 2FB60239D4D8C4D6 ;Mezzo 13E +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +V 021110 08 35F6B9217C2BA83F38C3C1FD23A5D321 ;Ant-1 Europe 9E +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +V 030B00 T1 7F308A9B0B803C4B6BBFEFB041F03B58E3BCAFBEE583B415A53571952BABE9A17964A8BA8BE4E053DB6AD5511C063739D81786DD92871BD7B718E7312DDC77F3DE1AD4FC60932909703D97B9688F2C5B6221F501D0894F995028A9FD4A3F9861F71F20AD030846CF546C44DF76C18D0078F607A0F17A2E32119FF4852F4913C2599E9623EB1924EDDA25FECAF894226533579DC3A39C0E56044882BD755AACFA26A6B3E80567ECB136E6FF4D107E8CB8AAE1EE8E5FC42A9A525DC702CD72B20F88D9437D16D65ECB406D144CF9745C127CC0C9A7A49069BB0DEAC8C563AE664ED26FB57B271D6E3ECEC645D3D142E238A2B63A340AFB73911E84CC47F20C8155 ; TransformTable +V 030B00 X1 8B2908AE39B0101A ;XORTABLE +V 030B00 P1 0704020305000601 ;PERMTABLE +V 030B00 C1 FC3C5F15D7A0B437 ;CW1XOR +V 030B00 08 D92A82E3111C9AFDED4626AD0B542E5B ;TNTSat +V 030B00 09 CC72AAFE5265D6D04608E832CEB9EC4D ;TNTSat +V 030B00 0A EE2679604A7DDD32E4F8CB913500D38E ;TNTSat +V 030B00 0B 7C6A2428C020023B163E4FE024FF5D9D ;TNTSat +V 030B00 E1 F627E52F1782BE037223B0D349E0361A ;AES KEY Decrypt +V 030B00 E2 EF3CB8D36A862097A33FC47101041BE3 ;TNTSat HD SurEncryption Key +V 030B00 E4 6B1B024D36F60974973CB81FA5E8F01C ;WB2 HD SurEncryption +V 030B00 E15 127003F8E95100367A556121C779FB6E ;TNT Sat HD +V 030B00 E17 1DE5B042AD670BB16A3A76BDAD2F7AC0 +V 030B00 EC 9A3EAB0203EBFFCA85B4F18280749F56 ;WB SurEncryption Key +V 030B00 ED 2504B382B16D8C6758DB960E311E9351 ;WB2 SurEncryption Key +V 030B00 EE 349883E54D58336DCA750A878ACC5CD5 ;WB2 SD SurEncryption +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::::: VideoGuard ::::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +S 090F 00 1585C5E4B852ECF7C3D908BA224A66F282154FB218486397DC19D8519A39FCCA1C24D065A9662DD6533B86BA40EA4C6DD91E4114FE15AFC318C5F8A7A8010001 ;Viasat (4.9E) +S 093E 00 1585C5E4B852ECF7C3D908BA224A66F282154FB218486397DC19D8519A39FCCA1C24D065A9662DD6533B86BA40EA4C6DD91E4114FE15AFC318C5F8A7A8010001 ;Viasat (4.9E) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::::: PowerVu ::::::::: +P 0011 00 437DD3B2A0A6D5 ;VTV HD 40.5W +P 0011 01 466B3B814138E1 ;VTV HD 40.5W +P 0013 00 437DD3B2A0A6D5 ;Gol TV HD 40.5W +P 0013 01 466B3B814138E1 ;Gol TV HD 40.5W +P 0017 00 437DD3B2A0A6D5 ;Gol TV Alternate 40.5W +P 0017 01 466B3B814138E1 ;Gol TV Alternate 40.5W + +P 9CA0 00 216447C54874C3 ;Discovery Showcase Europe HD 0.9W +P 9CA0 01 70F4D06DB57699 ;Discovery Showcase Europe HD 0.9W +P A8C0 00 216447C54874C3 ;ID Xtra Europe Russian HD 0.9W +P A8C0 01 70F4D06DB57699 ;ID Xtra Europe Russian HD 0.9W +P A8D0 00 216447C54874C3 ;ID Xtra Europe HD 0.9W +P A8D0 01 70F4D06DB57699 ;ID Xtra Europe HD 0.9W +P 5140 00 216447C54874C3 ;Historia Poland 0.9W +P 5140 01 70F4D06DB57699 ;Historia Poland 0.9W +P 5780 00 216447C54874C3 ;Discovery Iberia 0.9W +P 5780 01 70F4D06DB57699 ;Discovery Iberia 0.9W +P BB80 00 216447C54874C3 ;DTX 0.9W +P BB80 01 70F4D06DB57699 ;DTX 0.9W +P 9C60 00 216447C54874C3 ;Discovery Russia HD 0.9W +P 9C60 01 70F4D06DB57699 ;Discovery Russia HD 0.9W +P AF00 00 216447C54874C3 ;Discovery Poland HD 0.9W +P AF00 01 70F4D06DB57699 ;Discovery Poland HD 0.9W +P C830 00 216447C54874C3 ;Science Europe Russia HD 0.9W +P C830 01 70F4D06DB57699 ;Science Europe Russia HD 0.9W +P C850 00 216447C54874C3 ;Science Europe HD 0.9W +P C850 01 70F4D06DB57699 ;Science Europe HD 0.9W +P A2A0 00 216447C54874C3 ;Animal Planet Russia HD 0.9W +P A2A0 01 70F4D06DB57699 ;Animal Planet Russia HD 0.9W +P A290 00 216447C54874C3 ;Animal Planet Poland HD 0.9W +P A290 01 70F4D06DB57699 ;Animal Planet Poland HD 0.9W +P A2E0 00 216447C54874C3 ;Animal Planet HD 0.9W +P A2E0 01 70F4D06DB57699 ;Animal Planet HD 0.9W +P 0650 00 7F468E8B047CDE ;NBC Universal 0.9W +P 0650 01 679352FC3DEDF4 ;NBC Universal 0.9W + +P 0140 00 A25AE797314F61 ;HBO Hungary 4.0W +P 0140 01 4245667429DFEE ;HBO Hungary 4.0W +P 0020 00 A25AE797314F61 ;HBO Hungary 4.0W +P 0020 01 4245667429DFEE ;HBO Hungary 4.0W +P 0310 00 A25AE797314F61 ;HBO Comedy 4.0W +P 0310 01 4245667429DFEE ;HBO Comedy 4.0W +P 0330 00 A25AE797314F61 ;HBO Comedy Hungary/Czech 4.0W +P 0330 01 4245667429DFEE ;HBO Comedy Hungary/Czech 4.0W +P 0E90 00 A25AE797314F61 ;HBO Poland 4.0W +P 0E90 01 4245667429DFEE ;HBO Paland 4.0W +P 02A0 00 A25AE797314F61 ;HBO COMEDY HUNGARY, 4W +P 02A0 01 4245667429DFEE ;HBO COMEDY HUNGARY, 4W +P 0340 00 A25AE797314F61 ;HBO HUNGARY (AC3), 4W +P 0340 01 4245667429DFEE ;HBO HUNGARY (AC3), 4W +P 0CC0 00 A25AE797314F61 ;HBO 2 4.0W +P 0CC0 01 4245667429DFEE ;HBO 2 4.0W +P 00C9 00 A25AE797314F61 ;HBO2 HUNGARY, 4W +P 0C90 01 4245667429DFEE ;HBO2 HUNGARY, 4W +P 0CB0 00 A25AE797314F61 ;HBO2 OrigHu, 4W +P 0CB0 01 4245667429DFEE ;HBO2 OrigHu, 4W +P 0CA0 00 A25AE797314F61 ;HBO2 CZECH, 4W +P 0CA0 01 4245667429DFEE ;HBO2 CZECH, 4W +P 0E60 00 A25AE797314F61 ;Cinemax International 4.0W +P 0E60 01 4245667429DFEE ;Cinemax International 4.0W +P 0EC0 00 A25AE797314F61 ;Cinemax International 2 4.0W +P 0EC0 01 4245667429DFEE ;Cinemax International 2 4.0W +P 0F60 00 A25AE797314F61 ;Cinemax 2 International 4.0W +P 0F60 01 4245667429DFEE ;Cinemax 2 International 4.0W +P 0E70 00 A25AE797314F61 ;CINEMAX HUNGARY, 4W +P 0E70 01 4245667429DFEE ;CINEMAX HUNGARY, 4W +P 0F10 00 A25AE797314F61 ;CINEMAX 2 HUNGARY, 4W +P 0F10 01 4245667429DFEE ;CINEMAX 2 HUNGARY, 4W +P 0FB0 00 A25AE797314F61 ;CINEMAX 2 HUNGARY/Czech, 4W +P 0FB0 01 4245667429DFEE ;CINEMAX 2 HUNGARY/Czech, 4W +P 0F30 00 A25AE797314F61 ;CINEMAX 2 POLAND, 4W +P 0F30 01 4245667429DFEE ;CINEMAX 2 POLAND, 4W + +P 1FE0 00 B07EC58F412BD7 ;The Fight Network 15.0W +P 1FE0 01 A52E79D341F87F ;The Fight Network 15.0W + +P 00B0 00 6DADC79AAD00CF ;AFN Sports HD 9.0E +P 00B0 01 9E83D4513F3B23 ;AFN Sports HD 9.0E +P 0010 00 6DADC79AAD00CF ;AFN Sports 9.0E +P 0010 01 9E83D4513F3B23 ;AFN Sports 9.0E +P 0060 00 6DADC79AAD00CF ;AFN Sports 2 9.0E +P 0060 01 9E83D4513F3B23 ;AFN Sports 2 9.0E +P 0020 00 6DADC79AAD00CF ;AFN Prime Atlantic 9.0E +P 0020 01 9E83D4513F3B23 ;AFN Prime Atlantic 9.0E +P 0070 00 6DADC79AAD00CF ;Guide 9.0E +P 0070 01 9E83D4513F3B23 ;Guide 9.0E +P 0030 00 6DADC79AAD00CF ;Spectrum 9.0E +P 0030 01 9E83D4513F3B23 ;Spectrum 9.0E +P 0050 00 6DADC79AAD00CF ;News 9.0E +P 0050 01 9E83D4513F3B23 ;News 9.0E +P 0040 00 6DADC79AAD00CF ;Pacific 9.0E +P 0040 01 9E83D4513F3B23 ;Pacific 9.0E +P 0090 00 6DADC79AAD00CF ;Fam/Pulse 9.0E +P 0090 01 9E83D4513F3B23 ;Fam/Pulse 9.0E +P 00A0 00 6DADC79AAD00CF ;Movie 9.0E +P 00A0 01 9E83D4513F3B23 ;Movie 9.0E +P 06B0 00 6DADC79AAD00CF ;Decoder Expired 9.0E +P 06B0 01 9E83D4513F3B23 ;Decoder Expired 9.0E +P 0630 00 6DADC79AAD00CF ;Download 9.0E +P 0630 01 9E83D4513F3B23 ;Download 9.0E + +P 02C0 00 0123456789ABCD ;Snai Virtuali 1 16E +P 02C0 01 97D6968EEC34A3 ;Snai Virtuali 1 16E +P 0370 00 0123456789ABCD ;CH 55 Virtuali 3 16E +P 0370 01 97D6968EEC34A3 ;CH 55 Virtuali 3 16E + +#______________________12303 H 25548__________________________________ +P 2620 00 3AAB2C9D1A23BB ;DIVA Romania 4.9E +P 2620 01 01104AD73016C3 ;DIVA Romania 4.9E +P 1650 00 3AAB2C9D1A23BB ;CN TCM Russia 4.9E +P 1650 01 01104AD73016C3 ;CN TCM Russia 4.9E +P 1640 00 3AAB2C9D1A23BB ;CN/TCM RSEE 4.9E +P 1640 01 01104AD73016C3 ;CN/TCM RSEE 4.9E +P 26C0 00 3AAB2C9D1A23BB ;Universal Croatia-Slovenia 4.9E +P 26C0 01 01104AD73016C3 ;Universal Croatia-Slovenia 4.9E + +#______________________12322 V 27500__________________________________ +P 44C0 00 CBC3ECF15309C6 ;Discovery Turkey HD 4.9E +P 44C0 01 C19C56769B52AA ;Discovery Turkey HD 4.9E +P 1F40 00 CBC3ECF15309C6 ;Discovery Science Polska 4.9E +P 1F40 01 C19C56769B52AA ;Discovery Science Polska 4.9E +P 0640 00 CBC3ECF15309C6 ;Animal Planet Europe 4.9E +P 0640 01 C19C56769B52AA ;Animal Planet Europe 4.9E +P 0C80 00 CBC3ECF15309C6 ;Discovery central Europe 4.9E +P 0C80 01 C19C56769B52AA ;Discovery central Europe 4.9E +P 12D0 00 CBC3ECF15309C6 ;ID Europe 4.9E +P 12D0 01 C19C56769B52AA ;ID Europe 4.9E +P 1900 00 CBC3ECF15309C6 ;ID Extra Europe 4.9E +P 1900 01 C19C56769B52AA ;ID Extra Europe 4.9E +P 3850 00 CBC3ECF15309C6 ;Science Europe 4.9E +P 3850 01 C19C56769B52AA ;Science Europe 4.9E +P 1F40 00 CBC3ECF15309C6 ;Discovery World 4.9E +P 1F40 01 C19C56769B52AA ;Discovery World 4.9E +P 3E80 00 CBC3ECF15309C6 ;Discovery World 4.9E +P 3E80 01 C19C56769B52AA ;Discovery World 4.9E + +#______________________12360 V 27500_______________________________ +P 125C 00 216447C54874C3 ;Eurosport 2 Wimbledon HD 4.9E +P 125C 01 70F4D06DB57699 ;Eurosport 2 Wimbledon HD 4.9E +P 7080 00 216447C54874C3 ;Science Poland HD 4.9E +P 7080 01 70F4D06DB57699 ;Science Poland HD 4.9E +P 6A40 00 216447C54874C3 ;Animal Planet Poland HD 4.9E +P 6A40 01 70F4D06DB57699 ;Animal Planet Poland HD 4.9E +P C1C0 00 216447C54874C3 ;TLC Poland HD 4.9E & 0.9W +P C1C0 01 70F4D06DB57699 ;TLC Poland HD 4.9E & 0.9W +P 2BC0 00 216447C54874C3 ;Discovery Bulgaria 4.9E +P 2BC0 01 70F4D06DB57699 ;Discovery Bulgaria 4.9E +P B540 00 216447C54874C3 ;TLC Pan Regional 4.9E +P B540 01 70F4D06DB57699 ;TLC Pan Regional 4.9E +P 2580 00 216447C54874C3 ;Turbo Xtra Poland 4.9E +P 2580 01 70F4D06DB57699 ;Turbo Xtra Poland 4.9E +P 8340 00 216447C54874C3 ;ID Poland 4.9E +P 8340 01 70F4D06DB57699 ;ID Poland 4.9E +P 6400 00 216447C54874C3 ;ID Sweden 4.9E +P 6400 01 70F4D06DB57699 ;ID Sweden 4.9E +P 3200 00 216447C54874C3 ;TLC Balcans 4.9E +P 3200 01 70F4D06DB57699 ;TLC Balcans 4.9E +P 12C0 00 216447C54874C3 ;Discovery Channel Romania 4.9E +P 12C0 01 70F4D06DB57699 ;Discovery Channel Romania 4.9E +P 3840 00 216447C54874C3 ;Discovery Ukraine 4.9E +P 3840 01 70F4D06DB57699 ;Discovery Ukraine 4.9E +P 5DC0 00 216447C54874C3 ;Discovery Life Poland 4.9E +P 5DC0 01 70F4D06DB57699 ;Discovery Life Poland 4.9E +#______________________________________________________ +P 0930 00 C56B7706315E3F ;New Boyles Sport 4.9E +P 0930 01 DD51BECAA44C1F ;New Boyles Sport 4.9E +P 0350 00 C56B7706315E3F ;William Hill 4.9E +P 0350 01 DD51BECAA44C1F ;William Hill 4.9E +P 0560 00 C56B7706315E3F ;SIS 2 4.9E +P 0560 01 DD51BECAA44C1F ;SIS 2 4.9E +P 0170 00 C56B7706315E3F ;Coral TV2 4.9E +P 0170 01 DD51BECAA44C1F ;Coral TV2 4.9E +P 0420 00 C56B7706315E3F ;Ladbrokes 1 4.9E +P 0420 01 DD51BECAA44C1F ;Ladbrokes 1 4.9E + +P 0650 00 2E40E327BB7837 ;MTN Worldwide TV (34.5W & 47.5W & 57.0 & 20W) +P 0650 01 FFFA91E97B2570 ;MTN Worldwide TV (34.5W & 47.5W & 57.0 & 20W) + +P 0020 00 5A5E959C3743B7 ;SET Asia 66E +P 0020 01 C367E0F812D1DE ;SET Asia 66E +P 0050 00 5A5E959C3743B7 ;SET Middle East 66E +P 0050 01 C367E0F812D1DE ;SET Middle East 66E +P 0060 00 5A5E959C3743B7 ;Sony Max Asia 66E +P 0060 01 C367E0F812D1DE ;Sony Max Asia 66E +P 0070 00 5A5E959C3743B7 ;Sony Max UK 66E +P 0070 01 C367E0F812D1DE ;Sony Max UK 66E +P 0090 00 5A5E959C3743B7 ;Sony SAB TV Asia 66E +P 0090 01 C367E0F812D1DE ;Sony SAB TV Asia 66E +P 00A0 00 5A5E959C3743B7 ;Max Middle East 66E +P 00A0 01 C367E0F812D1DE ;Max Middle East 66E +P 00D0 00 5A5E959C3743B7 ;Sony Six 66E +P 00D0 01 C367E0F812D1DE ;Sony Six 66E +P 0320 00 5A5E959C3743B7 ;Sony Six HD 66E +P 0320 01 C367E0F812D1DE ;Sony Six HD 66E +P 0330 00 5A5E959C3743B7 ;SET Asia HD 66E +P 0330 01 C367E0F812D1DE ;SET Asia HD 66E +P 0340 00 5A5E959C3743B7 ;PIX HD 66E +P 0340 01 C367E0F812D1DE ;PIX HD 66E +P 0350 00 5A5E959C3743B7 ;AXN SA HD 66E +P 0350 01 C367E0F812D1DE ;AXN SA HD 66E +P 0360 00 5A5E959C3743B7 ;MAX SA HD 66E +P 0360 01 C367E0F812D1DE ;MAX SA HD 66E +P 0370 00 5A5E959C3743B7 ;Sony ESPN HD 66E +P 0370 01 C367E0F812D1DE ;Sony ESPN HD 66E +P 0420 00 5A5E959C3743B7 ;MAX INTERNATIONL 66E +P 0420 01 C367E0F812D1DE ;MAX INTERNATIONL 66E +P 0CA0 00 5A5E959C3743B7 ;SET INTERNATIONL 66E +P 0CA0 01 C367E0F812D1DE ;SET INTERNATIONL 66E +P 0FF0 00 5A5E959C3743B7 ;SOFTWAR 66E +P 0FF0 01 C367E0F812D1DE ;SOFTWAR 66E + +P 0150 00 113754C6C0CEE1 ;AS7 SD 1 (105.5E) +P 0150 01 00000000000000 ;AS7 SD 1 (105.5E) +P 0160 00 113754C6C0CEE1 ;AS7 SD 2 (105.5E) +P 0160 01 00000000000000 ;AS7 SD 2 (105.5E) +P 0170 00 113754C6C0CEE1 ;AS7 SD 3 (105.5E) +P 0170 01 00000000000000 ;AS7 SD 3 (105.5E) +P 0180 00 113754C6C0CEE1 ;AS7 SD 4 (105.5E) +P 0180 01 00000000000000 ;AS7 SD 4 (105.5E) +P 0470 00 113754C6C0CEE1 ;AS7 HD 1 (105.5E) +P 0470 01 00000000000000 ;AS7 HD 1 (105.5E) +P 0480 00 113754C6C0CEE1 ;AS7 HD 2 (105.5E) +P 0480 01 00000000000000 ;AS7 HD 2 (105.5E) +P 0490 00 113754C6C0CEE1 ;AS7 HD 3 (105.5E) +P 0490 01 00000000000000 ;AS7 HD 3 (105.5E) +P 04A0 00 113754C6C0CEE1 ;AS7 HD 4 (105.5E) +P 04A0 01 00000000000000 ;AS7 HD 4 (105.5E) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::::: BISS ::::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^ +F 0009002D 00 764924E3510382D6 ;TEST (4.0W) +F 0009002D 01 764924E3510382D6 ;TEST (4.0W) +F 00050101 00 764924E3510382D6 ;FilmUaDrama (4.0W) +F 00050101 01 764924E3510382D6 ;FilmUaDrama (4.0W) +F 00060101 00 764924E3510382D6 ;FilmUAction (4.0W +F 00060101 01 764924E3510382D6 ;FilmUAction (4.0W) +F 00050501 00 123ABC08123ABC08 ;EuroNews (4.0W) +F 00050501 01 123ABC08123ABC08 ;EuroNews (4.0W) +F 00090901 00 AABBCC31CCBBAA31 ;NTV Mir (Amos 4W) +F 00090901 01 AABBCC31CCBBAA31 ;NTV Mir (Amos 4W) +F 00040401 00 107220A215050721 ;TV Kiev (Amos 4W) +F 00040401 01 107220A215050721 ;TV Kiev (Amos 4W) +F 00080801 00 AC1234F24321CA2E ;Inter (Amos 4W) +F 00080801 01 AC1234F24321CA2E ;Inter (Amos 4W) +F 00090901 00 1234AC001234AC00 ;INTER+ (4.0W) +F 00090901 01 1234AC001234AC00 ;INTER+ (4.0W) +F 00010101 00 AC1234004321CA00 ;Inter (4.0W) +F 00010101 01 AC1234004321CA00 ;Inter (4.0W) +F 00030301 00 654321C91234569C ;1+1Plus (4.0W) +F 00030301 01 654321C91234569C ;1+1Plus (4.0W) +F 00040401 00 1231236612312366 ;Mega (4.0W) +F 00040401 01 1231236612312366 ;Mega (4.0W) +F 00050501 00 130419308313049A ;Test (4.0W ) +F 00050501 01 130419308313049A ;Test (4.0W ) +F 000C1201 00 198313AF041983A0 ;Test 2 (4.0W) +F 000C1201 01 198313AF041983A0 ;Test 2 (4.0W) +F 000D0131 00 1006102611071129 ;Pershiy (4.0W) +F 000D0131 01 1006102611071129 ;Pershiy (4.0W) +F 000C0C01 00 1A2B3C81C3B2A116 ;Trofey (4.0W) +F 000C0C01 01 1A2B3C81C3B2A116 ;Trofey (4.0W) +F 00010501 00 1234569C654321C9 ;Unian TV (4W) +F 00010501 01 1234569C654321C9 ;Unian TV (4W) +F 000808C0 00 2222226622222266 ;TV 1 Bosnia (4W) +F 000808C0 01 2222226622222266 ;TV 1 Bosnia (4W) + +F 0028008D 00 A1B2C316D4E5F8B1 ;ERT Digital - ERT HD (3.0E) +F 0028008D 01 A1B2C316D4E5F8B1 ;ERT Digital - ERT HD (3.0E) +F 0014008B 00 A1B2C316D4E5F8B1 ;ERT Digital - ET2 (3.0E) +F 0014008B 01 A1B2C316D4E5F8B1 ;ERT Digital - ET2 (3.0E) +F 0023008E 00 A1B2C316D4E5F8B1 ;ERT Digital - ET3 (3.0E) +F 0023008E 01 A1B2C316D4E5F8B1 ;ERT Digital - ET3 (3.0E) +F 000A008A 00 A1B2C316D4E5F8B1 ;ERT Digital - ET1 (3.0E) +F 000A008A 01 A1B2C316D4E5F8B1 ;ERT Digital - ET1 (3.0E) +F 0064047E 00 1111113311111133 ;ALPHA TV Greece (3.0E) +F 0064047E 01 1111113311111133 ;ALPHA TV Greece (3.0E) +F 015E0550 00 1111113311111133 ;ART (3.0E) +F 015E0550 01 1111113311111133 ;ART (3.0E) +F 0320073A 00 1111113311111133 ;ETV (3.0E) +F 0320073A 01 1111113311111133 ;ETV (3.0E) +F 02580672 00 1111113311111133 ;Skai (3.0E) +F 02580672 01 1111113311111133 ;Skai (3.0E) +F 02BC06D7 00 1111113311111133 ;Star Channel (3.0E) +F 02BC06D7 01 1111113311111133 ;Star Channel (3.0E) +F 01F4060E 00 1111113311111133 ;Mega Channel (3.0E) +F 01F4060E 01 1111113311111133 ;Mega Channel (3.0E) +F 019005AA 00 1111113311111133 ;Macedonia TV (3.0E) +F 019005AA 01 1111113311111133 ;Macedonia TV (3.0E) +F 012C0546 00 1111113311111133 ;ANT 1 (3.0E) +F 012C0546 01 1111113311111133 ;ANT 1 (3.0E) + +F 1A131A14 00 1122336633221166 ;XSport (4.9E) +F 1A131A14 01 1122336633221166 ;XSport (4.9E) +F 17ED17EE 00 1A2B3CAC4D5E6F0B ;1+1 Internetional (4.9E) +F 17ED17EE 01 1A2B3CAC4D5E6F0B ;1+1 Internetional (4.9E) +F 182E182F 00 5EB22B2576F5016 ;Ukraina-SD (4.9E) +F 182E182F 01 5EB22B2576F5016 ;Ukraina-SD (4.9E) +F 19D219D3 00 A5EB22B2576F5016 ;TRK Ukraina (4.9E) +F 19D219D3 01 A5EB22B2576F5016 ;TRK Ukraina (4.9E) +F 1A0E1A0F 00 A5EB2200576F7500 ;34 Telekanal (4.9E) +F 1A0E1A0F 01 A5EB2200576F7500 ;34 Telekanal (4.9E) +F 1A181A19 00 A5EB22B2576F25EB ;NLO TV (4.9E) +F 1A181A19 01 A5EB22B2576F25EB ;NLO TV (4.9E) +F 1A221A23 00 A5EB22B2576F25EB ;Indigo (4.9E) +F 1A221A23 01 A5EB22B2576F25EB ;Indigo (4.9E) +F 1B4E1B4F 00 1234AC001234AC00 ;Inter+ (4.9E) +F 1B4E1B4F 01 1234AC001234AC00 ;Inter+ (4.9E) +F 17DE17DF 00 19090628117660E7 ;TET (4.9E) +F 17DE17DF 01 19090628117660E7 ;TET (4.9E) + +F 00010100 00 AABB127734CCDDDD ;Fox Sport Europe (7E) +F 00010100 01 AABB127734CCDDDD ;Fox Sport Europe (7E) +F 00320802 00 C7B2A51ED4E3F1A8 ;Mena Media Feed (7E) +F 00320802 01 C7B2A51ED4E3F1A8 ;Mena Media Feed (7E) +F 00030202 00 1FD100F000000000 ;EVN-TV ( EVN EVNTV EVN TV / EUROVISION TV / EURO VISION NEWS ) (7E) +F 00030202 01 1FD100F000000000 ;EVN-TV ( EVN EVNTV EVN TV / EUROVISION TV / EURO VISION NEWS ) (7E) + +F 03E60BB6 00 1A2B3C814D5E6F1A ;TEST 4 (9.0E) +F 03E60BB6 01 1A2B3C814D5E6F1A ;TEST 4 (9.0E) +F 03E70BB7 00 1A2B3C814D5E6F1A ;TEST 8 (9.0E) +F 03E70BB7 01 1A2B3C814D5E6F1A ;TEST 8 (9.0E) +F 027211F9 00 E876F04E8BA51141 ;EFB1 (9.0E) +F 027211F9 01 E876F04E8BA51141 ;EFB1 (9.0E) +F 042101C9 00 1111113322222266 ;ODIE (9.0E) +F 042101C9 01 1111113322222266 ;ODIE (9.0E) +F 002E07FE 00 E876F04E8BA51141 ;Eurofootball Gonki (9.0E) +F 002E07FE 01 E876F04E8BA51141 ;Eurofootball Gonki (9.0E) +F 002D07FD 00 C0379C93E08FBB2A ;Monitor Games (9.0E) +F 002D07FD 01 C0379C93E08FBB2A ;Monitor Games (9.0E) +F 00370807 00 E876F04E8BA51141 ;Opap TV (9.0E) +F 00370807 01 E876F04E8BA51141 ;Opap TV (9.0E) +F 00130731 00 2000ABCBCD2000ED ;Sat2000 (9.0E) +F 00130731 01 2000ABCBCD2000ED ;Sat2000 (9.0E) + +F 00020B0F 00 6C37BA5D492D7EF4 ;BARAEM (10E) +F 00020B0F 01 6C37BA5D492D7EF4 ;BARAEM (10E) +F 00010B07 00 6C37BA5D492D7EF4 ;JEEM SD (10E) +F 00010B07 01 6C37BA5D492D7EF4 ;JEEM SD (10E) +F 00030B19 00 6C37BA5D492D7EF4 ;JEEM HD (10E) +F 00030B19 01 6C37BA5D492D7EF4 ;JEEM HD (10E) +F 00080202 00 F8C5A966EBA461F0 ;NBA TV (10.0E) +F 00080202 01 F8C5A966EBA461F0 ;NBA TV (10.0E) +F 00010191 00 F87384EF72A4CDE3 ;NBA TV HD (10.0E) +F 00010191 01 F87384EF72A4CDE3 ;NBA TV HD (10.0E) +F 000E0579 00 2557AC28CE25574B ;Barca Tv (10.0E) +F 000E0579 01 2557AC28CE25574B ;Barca Tv (10.0E) +F 00070201 00 2EEA2E46FE9E59F5 ;NBA-ADHOC (10.0E) +F 00070201 01 2EEA2E46FE9E59F5 ;NBA-ADHOC (10.0E) +F 00020201 00 AE7B80A9F968AF10 ;NBA POOL EUROPE 1 (10.0E) +F 00020201 01 AE7B80A9F968AF10 ;NBA POOL EUROPE 1 (10.0E) +F 00040259 00 E6CC37E9DB183A2D ;IMG A Europe (10.0E) +F 00040259 01 E6CC37E9DB183A2D ;IMG A Europe (10.0E) +F 000301F5 00 AA8B5F9427006F96 ;USRSC Europe ESPN (10E) +F 000301F5 01 AA8B5F9427006F96 ;USRSC Europe ESPN (10E) +F 00050191 00 23B8EEC92B6534C4 ;Chelsea TV (10.0E) +F 00050191 01 23B8EEC92B6534C4 ;Chelsea TV (10.0E) +F 00060259 00 11C4461BCE347A7C ;Premier League HD (10.0E) +F 00060259 01 11C4461BCE347A7C ;Premier League HD (10.0E) +F 000107D1 00 205976EF823DB574 ;MUTV (9.0E-10.0E ) +F 000107D1 01 205976EF823DB574 ;MUTV (9.0E-10.0E ) +F 007B03E9 00 3D10CB184EEC7DB7 ;Service-123HD (10.0E) +F 007B03E9 01 3D10CB184EEC7DB7 ;Service-123HD (10.0E) +F 01C80FA1 00 D05FC9F85131B537 ;Service-456HD (10.0E) +F 01C80FA1 01 D05FC9F85131B537 ;Service-456HD (10.0E) +F 000307F8 00 0000232301151026 ;Sahar 1 (10.0E) +F 000307F8 01 0000232301151026 ;Sahar 1 (10.0E) +F 00040816 00 0000232301151026 ;Sahar 2 (10.0E) +F 00040816 01 0000232301151026 ;Sahar 2 (10.0E) +F 00031004 00 159ACD7CEBF614F5 ;MGM ME (10.0E) +F 00031004 01 159ACD7CEBF614F5 ;MGM ME (10.0E) +F 0001012C 00 1234569C789FFF16 ;Sharqiya News (10.0E) +F 0001012C 01 1234569C789FFF16 ;Sharqiya News (10.0E) +F 0002076E 00 0000232301151026 ;Alalam News Channel (10.0E) +F 0002076E 01 0000232301151026 ;Alalam News Channel (10.0E) +F 0005080C 00 0000232301151026 ;Al Kawthar (10.0E) +F 0005080C 01 0000232301151026 ;Al Kawthar (10.0E) +F 00011023 00 0000232301151026 ;iFilm (10.0E) +F 00011023 01 0000232301151026 ;iFilm (10.0E) +F 002A0021 00 2301234701230125 ;DEFUALT (10.0E) +F 002A0021 01 2301234701230125 ;DEFUALT (10.0E) +F 00010032 00 0204757B6840751D ;ORTC (10.0E) +F 00010032 01 0204757B6840751D ;ORTC (10.0E) + +F 2A2F006E 00 1A2B3C814D5E6F1A ;TEST 6 (13.0E) +F 2A2F006E 01 1A2B3C814D5E6F1A ;TEST 6 (13.0E) +F 00030028 00 CA50B7D131D6585F ;Al Aoula Maroc (13.0E) +F 00030028 01 CA50B7D131D6585F ;Al Aoula Maroc (13.0E) +F 34D2052A 00 1A2B3C814D5E6F1A ;1+1 International (13.0E) +F 34D2052A 01 1A2B3C814D5E6F1A ;1+1 International (13.0E) + +F 00010134 00 124578CF875421FC ;SIC International (16E) +F 00010134 01 124578CF875421FC ;SIC International (16E) +F 00100121 00 2016013727BAFFE0 ;Kombat Sport (16E) +F 00100121 01 2016013727BAFFE0 ;Kombat Sport (16E) +F 00010310 00 BC33584706679502 ;EUTELSAT 16A S3-01 (16E) +F 00010310 01 BC33584706679502 ;EUTELSAT 16A S3-01 (16E) +F 03FA070A 00 9E186D23B5A74CA8 ;HNL (16E) +F 03FA070A 01 9E186D23B5A74CA8 ;HNL (16E) +F 00160201 00 CDEF12CE5678905E ;National 24 Plus (16.0E) +F 00160201 01 CDEF12CE5678905E ;National 24 Plus (16.0E) +F 000A0101 00 458825F27453682F ;National TV (16.0E) +F 000A0101 01 458825F27453682F ;National TV (16.0E) +F 00010064 00 C48DAF008FDA9700 ;Kanal D1 (16.0E) +F 00010064 01 C48DAF008FDA9700 ;Kanal D1 (16.0E) +F 00C80200 00 71F0F0519D8C234C ;SRTV Feed (16.0E) +F 00C80200 01 71F0F0519D8C234C ;SRTV Feed (16.0E) +F 000E00FD 00 1111113311111133 ;Test HD (16.0E) +F 000E00FD 01 1111113311111133 ;Test HD (16.0E) +F 00010200 00 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) +F 00010200 01 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) +F 00020201 00 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) +F 00020201 01 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) + +F 000D0191 00 12312366456456FF ;STN Test Transcode - [ TRACE Africa ] (19.2E) +F 000D0191 01 12312366456456FF ;STN Test Transcode - [ TRACE Africa ] (19.2E) +F 00130192 00 12312366456456FF ;STN Test Remux - [ MA CHAINE SPORT Extreme ] (19.2E) +F 00130192 01 12312366456456FF ;STN Test Remux - [ MA CHAINE SPORT Extreme ] (19.2E) + +F 007F04F6 00 1A1B1C511D1E1F5A ;Sahar University Network 1 (20.0E) +F 007F04F6 01 1A1B1C511D1E1F5A ;Sahar University Network 1 (20.0E) +F 00750492 00 1111113311111133 ;IRIB Varzesh (20.0E) +F 00750492 01 1111113311111133 ;IRIB Varzesh (20.0E) + +F 00070301 00 A9E746D68358E5C0 ;Topaz 1 (21.5E) +F 00070301 01 A9E746D68358E5C0 ;Topaz 1 (21.5E) + +F 000103E9 00 ACDE109A0616BCD8 ;MBC MASR FEED (21.6E) +F 000103E9 01 ACDE109A0616BCD8 ;MBC MASR FEED (21.6E) + +F 4E860838 00 917CA5B26B78D2B5 ;Majd feed (26.0E) +F 4E860838 01 917CA5B26B78D2B5 ;Majd feed (26.0E) +F 000501FE 00 1111224422333388 ;TV 5 (26.0E) +F 000501FE 01 1111224422333388 ;TV 5 (26.0E) +F 00290429 00 1212123612121236 ;Drama USA (26E) +F 00290429 01 1212123612121236 ;Drama USA (26E) +F 00140250 00 1234569C789ABCCE ;Nilesat promo (26E) +F 00140250 01 1234569C789ABCCE ;Nilesat promo (26E) + +F 00010064 00 21CD07F51168017A ;ERI TV Earth (30.5E) +F 00010064 01 21CD07F51168017A ;ERI TV Earth (30.5E) +F 012F03EB 00 1111113311111133 ;IRIB TV 3 (30.5E) +F 012F03EB 01 1111113311111133 ;IRIB TV 3 (30.5E) + +F 0FA000A3 00 A4D352C91B6C28AF :SES Test(31E) +F 0FA000A3 01 A4D352C91B6C28AF :SES Test(31E) + +F 1C3E1C3F 00 1111113311111133 ;BTB (31.5E) +F 1C3E1C3F 01 1111113311111133 ;BTB (31.5E) +F 1C341C35 00 1111113311111133 ;BTB (31.5E) +F 1C341C35 01 1111113311111133 ;BTB (31.5E) + +F 00020055 00 1111113311111133 ;Armenia 1 TV (36E) +F 00020055 01 1111113311111133 ;Armenia 1 TV (36E) +F 0A100682 00 1AEF010A0EDEF1DD ;Armenia TV Region (36E) +F 0A100682 01 1AEF010A0EDEF1DD ;Armenia TV Region (36E) + +F 000202C7 00 1111113311111133 ;Kentron TV (39E) +F 000202C7 01 1111113311111133 ;Kentron TV (39E) + +F 00640065 00 0327022C106251C3 ;GTRK Nizhny Novgorod (40E) +F 00640065 01 0327022C106251C3 ;GTRK Nizhny Novgorod (40E) +F 00010134 00 0327022C106251C3 ;GTRK Package (40E) +F 00010134 01 0327022C106251C3 ;GTRK Package (40E) +F 00010021 00 0327022C106251C3 ;GTRK Vainah (40E) +F 00010021 01 0327022C106251C3 ;GTRK Vainah (40E) +F 00030136 00 0327022C106251C3 ;GTRK Komi Gor (40E) +F 00030136 01 0327022C106251C3 ;GTRK Komi Gor (40E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (0h) (40E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (0h) (40E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+2h) (40E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+2h) (40E) + +F 3C281130 00 F0212435149122C7 ;Nat Geo Wild HD Turkiye (42E) +F 3C281130 01 F0212435149122C7 ;Nat Geo Wild HD Turkiye (42E) +F 00010200 00 1012002223000326 ;TX9 (42E) +F 00010200 01 1012002223000326 ;TX9 (42E) +F 00020202 00 1012002223000326 ;TX10 (42E) +F 00020202 01 1012002223000326 ;TX10 (42E) +F 00030204 00 1012002223000326 ;TX11 (42E) +F 00030204 01 1012002223000326 ;TX11 (42E) +F 00040206 00 1012002223000326 ;TX12 (42E) +F 00040206 01 1012002223000326 ;TX12 (42E) +F 000717FF 00 DFFEFCD9FDBF18D4 ;NBA TV (42.0E) +F 000717FF 01 DFFEFCD9FDBF18D4 ;NBA TV (42.0E) +F 00010134 00 2012ABDDCD2012FF ;Xazar TV (42.0E) +F 00010134 01 2012ABDDCD2012FF ;Xazar TV (42.0E) +F 296D0645 00 1000001000000000 ;TRT World HD (42.0E) +F 296D0645 01 1000001000000000 ;TRT World HD (42.0E) +F 296A0642 00 1000001000000000 ;TRT HABER HD (42.0E) +F 296A0642 01 1000001000000000 ;TRT HABER HD (42.0E) +F 001109AB 00 1000001000000000 ;Fog TV (42.0E) +F 001109AB 01 1000001000000000 ;Fog TV (42.0E) +F 000B1F9A 00 3453450034534500 ;Idman_Azerbaycan (42.0E) +F 000B1F9A 01 3453450034534500 ;Idman_Azerbaycan (42.0E) +F 00011BB2 00 1234560065432100 ;AzTV Azerbaijan (42.0E) +F 00011BB2 01 1234560065432100 ;AzTV Azerbaijan (42.0E) +F 00010134 00 98B0AFF78711C65E ;NTV ANK.Buro (42.0E) +F 00010134 01 98B0AFF78711C65E ;NTV ANK.Buro (42.0E) +F 00070207 00 1000000000000000 ;Star TV Turkey (42.0E) +F 00070207 01 1000000000000000 ;Star TV Turkey (42.0E) +F 3DB80C71 00 1000001000000000 ;7/24 (42E) +F 3DB80C71 01 1000001000000000 ;7/24 (42E) +F 3DB91FFF 00 002123441361188C ;Intercom Radio (42.0E) +F 3DB91FFF 01 002123441361188C ;Intercom Radio (42.0E) +F 2BC31FFF 00 002123441361188C ;Intercom Radio (42.0E) (42E) +F 2BC31FFF 01 002123441361188C ;Intercom Radio (42.0E) (42E) +F 2BC41FFF 00 002123441361188C ;Intercom HT (Radyo) (42E) +F 2BC41FFF 01 002123441361188C ;Intercom HT (Radyo) (42E) +F 2BC51FFF 00 002123441361188C ;Intercom BL (Radyo) (42E) +F 2BC51FFF 01 002123441361188C ;Intercom BL (Radyo) (42E) +F 001A1FFF 00 1000001010000010 ;DOST FM Radyo (42.0E) +F 001A1FFF 01 1000001010000010 ;DOST FM Radyo (42.0E) +F 06121FFF 00 1000000000000000 :Fenerbahce Radyo (42.0E) +F 06121FFF 01 1000000000000000 ;Fenerbahce Radyo (42.0E) + +F 000101E1 00 1111113311111133 ;IRMAK TV (46E) +F 000101E1 01 1111113311111133 ;IRMAK TV (46E) +F 00010201 00 1028ACE4EB4473A2 ;CBC SPORT HD(46E) +F 00010201 01 1028ACE4EB4473A2 ;CBC SPORT HD(46E) +F 000103E9 00 002005250019566F ;1 TV Georgia (46.0E) +F 000103E9 01 002005250019566F ;1 TV Georgia (46.0E) +F 000B0835 00 0020050000195600 ;2 TV Georgia (46.0E) +F 000B0835 01 0020050000195600 ;2 TV Georgia (46.0E) +F 00010200 00 204710771089710A ;Region TV(46.0E) +F 00010200 01 204710771089710A ;Region TV(46.0E) +F 00010134 00 1234560065432100 ;AzTV Azerbaycan (46.0E) +F 00010134 01 1234560065432100 ;AzTV Azerbaycan (46.0E) +F 000B0198 00 345345CC345345CC ;Idman TV (46.0E) +F 000B0198 01 345345CC345345CC ;Idman TV (46.0E) +F 00070211 00 1234569C654321C9 ;Medeniyet TV (46.0E) +F 00070211 01 1234569C654321C9 ;Medeniyet TV (46.0E) +F 00031F9A 00 1212123612121236 ;ITV Azerbaycan (46.0E) +F 00031F9A 01 1212123612121236 ;ITV Azerbaycan (46.0E) +F 00020198 00 3453450034534500 ;Idman Azerbaycan (46.0E) +F 00020198 01 3453450034534500 ;Idman Azerbaycan (46.0E) +F 6D66006E 00 12345696543219 ;ZDF (46E) +F 6D66006E 01 12345696543219 ;ZDF (46E) + +F 02940295 00 54709155198649E8 ;TEST 1 (TV Center) (49E) +F 02940295 01 54709155198649E8 ;TEST 1 (TV Center) (49E) +F 05140135 00 0327022C106251C3 ;GTRK Ugoria (49E) +F 05140135 01 0327022C106251C3 ;GTRK Ugoria (49E) +F 00020135 00 0327022C106251C3 ;GTRK Region Tyumen (49E) +F 00020135 01 0327022C106251C3 ;GTRK Region Tyumen (49E) +F 00010198 00 0327022C106251C3 ;GTRK Pomorie (49E) +F 00010198 01 0327022C106251C3 ;GTRK Pomorie (49E) +F 00010200 00 0327022C106251C3 ;GTRK Karelija (49E) +F 00010200 01 0327022C106251C3 ;GTRK Karelija (49E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (0h) (49E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (0h) (49E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+2h) (49E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+2h) (49E) + +F 000C00C9 00 0000000000000100 ;Nash Dom (53E) +F 000C00C9 01 0000000000000100 ;Nash Dom (53E) +F 00060205 00 0327022C106251C3 ;Rossiya 1 (+4h) (53E) +F 00060205 01 0327022C106251C3 ;Rossiya 1 (+4h) (53E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (53E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (53E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+8h) (53E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+8h) (53E) + +F 00640066 00 2608396712043811 ;Match! TV (55.0E) +F 00640066 01 2608396712043811 ;Match! TV (55.0E) +F 01F401F6 00 0327022C106251C3 ;Rossia 1 (55.0E) +F 01F401F6 01 0327022C106251C3 ;Rossia 1 (55.0E) +F 00060259 00 62696E39676F7349 ;Lifestyle TV 6 (55E) +F 00060259 01 62696E39676F7349 ;Lifestyle TV 6 (55E) +F 000702BD 00 62696E39676F7349 ;Lifestyle TV 7 (55E) +F 000702BD 01 62696E39676F7349 ;Lifestyle TV 7 (55E) +F 000D0042 00 C12345006789AB00 ;STS (55E) +F 000D0042 01 C12345006789AB00 ;STS (55E) +F 00080036 00 ABC1238F45678935 ;Che (55E) +F 00080036 01 ABC1238F45678935 ;Che (55E) +F 000E002D 00 D12345006789AB00 ;Home (55E) +F 000E002D 01 D12345006789AB00 ;Home (55E) +F 000C002E 00 1234569C789ABCCE ;STS Love (55E) +F 000C002E 01 1234569C789ABCCE ;STS Love (55E) +F 0009003F 00 C12345006789AB00 ;STS +2 (55E) Disney+7h (90E) +F 0009003F 01 C12345006789AB00 ;STS +2 (55E) Disney+7h (90E) +F 000B0033 00 ABC1238F45678935 ;Che +2 (55E) +F 000B0033 01 ABC1238F45678935 ;Che +2 (55E) +F 000A002A 00 D12345006789AB00 ;Home +2 (55E) +F 000A002A 01 D12345006789AB00 ;Home +2 (55E) +F 00020026 00 6BA1E5F174BBCAF9 ;Disney +2 (55E) +F 00020026 01 6BA1E5F174BBCAF9 ;Disney +2 (55E) +F 00010065 00 62696E39676F7349 ;BB1 (55E) +F 00010065 01 62696E39676F7349 ;BB1 (55E) +F 000200C9 00 62696E39676F7349 ;BB2 (55E) +F 000200C9 01 62696E39676F7349 ;BB2 (55E) +F 0003012D 00 62696E39676F7349 ;BB3 (55E) +F 0003012D 01 62696E39676F7349 ;BB3 (55E) +F 00040191 00 62696E39676F7349 ;BB4 (55E) +F 00040191 01 62696E39676F7349 ;BB4 (55E) +F 000501F5 00 62696E39676F7349 ;BB5 (55E) +F 000501F5 01 62696E39676F7349 ;BB5 (55E) +F 00060259 00 169037DD278403AE ;Test1 (55E) +F 00060259 01 169037DD278403AE ;Test1 (55E) +F 000702BD 00 169037DD278403AE ;Test2 (55E) +F 000702BD 01 169037DD278403AE ;Test2 (55E) +F 00080321 00 169037DD278403AE ;Test3 (55E) +F 00080321 01 169037DD278403AE ;Test3 (55E) + +F 0001044C 00 1234569C7890ABB3 ;Armenian Public TV (60E) +F 0001044C 01 1234569C7890ABB3 ;Armenian Public TV (60E) +F 000204B0 00 1234569C7890ABB3 ;Shoghakat TV (60E) +F 000204B0 01 1234569C7890ABB3 ;Shoghakat TV (60E) +F 00030514 00 1234569C7890ABB3 ;Armenia TV Satellite (60E) +F 00030514 01 1234569C7890ABB3 ;Armenia TV Satellite (60E) +F 00040578 00 1234569C7890ABB3 ;Shant TV (60E) +F 00040578 01 1234569C7890ABB3 ;Shant TV (60E) +F 000505DC 00 1234569C7890ABB3 ;H2 (60E) +F 000505DC 01 1234569C7890ABB3 ;H2 (60E) +F 00060640 00 1234569C7890ABB3 ;Kentron (60E) +F 00060640 01 1234569C7890ABB3 ;Kentron (60E) +F 000706A4 00 1234569C7890ABB3 ;Yerkir Media (60E) +F 000706A4 01 1234569C7890ABB3 ;Yerkir Media (60E) +F 00080708 00 1234569C7890ABB3 ;RTR-Planeta (60E) +F 00080708 01 1234569C7890ABB3 ;RTR-Planeta (60E) + +#F 00010200 00 ;Stan Sport (68.5E) +#F 00010200 01 ;Stan Sport (68.5E) + +F 06400641 00 6BA1E5F174BBCAF9 ;Disney (75.0E) +F 06400641 01 6BA1E5F174BBCAF9 ;Disney (75.0E) +F 03840386 00 1234569C789ABCCE ;Mir Audio Service (75.0E) +F 03840386 01 1234569C789ABCCE ;Mir Audio Service (75.0E) + +F 05160CE6 00 0103050907090B1B ;Test_1302 +F 05160CE6 01 0103050907090B1B ;Test_1302 +F 04E61FFF 00 1212123612121236 ;Radio Kunel (85E) +F 04E61FFF 01 1212123612121236 ;Radio Kunel (85E) +F 057E0D4E 00 C12345006789AB00 ;STS +4 (85E) +F 057E0D4E 01 C12345006789AB00 ;STS +4 (85E) +F 05800D50 00 ABC1238F45678935 ;Peretz +4 (85E) +F 05800D50 01 ABC1238F45678935 ;Peretz +4 (85E) +F 057F0D4F 00 D12345006789AB00 ;Home +4 (85E) +F 057F0D4F 01 D12345006789AB00 ;Home +4 (85E) +F 051E0CEE 00 1234569C789ABCCE ; Love (85E) +F 051E0CEE 01 1234569C789ABCCE ; Love (85E) +F 0325070D 00 D12345006789AB00 ;Home 0 (85E) +F 0325070D 01 D12345006789AB00 ;Home 0 (85E) +F 0326070E 00 D12345006789AB00 ;Home 2 (85E) +F 0326070E 01 D12345006789AB00 ;Home 2 (85E) +F 00FB04E3 00 D12345006789AB00 ;Home -4 (85E) +F 00FB04E3 01 D12345006789AB00 ;Home -4 (85E) +F 00FC04E4 00 1234569C789ABCCE ;Home-R (85E) +F 00FC04E4 01 1234569C789ABCCE ;Home-R (85E) +F 00FB04E3 00 1234569C789ABCCE ;Home -7 (85E) +F 00FB04E3 01 1234569C789ABCCE ;Home -7 (85E) +F 03210709 00 C12345006789AB00 ;STS 0 (85E) +F 03210709 01 C12345006789AB00 ;STS 0 (85E) +F 0322070A 00 C12345006789AB00 ;STS 2 (85E) +F 0322070A 01 C12345006789AB00 ;STS 2 (85E) +F 0005003C 00 C12345006789AB00 ;STS +4 (85E) +F 0005003C 01 C12345006789AB00 ;STS +4 (85E) +F 00FA04E2 00 C12345006789AB00 ;STS -4 (85E) +F 00FA04E2 01 C12345006789AB00 ;STS -4 (85E) +F 0323070B 00 ABC1238F45678935 ;Peretz 0 (85E) +F 0323070B 01 ABC1238F45678935 ;Peretz 0 (85E) +F 0324070C 00 ABC1238F45678935 ;Peretz 2 (85E) +F 0324070C 01 ABC1238F45678935 ;Peretz 2 (85E) +F 00FD04E5 00 ABC1238F45678935 ;Perez -4 (85E) +F 00FD04E5 01 ABC1238F45678935 ;Perez -4 (85E) +F 0063044B 00 198313AF041983A0 ;Test-99 (85.1E) +F 0063044B 01 198313AF041983A0 ;Test-99 (85.1E) +F 03890771 00 BABABA2EBABABA2E ;Test Bryansk (85.1E) +F 03890771 01 BABABA2EBABABA2E ;Test Bryansk (85.1E) +F 04611FFF 00 1234560012345600 ;Mir Belogore radio (85.1E) +F 04611FFF 01 1234560012345600 ;Mir Belogore radio (85.1E) + +F 00010134 00 0327022C106251C3 ;GTRK Bira (90E) +F 00010134 01 0327022C106251C3 ;GTRK Bira (90E) +F 001102BD 00 2608396712043811 ;Rossia 2 (90E) +F 001102BD 01 2608396712043811 ;Rossia 2 (90E) +F 00010134 00 0327022C106251C3 ;GTRK Chita (90E) +F 00010134 01 0327022C106251C3 ;GTRK Chita (90E) +F 00010133 00 0327022C106251C3 ;GTRK Gorny Altai (90E) +F 00010133 01 0327022C106251C3 ;GTRK Gorny Altai (90E) +F 00010200 00 0327022C106251C3 ;GTRK Tver (90E) +F 00010200 01 0327022C106251C3 ;GTRK Tver (90E) +F 00010028 00 57081372163689D5 ;MUSIC BOX RU (90E) +F 00010028 01 57081372163689D5 ;MUSIC BOX RU (90E) +F 0002002B 00 3710468D3138036C ;MUSIC BOX TV (90E) +F 0002002B 01 3710468D3138036C ;MUSIC BOX TV (90E) +F 0007003C 00 C12345006789AB00 ;STS +4 (90E) +F 0007003C 01 C12345006789AB00 ;STS +4 (90E) +F 00090038 00 ABC1238F45678935 ;Che +4 (90E) +F 00090038 01 ABC1238F45678935 ;Che +4 (90E) +F 00080034 00 D12345006789AB00 ;Home +4(90E) +F 00080034 01 D12345006789AB00 ;Home +4(90E) +F 01B20022 00 1234569C789ABCCE ;STS Love+7 (90E) +F 01B20022 01 1234569C789ABCCE ;STS Love+7 (90E) +F 0007003E 00 6BA1E5F174BBCAF9 ;Disney +7 (90E) +F 0007003E 01 6BA1E5F174BBCAF9 ;Disney +7 (90E) +F 000A004E 00 C12345676789AB9B ;STS +7 (90E) +F 000A004E 01 C12345676789AB9B ;STS +7 (90E) +F 000F0051 00 ABC1238F45678935 ;Peretz +7 (90E) +F 000F0051 01 ABC1238F45678935 ;Peretz+7 (90E) +F 000C0055 00 D12345396789AB9B ;Home +7 (90E) +F 000C0055 01 D12345396789AB9B ;Home +7 (90E) +F 000D004A 00 5322017658567422 ;HUMOR TV (90E) +F 000D004A 01 5322017658567422 ;HUMOR TV (90E) +F 0004002B 00 A260696B7182988B ;Jug Don Tv (90E) +F 0004002B 01 A260696B7182988B ;Jug Don Tv (90E) +F 001111F9 00 40A73F262C34AE0E ;Test Am (90E) +F 001111F9 01 40A73F262C34AE0E ;Test Am (90E) +F 00120059 00 3901356F2673059E ;Football (90E) +F 00120059 01 3901356F2673059E ;Football (90E) +F 00090065 00 6BA1E5F174BBCAF9 ;Disney (+7h)(90E) 11265 30000 3/4 S2 +F 00090065 01 6BA1E5F174BBCAF9 ;Disney (+7h)(90E) 11265 30000 3/4 S2 +F 000A003C 00 C12345676789AB9B ;STS (+7h)(90E) 11265 30000 3/4 S2 +F 000A003C 01 C12345676789AB9B ;STS (+7h)(90E) 11265 30000 3/4 S2 +F 000B003F 00 ABC1238F45678935 ;Che+7(90E) 11265 30000 3/4 S2 +F 000B003F 01 ABC1238F45678935 ;Che+7(90E) 11265 30000 3/4 S2 +F 000C0043 00 D12345396789AB9B ;HOME+7(90E) 11265 30000 3/4 S2 +F 000C0043 01 D12345396789AB9B ;HOME+7(90E) 11265 30000 3/4 S2 +F 000D0046 00 3901350026730500 ;Football (90) 11265 30000 3/4 S2 +F 000D0046 01 3901350026730500 ;Football (90) 11265 30000 3/4 S2 + +F 00060205 00 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) 3675 V 33483 +F 00060205 01 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) 3675 V 33483 +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) 3875 V 33484 +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) 3875 V 33484 +F 00010580 00 0327022C106251C3 ;GTRK Novosibirsk (96.5E) 3758 V 4340 +F 00010580 01 0327022C106251C3 ;GTRK Novosibirsk (96.5E) 3758 V 4340 +F 00010134 00 0327022C106251C3 ;GTRK Altai (96.5E) 3817 V 4270 +F 00010134 01 0327022C106251C3 ;GTRK Altai (96.5E) 3817 V 4270 +F 00010060 00 0327022C106251C3 ;GTRK Tomsk (96.5E) 10979 H 3200 +F 00010060 01 0327022C106251C3 ;GTRK Tomsk (96.5E) 10979 H 3200 +F 00020201 00 0327022C106251C3 ;Dubl-2+RRD2 (96.5E) +F 00020201 01 0327022C106251C3 ;Dubl-2+RRD2 (96.5E) +F 00060205 00 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) +F 00060205 01 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) +F 00010580 00 0327022C106251C3 ;GTRK Novosibirsk (96.5E) +F 00010580 01 0327022C106251C3 ;GTRK Novosibirsk (96.5E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+8h) (96.5E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+8h) (96.5E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) +F 00010134 00 0327022C106251C3 ;GTRK Krasnoyarsk (96.5E) +F 00010134 01 0327022C106251C3 ;GTRK Krasnoyarsk (96.5E) +F 00010060 00 0327022C106251C3 ;GTRK Tomsk (96.5E) +F 00010060 01 0327022C106251C3 ;GTRK Tomsk (96.5E) + +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (103E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (103E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+8h) (103E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+8h) (103E) + +F 00010134 00 0327022C106251C3 ;GTRK Magadan (140E) +F 00010134 01 0327022C106251C3 ;GTRK Magadan (140E) +F 00010100 00 0327022C106251C3 ;GTRK Amur (140E) +F 00010100 01 0327022C106251C3 ;GTRK Amur (140E) +F 00650134 00 0327022C106251C3 ;GTRK Kamchatka (140E) +F 00650134 01 0327022C106251C3 ;GTRK Kamchatka (140E) +F 00020204 00 0327022C106251C3 ;Rossiya 1 (+8h) (140E) +F 00020204 01 0327022C106251C3 ;Rossiya 1 (+8h) (140E) +F 00060201 00 0327022C106251C3 ;Rossiya 1 (+6h) (140E) +F 00060201 01 0327022C106251C3 ;Rossiya 1 (+6h) (140E) +F 000702BD 00 2608396712043811 ;Rossiya 2 (140E) +F 000702BD 01 2608396712043811 ;Rossiya 2 (140E) +F 00010201 00 0327022C106251C3 ;GTRK Sakhalin (140E) +F 00010201 01 0327022C106251C3 ;GTRK Sakhalin (140E) +F 033500DD 00 C12345676789AB9B ;STS (+7h) (140E) +F 033500DD 01 C12345676789AB9B ;STS (+7h) (140E) +F 033600DE 00 D12345396789AB9B ;Home (+7h) (140E) +F 033600DE 01 D12345396789AB9B ;Home (+7h) (140E) +F 033700DF 00 0327022C106251C3 ;Peretz (+7h) (140E) +F 033700DF 01 0327022C106251C3 ;Peretz (+7h) (140E) + +F 00010200 00 F34698D188513B14 ;ITA 473 ch1 & ITA 473 ch2 + New Freq 12715 H 7500 (5W) +F 00010200 01 F34698D188513B14 ;ITA 473 ch1 & ITA 473 ch2 + New Freq 12715 H 7500 (5W) +F 0065012D 00 3C4D5EE76F12AB2C ;Reversible Guadeloupe (5.0W) +F 0065012D 01 3C4D5EE76F12AB2C ;Reversible Guadeloupe (5.0W) + +F 12700213 00 1234569C789C3347 ;Dubai 33 (7.0W) +F 12700213 01 1234569C789C3347 ;Dubai 33 (7.0W) +F 000B044D 00 444333BA22211154 ;MBC Test 1 (7.0W) +F 000B044D 01 444333BA22211154 ;MBC Test 1 (7.0W) + +F 03850134 00 AB737C9A54D199BE ;Caribbean 901 (15.0W) +F 03850134 01 AB737C9A54D199BE ;Caribbean 901 (15.0W) +F 03860135 00 B86E4C72DD273E42 ;Syndication 902 (15.0W) +F 03860135 01 B86E4C72DD273E42 ;Syndication 902 (15.0W) + +F 000405B4 00 E876F04E8BA51141 ;EFB Ch.1 (24.5W) +F 000405B4 01 E876F04E8BA51141 ;EFB Ch.1 (24.5W) + +F 45401901 00 D581F94F24112D62 ;Channel 5 HD (27.5W) +F 45401901 01 D581F94F24112D62 ;Channel 5 HD (27.5W) +F 4F801D4D 00 D581F94F24112D62 ;Film 4+1 UK (27.5W) +F 4F801D4D 01 D581F94F24112D62 ;Film 4+1 UK (27.5W) +F 444017D5 00 D581F94F24112D62 ;BBC HD (27.5W) +F 444017D5 01 D581F94F24112D62 ;BBC HD (27.5W) +F 448419C9 00 D581F94F24112D62 ;BBC One HD (27.5W) +F 448419C9 01 D581F94F24112D62 ;BBC One HD (27.5W) +F 44C81839 00 D581F94F24112D62 ;ITV1 HD (27.5W) +F 44C81839 01 D581F94F24112D62 ;ITV1 HD (27.5W) +F 4500189D 00 D581F94F24112D62 ;Channel 4 HD (27.5W) +F 4500189D 01 D581F94F24112D62 ;Channel 4 HD (27.5W) +F 4CC01A2D 00 D581F94F24112D62 ;303 (27.5W) +F 4CC01A2D 01 D581F94F24112D62 ;303 (27.5W) +F 10440065 00 D581F94F24112D62 ;BBC ONE (27.5W) +F 10440065 01 D581F94F24112D62 ;BBC ONE (27.5W) +F 10BF00C9 00 D581F94F24112D62 ;BBC TWO (27.5W) +F 10BF00C9 01 D581F94F24112D62 ;BBC TWO (27.5W) +F 10C0012D 00 D581F94F24112D62 ;BBC THREE (27.5W) +F 10C0012D 01 D581F94F24112D62 ;BBC THREE (27.5W) +F 11C00191 00 D581F94F24112D62 ;BBC FOUR (27.5W) +F 11C00191 01 D581F94F24112D62 ;BBC FOUR (27.5W) +F 110001F5 00 D581F94F24112D62 ;BBC NEWS (27.5W) +F 110001F5 01 D581F94F24112D62 ;BBC NEWS (27.5W) +F 1200012D 00 D581F94F24112D62 ;CBBC (27.5W) +F 1200012D 01 D581F94F24112D62 ;CBBC (27.5W) +F 12400191 00 D581F94F24112D62 ;CBeebies (27.5W) +F 12400191 01 D581F94F24112D62 ;CBeebies (27.5W) +F 12800259 00 D581F94F24112D62 ;BBC Parliament (27.5W) +F 12800259 01 D581F94F24112D62 ;BBC Parliament (27.5W) +F 107D13ED 00 D581F94F24112D62 ;BBC ONE NI (27.5W) +F 107D13ED 01 D581F94F24112D62 ;BBC ONE NI (27.5W) +F 107C1005 00 D581F94F24112D62 ;BBC ONE Scot (27.5W) +F 107C1005 01 D581F94F24112D62 ;BBC ONE Scot (27.5W) +F 107E0C1D 00 D581F94F24112D62 ;BBC ONE Wales (27.5W) +F 107E0C1D 01 D581F94F24112D62 ;BBC ONE Wales (27.5W) +F 11401FFF 00 D581F94F24112D62 ;BBC Red Button (27.5W) +F 11401FFF 01 D581F94F24112D62 ;BBC Red Button (27.5W) + +F 00010101 00 383838A8383838A8 ;Agencia EFE (30W) +F 00010101 01 383838A8383838A8 ;Agencia EFE (30W) +F 001106A4 00 851267FE339412D9 ;RESUMEN 10 (30.0W) +F 001106A4 01 851267FE339412D9 ;RESUMEN 10 (30.0W) +F 01F40443 00 12481670326412A8 ;SD TVI Internacional (30.0W) +F 01F40443 01 12481670326412A8 ;SD TVI Internacional (30.0W +F 000707D7 00 F9E8D7B8C6B5A41F ;Fox Sports HD (30.0W) +F 000707D7 01 F9E8D7B8C6B5A41F ;Fox Sports HD (30.0W) +F 02BD1B63 00 383838A8383838A8 ;National Geographic HD (30.0W) +F 02BD1B63 01 383838A8383838A8 ;National Geographic HD (30.0W) +F 02BE1B6D 00 383838A8383838A8 ;National Geographic Portugal (30.0W) +F 02BE1B6D 01 383838A8383838A8 ;National Geographic Portugal (30.0W) +# ........................ +# ::::::::: CCW'S ::::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: MTV Portugal 9E CCW's ::::::: +F 06A50969 00 ;MTV Portugal (9E) +F 06A50969 01 ;MTV Portugal (9E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: FreeX TV/French Lover/XTSY ::::::: +F 128F1D7F 00 ; XTSY (13.0E) +F 128F1D7F 01 ; XTSY (13.0E) +F 08330FA2 00 ;Free-X TV (13.0E) +F 08330FA2 01 ;Free-X TV (13.0E) +F 08320FA1 00 ;French Lover TV (13.0E) +F 08320FA1 01 ;French Lover TV (13.0E) +# ::::::: PentHause HD 9E CCW's ::::::: +F 000A0026 00 ;Penthouse HD (9.0E) +F 000A0026 01 ;Penthouse HD (9.0E) +F 00140027 00 ;Penthouse HD 1 (9.0E) +F 00140027 01 ;Penthouse HD 1 (9.0E) +F 001E0028 00 ;Penthouse HD 2 (9.0E) +F 001E0028 01 ;Penthouse HD 2 (9.0E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#:::::::: CSLink & SkyLink 23E CCW's :::::::: +F 23290640 00 ;FilmBox (23.5E) +F 23290640 01 ;FilmBox (23.5E) +F 232B0641 00 ;FilmBox Extra (23.5E) +F 232B0641 01 ;FilmBox Extra (23.5E) +F 13AE00B2 00 ;NatGeo Wild Hungary (23.5E) +F 13AE00B2 01 ;NatGeo Wild Hungary (23.5E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#:::::::: MTV Networks 13E CCW's ::::::: +F 000619D0 00 ;Viacom Blink! (13.0E) +F 000619D0 01 ;Viacom Blink! (13.0E) +F 00011B59 00 ;MTV Live HD (13.0E) +F 00011B59 01 ;MTV Live HD (13.0E) +F 000A184F 00 ;Comedy Central Polska (13.0E) +F 00071803 00 ;VH1 (13.0E) +F 00071803 01 ;VH1 (13.0E) +F 00041EE0 00 ;Comedy Central Family Polska (13.0E) +F 00041EE0 01 ;Comedy Central Family Polska (13.0E) +F 000A184F 01 ;Comedy Central Polska (13.0E) +F 000B1850 00 ;Nickeladeon Europe (13.0E) +F 000B1850 01 ;Nickeladeon Europe (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: MTV Network 19.2E CCW's ::::::: +F 70021790 00 ; MTV Pulse (19.2E) +F 70021790 01 ; MTV Pulse (19.2E) +F 70031791 00 ; MTV IDOL (19.2E) +F 70031791 01 ; MTV IDOL (19.2E) +F 6FFF1B59 00 ; MTV Music (19.2E) +F 6FFF1B59 01 ; MTV Music (19.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: HUSTLER HD-3D/Redlight Premium/Redlight 3D-HD +F 42231E21 00 ;Redlight Premium (13.0E) +F 42231E21 01 ;Redlight Premium (13.0E) +F 42241D74 00 ;Redlight 3D-HD (13.0E) +F 42241D74 01 ;Redlight 3D-HD (13.0E) +F 42251E0B 00 ;HUSTLER HD-3D (13.0E) +F 42251E0B 01 ;HUSTLER HD-3D (13.0E) +F 42251ECA 00 ;HUSTLER HD-3D (13.0E) +F 42251ECA 01 ;HUSTLER HD-3D (13.0E) +F 42251D60 00 ;HUSTLER HD-3D (13.0E) +F 42251D60 01 ;HUSTLER HD-3D (13.0E) +F 42251D5F 00 ;HUSTLER HD-3D (13.0E) +F 42251D5F 01 ;HUSTLER HD-3D (13.0E) +F 42251D55 00 ;HUSTLER HD-3D (13.0E) +F 42251D55 01 ;HUSTLER HD-3D (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: SSR/SRG Swiss (TSR/RSI LA/SF 13E CCW's ::::::: +F 433102CF 00 ; SF 1 HD (13.0E) +F 433102CF 01 ; SF 1 HD (13.0E) +F 433202CF 00 ; SF Zwei HD (13.0E) +F 433202CF 01 ; SF Zwei HD (13.0E) +F 433302CF 00 ; TSR 1 HD (13.0E) +F 433302CF 01 ; TSR 1 HD (13.0E) +F 433402CF 00 ; TSR 2 HD (13.0E) +F 433402CF 01 ; TSR 2 HD (13.0E) +F 36B202CE 00 ; TSR 1 (13.0E) +F 36B202CE 01 ; TSR 1 (13.0E) +F 36B302CE 00 ; TSI 1 (13.0E) +F 36B302CE 01 ; TSI 1 (13.0E) +F 36B802CE 00 ; TSR 2 (13.0E) +F 36B802CE 01 ; TSR 2 (13.0E) +F 36B902CE 00 ; TSI 2 (13.0E) +F 36B902CE 01 ; TSI 2 (13.0E) +F 36E302CE 00 ; RSI La 1 HD (13.0E) +F 36E302CE 01 ; RSI La 1 HD (13.0E) +F 038502CD 00 ; SF 1 (13.0E) +F 038502CD 01 ; SF 1 (13.0E) +F 038B02CD 00 ; SF 2 (13.0E) +F 038B02CD 01 ; SF 2 (13.0E) +F 038F02CD 00 ; SFI (13.0E) +F 038F02CD 01 ; SFI (13.0E) +F 03B702CD 00 ; RSI La 2 HD (13.0E) +F 03B702CD 01 ; RSI La 2 HD (13.0E) +F 03DE02CD 00 ; HD suisse (13.0E) +F 03DE02CD 01 ; HD suisse (13.0E) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Total TV (16.0E) CCW's ::::::: +F 032503B7 00 ;Fox Life (16.0E) +F 032503B7 01 ;Fox Life (16.0E) +F 032403B8 00 ;Fox Crime (16.0E) +F 032403B8 01 ;Fox Crime (16.0E) +F 032603B9 00 ;Nat Geographic (16.0E) +F 032603B9 01 ;Nat Geographic (16.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Baby Tv 13E CCW's Keys ::::::: +F 439D0807 00 ; BABY TV (13.0E) +F 439D0807 01 ; BABY TV (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# :::::: Raduga TV 75E CCW's ::::::: +F 012C0132 00 ;ESP Russian (75E) +F 012C0132 01 ;ESP Russian (75E) +F 01900196 00 ;ESP2 Russian (75E) +F 01900196 01 ;ESP2 Russian (75E) +F 012C0131 00 ;ESP Russian (75E) +F 012C0131 01 ;ESP Russian (75E) +F 01900195 00 ;ESP2 Russian (75E) +F 01900195 01 ;ESP2 Russian (75E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: AXN Adria CCW's :::::: +F 1AC21D51 00 ;AXN Adria (16E) +F 1AC21D51 01 ;AXN Adria (16E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Dozhdj/NTV 4.9E/90.0E CCW's :::::: +F 010E010F 00 ;Dozhdj 4.9E +F 010E010F 01 ;Dozhdj 4.9E +F 000A0032 00 ;NTV 4.9E +F 000A0032 01 ;NTV 4.9E +F 02710270 00 ;Dozhdj 90.0E +F 02710270 01 ;Dozhdj 90.0E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Telelombardia 13E CCW's +F 0E200269 00 ; Telelombardia (13.0E) +F 0E200269 01 ; Telelombardia (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: NSAB 5E CCW's ::::::: +F 19E619EF 00 ;Football (4.8E) +F 19E619EF 01 ;Football (4.8E) +F 1A041A0D 00 ;Football+ (4.8E) +F 1A041A0D 01 ;Football+ (4.8E) +F 17FC1805 00 ;Kanal Ukraina (4.8E) +F 17FC1805 01 ;Kanal Ukraina (4.8E) +F 19DC19E5 00 ;Ukraina (4.8E) +F 19DC19E5 01 ;Ukraina (4.8E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: EQUIDIA 13E CCW's ::::::: +F 043900 00 ;EQUIDIA PRO P1 13E +F 043900 01 ;EQUIDIA PRO P1 13E +F 043900 00 ;EQUIDIA PRO 13E +F 043900 01 ;EQUIDIA PRO 13E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Sky Italia DCW Keys (13E) ::::::: +F 2FD20516 00 ;DMAX (13.0E) +F 2FD20516 01 ;DMAX (13.0E) +F 2FD3051C 00 ;Frisbee (13.0E) +F 2FD3051C 01 ;Frisbee (13.0E) +F 2FD4051F 00 ;Radio Capital Tv (13.0E) +F 2FD4051F 01 ;Radio Capital Tv (13.0E) +F 2FD50519 00 ;K2 (13.0E) +F 2FD50519 01 ;K2 (13.0E) +F 2FDE050D 00 ;Nick Junior +1 (13.0E) +F 2FDE050D 01 ;Nick Junior +1 (13.0E) +F 2FE0050A 00 ;AXN +1 (13.0E) +F 2FE0050A 01 ;AXN +1 (13.0E) +F 2FE704FC 00 ;GXT +1 (13.0E) +F 2FE704FC 01 ;GXT +1 (13.0E) +F 2FE804F8 00 ;Cartoon Network +1 (13.0E) +F 2FE804F8 01 ;Cartoon Network +1 (13.0E) +F 2FE904FF 00 ;Boomerang +1 (13.0E) +F 2FE904FF 01 ;Boomerang +1 (13.0E) +F 2FF00507 00 ;Comedy Central +1 (13.0E) +F 2FF00507 01 ;Comedy Central +1 (13.0E) +F 2FF104F9 00 ;Nickelodeon+1 (13.0E) +F 2FF104F9 01 ;Nickelodeon+1 (13.0E) +F 1FAC0532 00 ;Sky News International (13.0E) +F 1FAC0532 01 ;Sky News International (13.0E) +F 1FBF052C 00 ;Yacht & Sail (13.0E) +F 1FBF052C 01 ;Yacht & Sail (13.0E) +F 1FC90522 00 ;Cult Network Italia (13.0E) +F 1FC90522 01 ;Cult Network Italia (13.0E) +F 2DD9070A 00 ;Sky Sport 3 Italia (13.0E) +F 2DD9070A 01 ;Sky Sport 3 Italia (13.0E) +F 420F008D 00 ;Primocanale(13.0E) +F 420F008D 01 ;Primocanale(13.0E) +F 420B008B 00 ;TG Norba 24(13.0E) +F 420B008B 01 ;TG Norba 24(13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Daring Tv 13E CCW's ::::::: +F 43B317FF 00 ; Daring!TV (13.0E) +F 43B317FF 01 ; Daring!TV (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Trace Tropical HD 9E CCW's ::::::: +F 08CB09D5 00 ;Trace Tropical HD(9.0E) +F 08CB09D5 01 ;Trace Tropical HD(9.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Sky Box Office DCW Keys ::::::: +F 14AB0503 00 ;Sky Box Office(28.2E) +F 14AB0503 01 ;Sky Box Office(28.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: WDS Tv CCW's ::::::: +F 01F50553 00 ;WDS TV (100E) +F 01F50553 01 ;WDS TV (100E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: MTV Trax CCW's ::::::: +F 1B6D050B 00 ; MTV Trax (28.2E) +F 1B6D050B 01 ; MTV Trax (28.2E) +#::::::: Sky Sport Active CCW's ::::::::::: +F 152305C8 00 ;1381 (28.2E) +F 152305C8 01 ;1381 (28.2E) +F 152405C8 00 ;1382 (28.2E) +F 152405C8 01 ;1382 (28.2E) +F 152505C8 00 ;1383 (28.2E) +F 152505C8 01 ;1383 (28.2E) +F 152605C8 00 ;1384 (28.2E) +F 152605C8 01 ;1384 (28.2E) +F 152705C8 00 ;1385 (28.2E) +F 152705C8 01 ;1385 (28.2E) +F 152805C8 00 ;1386 (28.2E) +F 152805C8 01 ;1386 (28.2E) +F 156905C8 00 ;1481 (28.2E) +F 156905C8 01 ;1481 (28.2E) +F 156A05C8 00 ;1482 (28.2E) +F 156A05C8 01 ;1482 (28.2E) +F 156B05C8 00 ;1483 (28.2E) +F 156B05C8 01 ;1483 (28.2E) +F 156C05C8 00 ;1484 (28.2E) +F 156C05C8 01 ;1484 (28.2E) +F 156D05C8 00 ;1485 (28.2E) +F 156D05C8 01 ;1485 (28.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Private Spice 13.0E CCW's ::::::: +F 125102B3 00 ;Private Spice (13.0E) +F 125102B3 01 ;Private Spice (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: 19E CCW's ::::::: +F 0FA20565 00 ; SBS6 (19.2E) +F 0FA20565 01 ; SBS6 (19.2E) +F 0FA30566 00 ; NE5 (19.2E) +F 0FA30566 01 ; NE5 (19.2E) +F 0FAB0567 00 ; NED1 (19.2E) +F 0FAB0567 01 ; NED1 (19.2E) +F 0FAC0568 00 ; NED2 (19.2E) +F 0FAC0568 01 ; NED2 (19.2E) +F 0FAD0569 00 ; NED3 (19.2E) +F 0FAD0569 01 ; NED3 (19.2E) +#.......................... +# ::::::: Canal Sat 19.2E +F 7A4D0BD9 00 ;L'Equipe 21 (19.2E) +F 7A4D0BD9 01 ;L'Equipe 21 (19.2E) +F 24BF19AC 00 ;M6 Music Hits(19.2E) +F 24BF19AC 01 ;M6 Music Hits(19.2E) +F 24BD1998 00 ;Cinecinema Star(19.2E) +F 24BD1998 01 ;Cinecinema Star(19.2E) +F 24C01A1A 00 ;Discovery Channel France(19.2E) +F 24C01A1A 01 ;Discovery Channel France(19.2E) +F 24BC19F2 00 ;InfoSport(19.2E) +F 24BC19F2 01 ;InfoSport(19.2E) +F 24C119C1 00 ;Pink TV(19.2E) +F 24C119C1 01 ;Pink TV(19.2E) +F 24BA19DF 00 ;Se'rie Club(19.2E) +F 24BA19DF 01 ;Se'rie Club(19.2E) +F 24BE1A06 00 ;Te'le'toon(19.2E) +F 24BE1A06 01 ;Te'le'toon(19.2E) +F 24C21A9C 00 ;Te'le'toon +1(19.2E) +F 24C21A9C 01 ;Te'le'toon +1(19.2E) +F 24B91971 00 ;TPS Star(19.2E) +F 24B91971 01 ;TPS Star(19.2E) +F 6FF1191A 00 ;VH1 Classic 19.2E +F 6FF1191A 01 ;VH1 Classic 19.2E +F 6FF7180A 00 ;Game One 19.2E +F 6FF7180A 01 ;Game One 19.2E +F 6FFC180C 00 ;Nickelodeon France 19.2E +F 6FFC180C 01 ;Nickelodeon France 19.2E +F 6FFF19B2 00 ;VH1 Europe 19.2E +F 6FFF19B2 01 ;VH1 Europe 19.2E +F 6FF317B1 00 ;MTV Rocks 19.2E +F 6FF317B1 01 ;MTV Rocks 19.2E +F 6FEF190D 00 ;MTV Dance 19.2E +F 6FEF190D 01 ;MTV Dance 19.2E +F 6FEC1806 00 ;MTV France 19.2E +F 6FEC1806 01 ;MTV France 19.2E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Weddeng Tv and Deepam Tv 13E CCW's ::::::: +F 12350295 00 ;Wedding TV (13.0E) +F 12350295 01 ;Wedding TV (13.0E) +F 11FE0263 00 ;Deepam TV (13.0E) +F 11FE0263 01 ;Deepam TV (13.0E) +#............................... +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: SIC 16E CCW's +F 000103E9 00 ;SIC Internacional (16E) by Serjoga latvia +F 000103E9 01 ;SIC Internacional (16E) by Serjoga latvia +#.................................. +#^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Dorcel TV 13.0E CCW's ::::::: +F 227B1216 00 ;Dorcel TV (13.0E) +F 227B1216 01 ;Dorcel TV (13.0E) +F 2288121B 00 ;Dorcel TV (13.0E) +F 2288121B 01 ;Dorcel TV (13.0E) +F 37860B75 00 ;DorcelTV (13.0E) +F 37860B75 01 ;DorcelTV (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#............................................... +# ::::::: Nat Geo HD UK 16.0E CCW's ::::::: +F 03E91BCC 00 ;Nat Geo HD UK (16.0E) by Serjoga latvia +F 03E91BCC 01 ;Nat Geo HD UK (16.0E) by Serjoga latvia +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ..................................................... +# ::::::: HAYAT TV SAT/HAYAT TV BIH 16.0E CCW's ::::::: +F 00010065 00 ;HAYAT TV BIH (16.0E) +F 00010065 01 ;HAYAT TV BIH (16.0E) +F 00020064 00 ;HAYAT PLUS (16.0E) +F 00020064 01 ;HAYAT PLUS (16.0E) +F 00030064 00 ;Hayat Folk TV (16.0E) +F 00030064 01 ;Hayat Folk TV (16.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Hustler Tv 19.2E CCW's +F 07FA05AA 00 ;Hustler TV viaccess (19.2E) +F 07FA05AA 01 ;Hustler TV viaccess (19.2E) +F 07FA05AA 00 ;Hustler TV seca (19.2E) +F 07FA05AA 01 ;Hustler TV seca (19.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Trace TV 13.0E CCW's ::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 13F10AF5 00 ;Trace TV (13.0E) +F 13F10AF5 01 ;Trace TV (13.0E) +#.......................... +#::::::: SciFi & Universal CCWs +F 3A351B9E 00 ;UNIVERSAL (13.0E) +F 3A351B9E 01 ;UNIVERSAL (13.0E) +F 3A361B9F 00 ;SCi Fi (13.0E) +F 3A361B9F 01 ;SCi Fi (13.0E) +F 3A34057B 00 ;Sport Klub (13.0E) +F 3A34057B 01 ;Sport Klub (13.0E) +#........................ +#::::::: CONTO TV CCW's::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^^ +F 20EC0518 00 ;CONTO TV 2 (13.0E) +F 20EC0518 01 ;CONTO TV 2 (13.0E) +F 20EF0524 00 ;CONTO TV 4 +F 20EF0524 01 ;CONTO TV 4 +#............................... +#::::::: RTVI CCW's ::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^ +F 39D20399 00 ; RTVi Europe (13.0E) +F 39D20399 01 ; RTVi Europe (13.0E) +F 39D3039B 00 ; RTVi Detskii Mir (13.0E) +F 39D3039B 01 ; RTVi Detskii Mir (13.0E) +F 39D4039A 00 ; RTVi Nashe Kino (13.0E) +F 39D4039A 01 ; RTVi Nashe Kino (13.0E) +#................................ +#::::::: Satisfaction TV CCW's ::::::: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 35D81777 00 ;Pink O TV (13E) +F 35D81777 01 ;Pink O TV (13E) +F 35C10542 00 ;Extocica TV (13E) +F 35C10542 01 ;Extocica TV (13E) +F 35C80548 00 ;PassionXXX (13E) +F 35C80548 01 ;PassionXXX (13E) +F 35C30545 00 ;SCT (13E) +F 35C30545 01 ;SCT (13E) +F 000A0549 00 ;SCT HD (13E) +F 000A0549 01 ;SCT HD (13E) +F 35C60546 00 ;CentoxCento (13E) +F 35C60546 01 ;CentoxCento (13E) +F 35C70547 00 ;Sesto Senso TV (13E) +F 35C70547 01 ;Sesto Senso TV (13E) +F 35C00541 00 ;TGirls TV (13E) +F 35C00541 01 ;TGirls TV (13E) +#........................................ +#::::::: Belgium Package CCW's 13E ::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 362F16BD 00 ;La Une (13.0E) +F 362F16BD 01 ;La Une (13.0E) +F 363016BE 00 ;La Deux (13.0E) +F 363016BE 01 ;La Deux (13.0E) +F 363116BF 00 ;RTL-TVi (13.0E) +F 363116BF 01 ;RTL-TVi (13.0E) +F 363216C0 00 ;Club-RTL (13.0E) +F 363216C0 01 ;Club-RTL (13.0E) +F 363316C1 00 ;Plug-RTL (13.0E) +F 39D4039A 01 ;Plug-RTL (13.0E) +F 363416C2 00 ;Disney Channel (13.0E) +F 39D4039A 01 ;Disney Channel (13.0E) +#....................................... +#::::::: JSC SPORT CCW's ::::::: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 20F514B8 00 ; JSC Sports +1 (13.0E) +F 20F514B8 01 ; JSC Sports +1 (13.0E) +F 20F61648 00 ; JSC Sports +2 (13.0E) +F 20F61648 01 ; JSC Sports +2 (13.0E) +F 20F71710 00 ; JSC Sports +3 (13.0E) +F 20F71710 01 ; JSC Sports +3 (13.0E) +F 20F817D8 00 ; JSC Sports +4 (13.0E) +F 20F817D8 01 ; JSC Sports +4 (13.0E) +F 20F9183C 00 ; JSC Sports +5 (13.0E) +F 20F9183C 01 ; JSC Sports +5 (13.0E) +F 20FA18A0 00 ; JSC Sports +6 (13.0E) +F 20FA18A0 01 ; JSC Sports +6 (13.0E) +F 20FB1904 00 ; JSC Sports +7 (13.0E) +F 20FB1904 01 ; JSC Sports +7 (13.0E) +F 20FC1968 00 ; JSC Sports +8 (13.0E) +F 20FC1968 01 ; JSC Sports +8 (13.0E) +F 20FD19CC 00 ; JSC Sports +9 (13.0E) +F 20FD19CC 01 ; JSC Sports +9 (13.0E) +F 20FE1A30 00 ; JSC Sports +10 (13.0E) +F 20FE1A30 01 ; JSC Sports +10 (13.0E) +F 20FF1AC7 00 ; JSC World Cup (13.0E) +F 20FF1AC7 01 ; JSC World Cup (13.0E) +#........................................... +#::::::: Rai/Tivusat 13E CCW's +F 0D491081 00 ;Rai HD (13.0E) +F 0D491081 01 ;Rai HD (13.0E) +F 0D4B1083 00 ;Rai 3 TGR FVG (13.0E) +F 0D4B1083 01 ;Rai 3 TGR FVG (13.0E) +F 0D521087 00 ;Rai 5 (13.0E) +F 0D521087 01 ;Rai 5 (13.0E) +F 0D661088 00 ;Rai yoyo (13.0E) +F 0D661088 01 ;Rai yoyo (13.0E) +#............................................. +#::::::: TV Globo 13E CCW's ::::::: +F 34D61F40 00 ;TV Globo (13.0E) +F 34D61F40 01 ;TV Globo (13.0E) +#............................................. +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Nick Jr. 13E CCW's::::::: +F 001E0326 00 (13.0E) +F 001E0326 01 (13.0E) +#.............................................. +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: AustriaSat/HD+ CCW's::::::: +F 15191C9E 00 ;Tele 5 HD (19.2E) +F 15191C9E 01 ;Tele 5 HD (19.2E) +F 157F1AE2 00 ;Deluxe Music HD (19.2E) +F 157F1AE2 01 ;Deluxe Music HD (19.2E) +F 52741AC2 00 ;N24 HD (19.2E) +F 52741AC2 01 ;N24 HD (19.2E) +F 14B51AEC 00 ;ProSieben HD (19.2E) +F 14B51AEC 01 ;ProSieben HD (19.2E) +F 52731AC0 00 ;NICH/CC HD (19.2E) +F 52731AC0 01 ;NICH/CC HD (19.2E) +# .................................................. +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Overon/M7 (SkyLink/CSLink) 23.5E CCW's ::::::: +F 02C5044D 00 ;NatGeo Wild HD DUT (23.5E) +F 02C5044D 01 ;NatGeo Wild HD DUT (23.5E) +F 02C71BC7 00 ;M1 - Magyar TV (23.5E) +F 02C71BC7 01 ;M1 - Magyar TV (23.5E) +F 02C91BDB 00 ;Duna TV (23.5E) +F 02C91BDB 01 ;Duna TV (23.5E) +F 02CA1BE5 00 ;Duna World (23.5E) +F 02CA1BE5 01 ;Duna World (23.5E) +F 02CB1BEF 00 ;RTL Klub (23.5E) +F 02CB1BEF 01 ;RTL Klub (23.5E) +F 02CC1BF9 00 ;TV 2 (Hungary) (23.5E) +F 02CC1BF9 01 ;TV 2 (Hungary) (23.5E) +F 02CD1C03 00 ;Hir TV (23.5E) +F 02CD1C03 01 ;Hir TV (23.5E) +F 02CE1C0D 00 ;Magyar ATV (23.5E) +F 02CE1C0D 01 ;Magyar ATV (23.5E) +F 02CF1C17 00 ;Nota TV (23.5E) +F 02CF1C17 01 ;Nota TV (23.5E) +F 02D01C21 00 ;4!Story TV (23.5E) +F 02D01C21 01 ;4!Story TV (23.5E) +F 02D21C35 00 ;Viasat 3 (23.5E) +F 02D21C35 01 ;Viasat 3 (23.5E) +F 02D31C3F 00 ;RTL 2 Hungary (23.5E) +F 02D31C3F 01 ;RTL 2 Hungary (23.5E) +F 02D41C49 00 ;Super TV 2 (23.5E) +F 02D41C49 01 ;Super TV 2 (23.5E) +F 02D51C53 00 ;SportKlub (23.5E) +F 02D51C53 01 ;SportKlub (23.5E) +F 02D61C5D 00 ;Sport 1 Hungary (23.5E) +F 02D61C5D 01 ;Sport 1 Hungary (23.5E) +F 02D71C67 00 ;Cool TV (23.5E) +F 02D71C67 01 ;Cool TV (23.5E) +F 02D81C71 00 ;Digi Sport Hungary (23.5E) +F 02D81C71 01 ;Digi Sport Hungary (23.5E) +F 02D91C7B 00 ;Comedy Central Hungary (23.5E) +F 02D91C7B 01 ;Comedy Central Hungary (23.5E) +F 02DA1C85 00 ;Discovery Channel Hungary (23.5E) +F 02DA1C85 01 ;Discovery Channel Hungary (23.5E) +F 02DB1C8F 00 ;Sport 2 Hungary (23.5E) +F 02DB1C8F 01 ;Sport 2 Hungary (23.5E) +F 02DC1C99 00 ;FEM3 (23.5E) +F 02DC1C99 01 ;FEM3 (23.5E) +F 02F9044D 00 ;NatGeo Wild HD (23.5E) +F 02F9044D 01 ;NatGeo Wild HD (23.5E) +F 15EB044D 00 ;NatGeo Wild HD CZ (23.5E) +F 15EB044D 01 ;NatGeo Wild HD CZ (23.5E) +# ........................................................... +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: BFBS 10E CCW's ::::::: +F 1F490BC1 00 ;09 BBC One Delay (10.0E) +F 1F490BC1 01 ;09 BBC One Delay (10.0E) +F 1F420BBA 00 ;02 BBC Two (10.0E) +F 1F420BBA 01 ;02 BBC Two (10.0E) +F 1F440BBC 00 ;04 BFBS Extra (10.0E) +F 1F440BBC 01 ;04 BFBS Extra (10.0E) +F 1F470BBF 00 ;07 BFBS Sport (10.0E) +F 1F470BBF 01 ;07 BFBS Sport (10.0E) +F 1F450BBD 00 ;05 Sky Sports 1 (10.0E) +F 1F450BBD 01 ;05 Sky Sports 1 (10.0E) +F 1F460BBE 00 ;Sky Sports 2) (10.0E) +F 1F460BBE 01 ;Sky Sports 2) (10.0E) +F 1F480BC0 00 ;08 Sky News (10.0E) +F 1F480BC0 01 ;08 Sky News (10.0E) +# ........................................................... +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: TRING TV 16.0E CCWs ::::::: +F 00320037 00 ;JOLLY HD (16.0E) +F 00320037 01 ;JOLLY HD (16.0E) +F 00070A32 00 ;RTV21 (16.0E) +F 00070A32 01 ;RTV21 (16.0E) +F 0C260C2A 00 ;RTV21 PLUS (16.0E) +F 0C260C2A 01 ;RTV21 PLUS (16.0E) +F 003C0041 00 ;BBF (16.0E) +F 003C0041 01 ;BBF (16.0E) +F 08D40A46 00 ;TRING FANTASY (16.0E) +F 08D40A46 01 ;TRING FANTASY (16.0E) +F 00461004 00 ;TRING HISTORY (16.0E) +F 00461004 01 ;TRING HISTORY (16.0E) +F 038A0775 00 ;Fox Life (16.0E) +F 038A0775 01 ;Fox Life (16.0E) +F 00501068 00 ;LIVING (16.0E) +F 00501068 01 ;LIVING (16.0E) +F 005E07CA 00 ;Agon Channel (16.0E) +F 005E07CA 01 ;Agon Channel (16.0E) + +F 3B630517 00 ;Eurosport 2 HD (13.0E) +F 3B630517 01 ;Eurosport 2 HD (13.0E) + +F 363B1421 00 ;ESP2 NE (13.0E) +F 363B1421 01 ;ESP2 NE (13.0E) + +F 32CA012E 00 ;ORF2 (19.2E) +F 32CA012E 01 ;ORF2 (19.2E) + +# ::::::: BeiN Sports 19.2E CCWs ::::::: + +F 189D0BD7 00 ;BeIN Sport 1 HD (19.2E) +F 189D0BD7 01 ;BeIN Sport 1 HD (19.2E) +F 189E0BD8 00 ;BeIN Sport 2 HD (19.2E) +F 189E0BD8 01 ;BeIN Sport 2 HD (19.2E) +F 18A00BDA 00 ;BeIN Sport 3 HD (19.2E) +F 18A00BDA 01 ;BeIN Sport 3 HD (19.2E) + +# ::::::: FilBox 42E CCWs ::::::: + +F 3EE61966 00 50CCA6C21AF69BAB ;Fightbox HD (42.0E) +F 3EE61966 01 50CCA6C21AF69BAB ;Fightbox HD (42.0E) +F 3EEA196A 00 3D8B26EEDEB7861B ;DaVinci Learning (42.0E) +F 3EEA196A 01 3D8B26EEDEB7861B ;DaVinci Learning (42.0E) + +# ::::::: Pershiy Avtomobilniy (1 Auto) 4Ws ::::::: + +F 000B1111 00 ;Pershiy Avtomobilniy (1 Auto) (4W) +F 000B1111 01 ;Pershiy Avtomobilniy (1 Auto) (4W ) + + +# :::::::::: sat-life.info ::::::::::::::: +# <><><><><> by Serjoga latvia <><><><><><> diff --git a/package/lean/dvb/oscam/files/oscam.conf b/package/lean/dvb/oscam/files/oscam.conf new file mode 100755 index 000000000..7305dab93 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.conf @@ -0,0 +1,43 @@ +# oscam.conf generated automatically by Streamboard OSCAM 1.20-unstable_svn SVN r11390 +# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/oscam.conf.txt + +[global] +logfile = /var/log/oscam/oscam.log +nice = 0 +maxlogsize = 1000 +preferlocalcards = 1 + +[cache] + +[cccam] +port = 12000 +nodeid = AC2D31EE10E41520 +version = 2.1.1 +reshare = 1 +ignorereshare = 1 +stealth = 1 + +[streamrelay] + +[dvbapi] +enabled = 1 +au = 1 +pmt_mode = 4 +request_mode = 1 +listen_port = 9000 +delayer = 80 +user = TVH +boxtype = pc + +[webif] +httpport = 8888 +httpuser = oscam +httppwd = oscam +httpshowmeminfo = 1 +httpshowuserinfo = 1 +httpshowecminfo = 1 +httpshowloadinfo = 1 +httpallowed = 0.0.0.0-255.255.255.255 +aulow = 120 +httputf8 = 1 + diff --git a/package/lean/dvb/oscam/files/oscam.dvbapi b/package/lean/dvb/oscam/files/oscam.dvbapi new file mode 100644 index 000000000..68fc1c027 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.dvbapi @@ -0,0 +1,31 @@ +P: 0500:040620 # NTV+ (36Е) +P: 0500:041200 # NTV+ (36Е) +P: 0500:060A00 # NTV+ (36E) +P: 0500:060C00 # NTV+ (36E) +P: 0500:023100 # trk football (Shara)(5Е) +P: 0500:041200 # trk football (Shara)(5Е) +P: 0500:041700 # Dorcel TV (13Е) +P: 0500:042300 # rtvi (13Е) +P: 0500:042700 # SCT, S1-7-HQ,HD (13Е) +P: 0500:042800 # Absat/BisTV (13Е) +P: 0500:043800 # REDLIGHT HD, Redlight Premium & Daring! TV (13Е) +P: 0100:000068 # Cyfra+ 13e +P: 09CD:0 # Sky 13e +P: 1803:007001 # Polsat (13Е) +P: 1803:007101 # Polsat (13Е) +P: 1803:000000 # Polsat (13Е) +P: 090D:0 # yes 4w +P: 090F:0 # viasat baltic 5e + +# EMU +P: 2600:000000 # BISS +P: 0500:023800 # srg (EMU)(13Е) +P: 0E00:000000 # PowerVU +P: 0500:007400 +P: 0D00:000000 +P: 0D05:000000 +P: 0D02:000000 +P: 1801:000000 + +# Ignor +I:0 diff --git a/package/lean/dvb/oscam/files/oscam.init b/package/lean/dvb/oscam/files/oscam.init new file mode 100755 index 000000000..90f38202e --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.init @@ -0,0 +1,23 @@ +#!/bin/sh /etc/rc.common + +START=99 +OSCAM_PATH=/usr/bin + +[ -f /tmp/oscam ] && +{ + OSCAM_PATH=/tmp + [ -x /tmp/oscam ] || chmod +x /tmp/oscam +} + +start() { + logger "Starting Oscam" + [ -d /var/log/oscam ] || mkdir -p /var/log/oscam + service_start ${OSCAM_PATH}/oscam -b -r 2 -u +} + +stop() { + logger "Stopping Oscam" + service_stop ${OSCAM_PATH}/oscam -b -r 2 -u +} + + diff --git a/package/lean/dvb/oscam/files/oscam.server b/package/lean/dvb/oscam/files/oscam.server new file mode 100644 index 000000000..fb6b220cb --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.server @@ -0,0 +1,61 @@ +# oscam.server generated automatically by Streamboard OSCAM 1.20-unstable_svn SVN r11401 +# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/oscam.server.txt + +[reader] +label = emulator +protocol = emu +device = emulator +caid = 0D00,0D02,090F,0500,1801,0604,2600,FFFF,0E00 +detect = cd +ident = 0D00:000000,000004,000010,000014,000020,0000C0,0000C4,0000C8,0000CC;0D02:000000,00008C,0000A0,0000A4,0000A8;090F:000000;0500:000000,030B00,023800,021110,007400,007800;1801:000000,007301,001101;0604:000000;2600:000000;FFFF:000000;0E00:000000 +group = 1 +emmcache = 2,3,2,0 +emu_auproviders = 0500:030B00;0604:010200;0E00:000000 + +# Example for NTV+, all disable + +[reader] +label = reshare1 +description = TVShara1 +enable = 0 +protocol = cccam +device = s4.oscam.org,444 +user = test1 +password = test1 +inactivitytimeout = 200 +reconnecttimeout = 10 +caid = 0500 +group = 1 +cccversion = 2.3.0 +cccreshare = 1 + +[reader] +label = reshare2 +description = TVShara2 +enable = 0 +protocol = newcamd +device = s4.oscam.org,2004 +key = 0102030405060708091011121314 +user = test2 +password = test2 +inactivitytimeout = 200 +reconnecttimeout = 10 +connectoninit = 1 +caid = 0500 +ident = 0500:060A00,041200,060C00,040620 +group = 1 +cccreshare = 1 + +[reader] +label = reshare3 +description = TVShara3 +enable = 0 +protocol = cs357x +device = s4.oscam.org,333 +user = test3 +password = test3 +caid = 0500 +ident = 0500:060A00,041200,060C00,040620 +group = 1 +cccreshare = 1 + diff --git a/package/lean/dvb/oscam/files/oscam.user b/package/lean/dvb/oscam/files/oscam.user new file mode 100644 index 000000000..5e02dd83e --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.user @@ -0,0 +1,27 @@ +# oscam.user generated automatically by Streamboard OSCAM 1.20-unstable_svn SVN r11401 +# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/oscam.user.txt + +[account] +user = tvheadend_x +pwd = tvheadend_x +monlevel = 4 +au = 1 +group = 1 +max_connections = 100 +cccreshare = 1 + +[account] +user = user1 +pwd = user1 +monlevel = 4 +au = 1 +group = 1 +max_connections = 100 +cccreshare = 1 + +[account] +user = monitor +pwd = monitor +monlevel = 4 +group = 1 + diff --git a/package/lean/dvb/oscam/patches/002-config.patch b/package/lean/dvb/oscam/patches/002-config.patch new file mode 100644 index 000000000..413122177 --- /dev/null +++ b/package/lean/dvb/oscam/patches/002-config.patch @@ -0,0 +1,41 @@ +diff -ruNp trunk.orig/config.h trunk/config.h +--- trunk.orig/config.h 2018-03-25 14:31:53.147349681 +0300 ++++ trunk/config.h 2018-03-25 14:46:42.842348711 +0300 +@@ -22,7 +22,7 @@ + //#define IPV6SUPPORT 1 + #define MODULE_MONITOR 1 + +-//#define MODULE_CAMD33 1 ++#define MODULE_CAMD33 1 + #define MODULE_CAMD35 1 + #define MODULE_CAMD35_TCP 1 + #define MODULE_NEWCAMD 1 +@@ -62,10 +62,14 @@ + #define CARDREADER_STINGER 1 + #define CARDREADER_DRECAS 1 + ++#define WITH_PCSC 1 ++ + #ifdef WITH_PCSC + #define CARDREADER_PCSC 1 + #endif + ++#define WITH_LIBUSB 1 ++ + #ifdef WITH_LIBUSB + #define CARDREADER_SMART 1 + #endif +@@ -83,11 +87,11 @@ + #endif + + #ifdef WITH_STAPI +-#define CARDREADER_STAPI 1 ++//#define CARDREADER_STAPI 1 + #endif + + #ifdef WITH_STAPI5 +-#define CARDREADER_STAPI5 1 ++//#define CARDREADER_STAPI5 1 + #endif + + #ifdef READER_DRE diff --git a/package/lean/dvb/oscam/patches/003-fix_ver.patch b/package/lean/dvb/oscam/patches/003-fix_ver.patch new file mode 100644 index 000000000..fa1551952 --- /dev/null +++ b/package/lean/dvb/oscam/patches/003-fix_ver.patch @@ -0,0 +1,121 @@ +diff -ruNp trunk.patches/globals.h trunk/globals.h +--- trunk.patches/globals.h 2018-04-03 02:48:24.952386413 +0300 ++++ trunk/globals.h 2018-04-03 03:02:59.558440627 +0300 +@@ -365,6 +365,9 @@ typedef unsigned char uchar; + #ifndef CS_SVN_VERSION + # define CS_SVN_VERSION "test" + #endif ++#ifndef CS_EMU_VERSION ++# define CS_EMU_VERSION "000" ++#endif + #ifndef CS_TARGET + # define CS_TARGET "unknown" + #endif +diff -ruNp trunk.patches/Makefile trunk/Makefile +--- trunk.patches/Makefile 2018-04-03 02:44:08.318254054 +0300 ++++ trunk/Makefile 2018-04-03 03:01:12.325689204 +0300 +@@ -5,7 +5,8 @@ SHELL = /bin/sh + .PHONY: all tests help README.build README.config simple default debug config menuconfig allyesconfig allnoconfig defconfig clean distclean + + VER := $(shell ./config.sh --oscam-version) +-SVN_REV := $(shell ./config.sh --oscam-revision) ++#SVN_REV := $(shell ./config.sh --oscam-revision) ++#EMU_REV := 000 + + uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') + +@@ -35,7 +36,7 @@ ifdef USE_SSL + override USE_LIBCRYPTO=1 + endif + +-CONF_DIR = /usr/local/etc ++CONF_DIR = /opt/etc/oscam + + LIB_PTHREAD = -lpthread + LIB_DL = -ldl +@@ -52,6 +53,7 @@ endif + + override STD_LIBS := $(LIB_PTHREAD) $(LIB_DL) $(LIB_RT) + override STD_DEFS := -D'CS_SVN_VERSION="$(SVN_REV)"' ++override STD_DEFS += -D'CS_EMU_VERSION="$(EMU_REV)"' + override STD_DEFS += -D'CS_CONFDIR="$(CONF_DIR)"' + + # Compiler warnings +diff -ruNp trunk.patches/module-dvbapi.c trunk/module-dvbapi.c +--- trunk.patches/module-dvbapi.c 2018-04-03 02:48:24.956386446 +0300 ++++ trunk/module-dvbapi.c 2018-04-03 03:06:13.063827549 +0300 +@@ -533,7 +533,7 @@ int32_t dvbapi_net_send(uint32_t request + if (cfg.dvbapi_extended_cw_api == 2) + strcat(capabilities, ",e2"); + +- *info_len = snprintf((char *) &packet[size], sizeof(packet) - size, "OSCam v%s, build r%s (%s); %s", CS_VERSION, CS_SVN_VERSION, CS_TARGET, capabilities + 1); ++ *info_len = snprintf((char *) &packet[size], sizeof(packet) - size, "OSCam v%s, build r%s + EMU r%s (%s); %s", CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION, CS_TARGET, capabilities + 1); + size += *info_len; + break; + } +diff -ruNp trunk.patches/module-lcd.c trunk/module-lcd.c +--- trunk.patches/module-lcd.c 2018-04-03 02:44:10.102269013 +0300 ++++ trunk/module-lcd.c 2018-04-03 03:15:44.360059325 +0300 +@@ -81,6 +81,7 @@ static void refresh_lcd_file(void) + + fprintf(fpsave, "Version: %s\n", CS_VERSION); + fprintf(fpsave, "Revision: %s\n", CS_SVN_VERSION); ++ fprintf(fpsave, "EMU rev.: %s\n", CS_EMU_VERSION); + if(days == 0) + { fprintf(fpsave, "up: %02d:%02d:%02d\n", hours, mins, secs); } + else +diff -ruNp trunk.patches/oscam.c trunk/oscam.c +--- trunk.patches/oscam.c 2018-04-03 02:48:24.956386446 +0300 ++++ trunk/oscam.c 2018-04-03 03:10:28.813703490 +0300 +@@ -144,7 +144,7 @@ static void show_usage(void) + "| | | \\___ \\| | / _` | '_ ` _ \\\n" + "| |_| |___) | |_| (_| | | | | | |\n" + " \\___/|____/ \\___\\__,_|_| |_| |_|\n\n"); +- printf("OSCam cardserver v%s, build r%s (%s)\n", CS_VERSION, CS_SVN_VERSION, CS_TARGET); ++ printf("OSCam cardserver v%s, build r%s + EMU r%s (%s)\n", CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION, CS_TARGET); + printf("Copyright (C) 2009-2015 OSCam developers.\n"); + printf("This program is distributed under GPLv3.\n"); + printf("OSCam is based on Streamboard mp-cardserver v0.9d written by dukat\n"); +@@ -376,6 +376,7 @@ static void write_versionfile(bool use_s + } + + fprintf(fp, "Version: oscam-%s-r%s\n", CS_VERSION, CS_SVN_VERSION); ++ fprintf(fp, "EMU: r%s\n", CS_EMU_VERSION); + fprintf(fp, "Compiler: %s\n", CS_TARGET); + fprintf(fp, "Box type: %s (%s)\n", boxtype_get(), boxname_get()); + fprintf(fp, "PID: %d\n", getppid()); +@@ -634,7 +635,7 @@ static void cs_dumpstack(int32_t sig) + + fprintf(stderr, "crashed with signal %d on %swriting oscam.crash\n", sig, buf); + +- fprintf(fp, "%sOSCam cardserver v%s, build r%s (%s)\n", buf, CS_VERSION, CS_SVN_VERSION, CS_TARGET); ++ fprintf(fp, "%sOSCam cardserver v%s, build r%s + EMU r%s (%s)\n", buf, CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION, CS_TARGET); + fprintf(fp, "FATAL: Signal %d: %s Fault. Logged StackTrace:\n\n", sig, (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown")); + fclose(fp); + +diff -ruNp trunk.patches/oscam-conf.c trunk/oscam-conf.c +--- trunk.patches/oscam-conf.c 2018-04-03 02:44:10.086268878 +0300 ++++ trunk/oscam-conf.c 2018-04-03 03:13:07.970887467 +0300 +@@ -509,8 +509,8 @@ FILE *create_config_file(const char *con + cs_log("ERROR: Cannot create file \"%s\" (errno=%d %s)", temp_file, errno, strerror(errno)); + return NULL; + } +- fprintf(f, "# %s generated automatically by Streamboard OSCAM %s SVN r%s\n", +- conf_filename, CS_VERSION, CS_SVN_VERSION); ++ fprintf(f, "# %s generated automatically by Streamboard OSCAM %s SVN r%s + EMU r%s\n", ++ conf_filename, CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION); + fprintf(f, "# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/%s.txt\n\n", + conf_filename); + return f; +diff -ruNp trunk.patches/oscam-log.c trunk/oscam-log.c +--- trunk.patches/oscam-log.c 2018-04-03 02:44:09.766266195 +0300 ++++ trunk/oscam-log.c 2018-04-03 03:12:04.910417167 +0300 +@@ -232,7 +232,7 @@ int32_t cs_open_logfiles(void) + // according to syslog docu: calling closelog is not necessary and calling openlog multiple times is safe + // We use openlog to set the default syslog settings so that it's possible to allow switching syslog on and off + openlog(syslog_ident, LOG_NDELAY | LOG_PID, LOG_DAEMON); +- cs_log(">> OSCam << cardserver %s, version " CS_VERSION ", build r" CS_SVN_VERSION " (" CS_TARGET ")", starttext); ++ cs_log(">> OSCam << cardserver %s, version " CS_VERSION ", build r" CS_SVN_VERSION " + EMU r" CS_EMU_VERSION " (" CS_TARGET ")", starttext); + + return (fp <= (FILE *)0); + } diff --git a/package/lean/dvb/oscam/patches/004-oscam_emu.patch b/package/lean/dvb/oscam/patches/004-oscam_emu.patch new file mode 100644 index 000000000..bcab190d7 --- /dev/null +++ b/package/lean/dvb/oscam/patches/004-oscam_emu.patch @@ -0,0 +1,12988 @@ +diff -ruNp trunk.patches/CMakeLists.txt trunk/CMakeLists.txt +--- trunk.patches/CMakeLists.txt 2018-04-03 02:44:09.770266229 +0300 ++++ trunk/CMakeLists.txt 2018-04-03 03:20:07.654045339 +0300 +@@ -101,6 +101,7 @@ include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR}/csctapi + ${CMAKE_CURRENT_SOURCE_DIR}/cscrypt + ${CMAKE_CURRENT_SOURCE_DIR}/minilzo ++ ${CMAKE_CURRENT_SOURCE_DIR}/ffdecsa + ${CMAKE_CURRENT_SOURCE_DIR}/extapi/cygwin + /usr/include/w32api + ${OPTIONAL_INCLUDE_DIR} +@@ -110,6 +111,7 @@ include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR}/csctapi + ${CMAKE_CURRENT_SOURCE_DIR}/cscrypt + ${CMAKE_CURRENT_SOURCE_DIR}/minilzo ++ ${CMAKE_CURRENT_SOURCE_DIR}/ffdecsa + ${OPTIONAL_INCLUDE_DIR} + ) + endif (OSCamOperatingSystem MATCHES "Windows/Cygwin") +@@ -420,6 +422,13 @@ endif (HAVE_PCSC) + # Manage config.h based on command line parameters + # Manipulate config file based on given parameters and read unset parameters + ++execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled WITH_EMU OUTPUT_VARIABLE CONFIG_WITH_EMU OUTPUT_STRIP_TRAILING_WHITESPACE) ++if (CONFIG_WITH_EMU MATCHES "Y" AND NOT WITH_EMU EQUAL 1) ++ add_definitions ("-DWITH_EMU") ++ set (WITH_EMU "1") ++ message(STATUS " EMU is added by config compiling with EMU") ++endif(CONFIG_WITH_EMU MATCHES "Y" AND NOT WITH_EMU EQUAL 1) ++ + execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --show-valid OUTPUT_VARIABLE config_vars_string OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCHALL "[A-Z0-9_]+" config_vars ${config_vars_string}) + +@@ -449,6 +458,7 @@ execute_process (COMMAND make --no-print + add_subdirectory (csctapi) + add_subdirectory (minilzo) + add_subdirectory (cscrypt) ++add_subdirectory (ffdecsa) + + #----------------------- file groups ------------------------------ + execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled MODULE_CAMD33 OUTPUT_VARIABLE CAMD33 OUTPUT_STRIP_TRAILING_WHITESPACE) +@@ -498,7 +508,7 @@ add_library (${csoscam} STATIC ${csoscam + + set (exe_name "oscam") + add_executable (${exe_name} ${exe_srcs} ${exe_hdrs}) +-target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo) ++target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo ffdecsa) + if(HAVE_LIBRT AND HAVE_LIBUSB) + if (LIBUSBDIR) + set (libusb_link "imp_libusb") +@@ -647,6 +657,11 @@ add_definitions ("-D'CS_SVN_VERSION=\"${ + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpmachine COMMAND tr -d '\n' OUTPUT_VARIABLE CS_TARGET) + add_definitions ("-D'CS_TARGET=\"${CS_TARGET}\"'") + #----------------------- global compile and link options ------------------------------ ++#enable sse2 on x86 ++if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") ++ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3") ++endif (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") ++ + # disable warning about unused but set variables in gcc 4.6+ + if (CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) +@@ -731,6 +746,22 @@ endif( HAVE_LIBRT OR HAVE_LIBRT_STATIC) + + #-------------------------------------------------------------------------------- + ++if (NOT OSCamOperatingSystem MATCHES "Mac OS X") ++if (NOT DEFINED ENV{ANDROID_NDK}) ++if (NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) ++ if(WITH_EMU) ++ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) ++ execute_process(COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key ${CMAKE_CURRENT_BINARY_DIR}/SoftCam.Key) ++ else(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) ++ execute_process(COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/SoftCam.Key) ++ endif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) ++ execute_process(COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/utils/SoftCam.Key) ++ set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--format=binary -Wl,SoftCam.Key -Wl,--format=default" ) ++ endif(WITH_EMU) ++endif (NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) ++endif (NOT DEFINED ENV{ANDROID_NDK}) ++endif (NOT OSCamOperatingSystem MATCHES "Mac OS X") ++ + #----------------------- installation ----------------------------- + + file (GLOB config_files "${CMAKE_CURRENT_SOURCE_DIR}/Distribution/oscam.*") +@@ -819,4 +850,8 @@ endif(STATIC_LIBUSB EQUAL 1) + endif(STATICLIBUSB AND NOT LIBUSBDIR) + endif (HAVE_LIBUSB) + ++if (WITH_EMU) ++ message(STATUS " Compile with EMU support") ++endif (WITH_EMU) ++ + message (STATUS "") +diff -ruNp trunk.patches/config.h trunk/config.h +--- trunk.patches/config.h 2018-04-03 02:48:33.320455383 +0300 ++++ trunk/config.h 2018-04-03 03:20:07.654045339 +0300 +@@ -1,6 +1,7 @@ + #ifndef CONFIG_H_ + #define CONFIG_H_ + ++#define WITH_EMU 1 + #define WEBIF 1 + #define WEBIF_LIVELOG 1 + #define WEBIF_JQUERY 1 +diff -ruNp trunk.patches/config.sh trunk/config.sh +--- trunk.patches/config.sh 2018-04-03 02:44:09.134260896 +0300 ++++ trunk/config.sh 2018-04-03 03:20:07.654045339 +0300 +@@ -1,6 +1,6 @@ + #!/bin/sh + +-addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT" ++addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_EMU" + 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_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" +@@ -24,6 +24,7 @@ CONFIG_CW_CYCLE_CHECK=y + # CONFIG_LEDSUPPORT=n + CONFIG_CLOCKFIX=y + # CONFIG_IPV6SUPPORT=n ++CONFIG_WITH_EMU=y + # CONFIG_MODULE_CAMD33=n + CONFIG_MODULE_CAMD35=y + CONFIG_MODULE_CAMD35_TCP=y +@@ -289,12 +290,15 @@ get_opts() { + + update_deps() { + # Calculate dependencies +- enabled_any $(get_opts readers) $(get_opts card_readers) && enable_opt WITH_CARDREADER >/dev/null +- disabled_all $(get_opts readers) $(get_opts card_readers) && disable_opt WITH_CARDREADER >/dev/null ++ enabled_any $(get_opts readers) $(get_opts card_readers) WITH_EMU && enable_opt WITH_CARDREADER >/dev/null ++ disabled_all $(get_opts readers) $(get_opts card_readers) WITH_EMU && disable_opt WITH_CARDREADER >/dev/null + disabled WEBIF && disable_opt WEBIF_LIVELOG >/dev/null + disabled WEBIF && disable_opt WEBIF_JQUERY >/dev/null + enabled MODULE_CCCSHARE && enable_opt MODULE_CCCAM >/dev/null + enabled_any CARDREADER_DB2COM CARDREADER_MP35 CARDREADER_SC8IN1 CARDREADER_STINGER && enable_opt CARDREADER_PHOENIX >/dev/null ++ enabled WITH_EMU && enable_opt READER_VIACCESS >/dev/null ++ enabled WITH_EMU && enable_opt READER_DRE >/dev/null ++ enabled WITH_EMU && enable_opt MODULE_NEWCAMD >/dev/null + } + + list_config() { +@@ -344,9 +348,9 @@ list_config() { + not_have_flag USE_LIBCRYPTO && echo "CONFIG_LIB_AES=y" || echo "# CONFIG_LIB_AES=n" + enabled MODULE_CCCAM && echo "CONFIG_LIB_RC6=y" || echo "# CONFIG_LIB_RC6=n" + not_have_flag USE_LIBCRYPTO && enabled MODULE_CCCAM && echo "CONFIG_LIB_SHA1=y" || echo "# CONFIG_LIB_SHA1=n" +- enabled_any READER_DRE MODULE_SCAM READER_VIACCESS && echo "CONFIG_LIB_DES=y" || echo "# CONFIG_LIB_DES=n" +- enabled_any MODULE_CCCAM READER_NAGRA READER_SECA && echo "CONFIG_LIB_IDEA=y" || echo "# CONFIG_LIB_IDEA=n" +- not_have_flag USE_LIBCRYPTO && enabled_any READER_CONAX READER_CRYPTOWORKS READER_NAGRA && echo "CONFIG_LIB_BIGNUM=y" || echo "# CONFIG_LIB_BIGNUM=n" ++ enabled_any READER_DRE MODULE_SCAM READER_VIACCESS WITH_EMU && echo "CONFIG_LIB_DES=y" || echo "# CONFIG_LIB_DES=n" ++ enabled_any MODULE_CCCAM READER_NAGRA READER_SECA WITH_EMU && echo "CONFIG_LIB_IDEA=y" || echo "# CONFIG_LIB_IDEA=n" ++ not_have_flag USE_LIBCRYPTO && enabled_any READER_CONAX READER_CRYPTOWORKS READER_NAGRA WITH_EMU && echo "CONFIG_LIB_BIGNUM=y" || echo "# CONFIG_LIB_BIGNUM=n" + } + + make_config_c() { +@@ -457,6 +461,7 @@ menu_addons() { + LEDSUPPORT "LED support" $(check_test "LEDSUPPORT") \ + CLOCKFIX "Clockfix (disable on old systems!)" $(check_test "CLOCKFIX") \ + IPV6SUPPORT "IPv6 support (experimental)" $(check_test "IPV6SUPPORT") \ ++ WITH_EMU "Emulator support" $(check_test "WITH_EMU") \ + 2> ${tempfile} + + opt=${?} +diff -ruNp trunk.patches/cscrypt/aes.c trunk/cscrypt/aes.c +--- trunk.patches/cscrypt/aes.c 2018-04-03 02:44:10.098268979 +0300 ++++ trunk/cscrypt/aes.c 2018-04-03 03:20:07.654045339 +0300 +@@ -1250,4 +1250,71 @@ void AES_decrypt(const unsigned char *in + rk[3]; + PUTU32(out + 12, s3); + } ++ ++void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, ++ const unsigned long length, const AES_KEY *key, ++ unsigned char *ivec, const int enc) ++{ ++ unsigned long n; ++ unsigned long len = length; ++ unsigned char tmp[AES_BLOCK_SIZE]; ++ ++ assert(in && out && key && ivec); ++ assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); ++ ++ if(AES_ENCRYPT == enc) ++ { ++ while(len >= AES_BLOCK_SIZE) ++ { ++ for(n=0; n < AES_BLOCK_SIZE; ++n) ++ tmp[n] = in[n] ^ ivec[n]; ++ ++ AES_encrypt(tmp, out, key); ++ memcpy(ivec, out, AES_BLOCK_SIZE); ++ len -= AES_BLOCK_SIZE; ++ in += AES_BLOCK_SIZE; ++ out += AES_BLOCK_SIZE; ++ } ++ ++ if(len) ++ { ++ for(n=0; n < len; ++n) ++ tmp[n] = in[n] ^ ivec[n]; ++ ++ for(n=len; n < AES_BLOCK_SIZE; ++n) ++ tmp[n] = ivec[n]; ++ ++ AES_encrypt(tmp, tmp, key); ++ memcpy(out, tmp, AES_BLOCK_SIZE); ++ memcpy(ivec, tmp, AES_BLOCK_SIZE); ++ } ++ } ++ else ++ { ++ while(len >= AES_BLOCK_SIZE) ++ { ++ memcpy(tmp, in, AES_BLOCK_SIZE); ++ AES_decrypt(in, out, key); ++ ++ for(n=0; n < AES_BLOCK_SIZE; ++n) ++ out[n] ^= ivec[n]; ++ ++ memcpy(ivec, tmp, AES_BLOCK_SIZE); ++ len -= AES_BLOCK_SIZE; ++ in += AES_BLOCK_SIZE; ++ out += AES_BLOCK_SIZE; ++ } ++ ++ if(len) ++ { ++ memcpy(tmp, in, AES_BLOCK_SIZE); ++ AES_decrypt(tmp, tmp, key); ++ ++ for(n=0; n < len; ++n) ++ out[n] ^= ivec[n]; ++ ++ memcpy(ivec, tmp, AES_BLOCK_SIZE); ++ } ++ } ++} + #endif +diff -ruNp trunk.patches/cscrypt/aes.h trunk/cscrypt/aes.h +--- trunk.patches/cscrypt/aes.h 2018-04-03 02:44:10.098268979 +0300 ++++ trunk/cscrypt/aes.h 2018-04-03 03:20:07.654045339 +0300 +@@ -42,6 +42,9 @@ void AES_encrypt(const unsigned char *in + void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + ++void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, ++ const unsigned long length, const AES_KEY *key, ++ unsigned char *ivec, const int enc); + #endif /* !HEADER_AES_H */ + + #endif +diff -ruNp trunk.patches/cscrypt/md5.c trunk/cscrypt/md5.c +--- trunk.patches/cscrypt/md5.c 2018-04-03 02:44:10.090268912 +0300 ++++ trunk/cscrypt/md5.c 2018-04-03 03:20:07.654045339 +0300 +@@ -25,13 +25,6 @@ + + #if !defined(WITH_SSL) && !defined(WITH_LIBCRYPTO) + +-typedef struct MD5Context +-{ +- uint32_t buf[4]; +- uint32_t bits[2]; +- uint32_t in[16]; +-} MD5_CTX; +- + #ifdef __i386__ + #define byteReverse(a, b) + #else +@@ -155,7 +148,7 @@ static void MD5_Transform(uint32_t buf[4 + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +-static void MD5_Init(MD5_CTX *ctx) ++void MD5_Init(MD5_CTX *ctx) + { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; +@@ -170,7 +163,7 @@ static void MD5_Init(MD5_CTX *ctx) + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +-static void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len) ++void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len) + { + uint32_t t; + +@@ -219,7 +212,7 @@ static void MD5_Update(MD5_CTX *ctx, con + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +-static void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) ++void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) + { + unsigned count; + unsigned char *p; +diff -ruNp trunk.patches/cscrypt/md5.h trunk/cscrypt/md5.h +--- trunk.patches/cscrypt/md5.h 2018-04-03 02:44:10.102269013 +0300 ++++ trunk/cscrypt/md5.h 2018-04-03 03:20:07.654045339 +0300 +@@ -7,8 +7,16 @@ + #define MD5_DIGEST_LENGTH 16 + + unsigned char *MD5(const unsigned char *input, unsigned long len, unsigned char *output_hash); +-#endif + +-char *__md5_crypt(const char *text_pass, const char *salt, char *crypted_passwd); ++typedef struct MD5Context { ++ uint32_t buf[4]; ++ uint32_t bits[2]; ++ uint32_t in[16]; ++} MD5_CTX; + ++void MD5_Init(MD5_CTX *ctx); ++void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len); ++void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx); ++#endif ++char *__md5_crypt(const char *text_pass, const char *salt, char *crypted_passwd); + #endif +diff -ruNp trunk.patches/csctapi/cardreaders.h trunk/csctapi/cardreaders.h +--- trunk.patches/csctapi/cardreaders.h 2018-04-03 02:44:09.226261666 +0300 ++++ trunk/csctapi/cardreaders.h 2018-04-03 03:20:07.654045339 +0300 +@@ -14,5 +14,6 @@ extern const struct s_cardreader cardrea + extern const struct s_cardreader cardreader_stapi; + extern const struct s_cardreader cardreader_stinger; + extern const struct s_cardreader cardreader_drecas; ++extern const struct s_cardreader cardreader_emu; + + #endif +diff -ruNp trunk.patches/ffdecsa/CMakeLists.txt trunk/ffdecsa/CMakeLists.txt +--- trunk.patches/ffdecsa/CMakeLists.txt 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/CMakeLists.txt 2018-04-03 03:20:07.654045339 +0300 +@@ -0,0 +1,8 @@ ++project (ffdecsa) ++ ++file (GLOB ffdecsa_srcs "ffdecsa.c") ++file (GLOB ffdecsa_hdrs "*.h") ++ ++set (lib_name "ffdecsa") ++ ++add_library (${lib_name} STATIC ${ffdecsa_srcs} ${ffdecsa_hdrs}) +diff -ruNp trunk.patches/ffdecsa/COPYING trunk/ffdecsa/COPYING +--- trunk.patches/ffdecsa/COPYING 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/COPYING 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,339 @@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 675 Mass Ave, Cambridge, MA 02139, USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ Appendix: How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) 19yy ++ ++ 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. ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) 19yy name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff -ruNp trunk.patches/ffdecsa/ffdecsa.c trunk/ffdecsa/ffdecsa.c +--- trunk.patches/ffdecsa/ffdecsa.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/ffdecsa.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,926 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 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 ++#include ++#include ++#include ++ ++#include "ffdecsa.h" ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++//#define DEBUG ++#ifdef DEBUG ++#define DBG(a) a ++#else ++#define DBG(a) ++#endif ++ ++//// parallelization stuff, large speed differences are possible ++// possible choices ++#define PARALLEL_32_4CHAR 320 ++#define PARALLEL_32_4CHARA 321 ++#define PARALLEL_32_INT 322 ++#define PARALLEL_64_8CHAR 640 ++#define PARALLEL_64_8CHARA 641 ++#define PARALLEL_64_2INT 642 ++#define PARALLEL_64_LONG 643 ++#define PARALLEL_64_MMX 644 ++#define PARALLEL_128_16CHAR 1280 ++#define PARALLEL_128_16CHARA 1281 ++#define PARALLEL_128_4INT 1282 ++#define PARALLEL_128_2LONG 1283 ++#define PARALLEL_128_2MMX 1284 ++#define PARALLEL_128_SSE 1285 ++#define PARALLEL_128_SSE2 1286 ++ ++//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// ++#ifndef PARALLEL_MODE ++ ++#if defined(__x86_64__) || defined(_M_X64) ++#define PARALLEL_MODE PARALLEL_128_SSE2 ++ ++#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) ++#define PARALLEL_MODE PARALLEL_64_LONG ++ ++#elif defined(__sh__) || defined(__SH4__) ++#define PARALLEL_MODE PARALLEL_32_INT ++#define COPY_UNALIGNED_PKT ++#define MEMALIGN_VAL 4 ++ ++#else ++#define PARALLEL_MODE PARALLEL_32_INT ++#endif ++ ++#endif ++//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// ++ ++#include "parallel_generic.h" ++//// conditionals ++#if PARALLEL_MODE==PARALLEL_32_4CHAR ++#include "parallel_032_4char.h" ++#elif PARALLEL_MODE==PARALLEL_32_4CHARA ++#include "parallel_032_4charA.h" ++#elif PARALLEL_MODE==PARALLEL_32_INT ++#include "parallel_032_int.h" ++#elif PARALLEL_MODE==PARALLEL_64_8CHAR ++#include "parallel_064_8char.h" ++#elif PARALLEL_MODE==PARALLEL_64_8CHARA ++#include "parallel_064_8charA.h" ++#elif PARALLEL_MODE==PARALLEL_64_2INT ++#include "parallel_064_2int.h" ++#elif PARALLEL_MODE==PARALLEL_64_LONG ++#include "parallel_064_long.h" ++#elif PARALLEL_MODE==PARALLEL_64_MMX ++#include "parallel_064_mmx.h" ++#elif PARALLEL_MODE==PARALLEL_128_16CHAR ++#include "parallel_128_16char.h" ++#elif PARALLEL_MODE==PARALLEL_128_16CHARA ++#include "parallel_128_16charA.h" ++#elif PARALLEL_MODE==PARALLEL_128_4INT ++#include "parallel_128_4int.h" ++#elif PARALLEL_MODE==PARALLEL_128_2LONG ++#include "parallel_128_2long.h" ++#elif PARALLEL_MODE==PARALLEL_128_2MMX ++#include "parallel_128_2mmx.h" ++#elif PARALLEL_MODE==PARALLEL_128_SSE ++#include "parallel_128_sse.h" ++#elif PARALLEL_MODE==PARALLEL_128_SSE2 ++#include "parallel_128_sse2.h" ++#else ++#error "unknown/undefined parallel mode" ++#endif ++ ++// stuff depending on conditionals ++ ++#define BYTES_PER_GROUP (GROUP_PARALLELISM/8) ++#define BYPG BYTES_PER_GROUP ++#define BITS_PER_GROUP GROUP_PARALLELISM ++#define BIPG BITS_PER_GROUP ++ ++// platform specific ++ ++#ifdef __arm__ ++#if !defined(MEMALIGN_VAL) || MEMALIGN_VAL<4 ++#undef MEMALIGN_VAL ++#define MEMALIGN_VAL 4 ++#endif ++#define COPY_UNALIGNED_PKT ++#endif ++ ++// ++ ++#ifndef MALLOC ++#define MALLOC(X) malloc(X) ++#endif ++#ifndef FREE ++#define FREE(X) free(X) ++#endif ++#ifdef MEMALIGN_VAL ++#define MEMALIGN __attribute__((aligned(MEMALIGN_VAL))) ++#else ++#define MEMALIGN ++#endif ++ ++//// debug tool ++ ++#ifdef DEBUG ++static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){ ++ int i; ++ for(i=0;i>4)&0xf; ++ iA[1]=(ck[0] )&0xf; ++ iA[2]=(ck[1]>>4)&0xf; ++ iA[3]=(ck[1] )&0xf; ++ iA[4]=(ck[2]>>4)&0xf; ++ iA[5]=(ck[2] )&0xf; ++ iA[6]=(ck[3]>>4)&0xf; ++ iA[7]=(ck[3] )&0xf; ++ iB[0]=(ck[4]>>4)&0xf; ++ iB[1]=(ck[4] )&0xf; ++ iB[2]=(ck[5]>>4)&0xf; ++ iB[3]=(ck[5] )&0xf; ++ iB[4]=(ck[6]>>4)&0xf; ++ iB[5]=(ck[6] )&0xf; ++ iB[6]=(ck[7]>>4)&0xf; ++ iB[7]=(ck[7] )&0xf; ++} ++ ++//----- stream main function ++ ++#define STREAM_INIT ++#include "stream.c" ++#undef STREAM_INIT ++ ++#define STREAM_NORMAL ++#include "stream.c" ++#undef STREAM_NORMAL ++ ++ ++//-----block decypher ++ ++//-----key schedule for block decypher ++ ++static void key_schedule_block( ++ unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. ++ unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule. ++{ ++ 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, ++ }; ++ ++ 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) ++ 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){ ++ int *ri=(int *)in; ++ int *ibi=(int *)out; ++ int j,i,k,g; ++ // copy and first step ++ for(g=0;g>16) | (b&0xffff0000) ; ++ } ++ } ++ } ++//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 01010101 ++ for(j=0;j<8;j+=2){ ++ for(i=0;i<1;i++){ ++ for(k=0;k>8) | (b&0xff00ff00); ++ } ++ } ++ } ++//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 00000000 ++} ++ ++static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){ ++ int *ri=(int *)in; ++ int *bdi=(int *)out; ++ int j,i,k,g; ++#define INTS_PER_ROW (GROUP_PARALLELISM/8*2) ++//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 00000000 ++ for(j=0;j<8;j+=2){ ++ for(i=0;i<1;i++){ ++ for(k=0;k>8) | (b&0xff00ff00); ++ } ++ } ++ } ++//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 01010101 ++ for(j=0;j<8;j+=4){ ++ for(i=0;i<2;i++){ ++ for(k=0;k>16) | (b&0xffff0000) ; ++ } ++ } ++ } ++//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 01230123 ++ for(g=0;g=0;i--){ ++ { ++ MEMALIGN batch tkkmulti=kkmulti[i]; ++ batch *si=(batch *)sbox_in; ++ batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6); ++ for(g=0;gck,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<iA_g[by][bi]=(key->iA[by]&(1<iB_g[by][bi]=(key->iB[by]&(1<ck,key->kk); ++ for(i=0;i<56;i++){ ++ for(j=0;jkkmulti[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); ++} ++ ++void set_even_control_word(void *keys, const unsigned char *pk){ ++ schedule_key(&((struct csa_keys_t *)keys)->even,pk); ++} ++ ++void set_odd_control_word(void *keys, const unsigned char *pk){ ++ schedule_key(&((struct csa_keys_t *)keys)->odd,pk); ++} ++ ++//-----get control words ++ ++void get_control_words(void *keys, unsigned char *even, unsigned char *odd){ ++ memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8); ++ memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8); ++} ++ ++//----- decrypt ++ ++int decrypt_packets(void *keys, unsigned char **cluster){ ++ // statistics, currently unused ++ int stat_no_scramble=0; ++ int stat_reserved=0; ++ int stat_decrypted[2]={0,0}; ++ int stat_decrypted_mini=0; ++ unsigned char **clst; ++ unsigned char **clst2; ++ int grouped; ++ int group_ev_od; ++ int advanced; ++ int can_advance; ++ unsigned char *g_pkt[GROUP_PARALLELISM]; ++ int g_len[GROUP_PARALLELISM]; ++ int g_offset[GROUP_PARALLELISM]; ++ int g_n[GROUP_PARALLELISM]; ++ int g_residue[GROUP_PARALLELISM]; ++ unsigned char *pkt; ++ int xc0,ev_od,len,offset,n,residue; ++ struct csa_key_t* k; ++ int i,j,iter,g; ++ int t23,tsmall; ++ int alive[24]; ++//icc craziness int pad1=0; //////////align! FIXME ++ unsigned char *encp[GROUP_PARALLELISM]; ++ MEMALIGN unsigned char stream_in[GROUP_PARALLELISM*8]; ++ MEMALIGN unsigned char stream_out[GROUP_PARALLELISM*8]; ++ MEMALIGN unsigned char ib[GROUP_PARALLELISM*8]; ++ MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8]; ++#ifdef COPY_UNALIGNED_PKT ++ unsigned char *unaligned[GROUP_PARALLELISM]; ++ MEMALIGN unsigned char alignedBuff[GROUP_PARALLELISM][188]; ++#endif ++ struct stream_regs regs; ++ ++//icc craziness i=(int)&pad1;//////////align!!! FIXME ++ ++ // build a list of packets to be processed ++ clst=cluster; ++ grouped=0; ++ advanced=0; ++ can_advance=1; ++ group_ev_od=-1; // silence incorrect compiler warning ++ pkt=*clst; ++ do{ // find a new packet ++ if(grouped==GROUP_PARALLELISM){ ++ // full ++ break; ++ } ++ if(pkt==NULL){ ++ // no more ranges ++ break; ++ } ++ if(pkt>=*(clst+1)){ ++ // out of this range, try next ++ clst++;clst++; ++ pkt=*clst; ++ continue; ++ } ++ ++ do{ // handle this packet ++ xc0=pkt[3]&0xc0; ++ DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance)); ++ if(xc0==0x00){ ++ DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance)); ++ advanced+=can_advance; ++ stat_no_scramble++; ++ break; ++ } ++ if(xc0==0x40){ ++ DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance)); ++ advanced+=can_advance; ++ stat_reserved++; ++ break; ++ } ++ if(xc0==0x80||xc0==0xc0){ // encrypted ++ ev_od=(xc0&0x40)>>6; // 0 even, 1 odd ++ if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd) ++ if(group_ev_od==ev_od){ // could be added to group ++ pkt[3]&=0x3f; // consider it decrypted now ++ if(pkt[3]&0x20){ // incomplete packet ++ offset=4+pkt[4]+1; ++ len=188-offset; ++ n=len>>3; ++ residue=len-(n<<3); ++ if(n==0){ // decrypted==encrypted! ++ DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance)); ++ advanced+=can_advance; ++ stat_decrypted_mini++; ++ break; // this doesn't need more processing ++ } ++ }else{ ++ len=184; ++ offset=4; ++ n=23; ++ residue=0; ++ } ++ g_pkt[grouped]=pkt; ++ g_len[grouped]=len; ++ g_offset[grouped]=offset; ++ g_n[grouped]=n; ++ g_residue[grouped]=residue; ++ DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue)); ++ grouped++; ++ advanced+=can_advance; ++ stat_decrypted[ev_od]++; ++ } ++ else{ ++ can_advance=0; ++ DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt)); ++ break; // skip and go on ++ } ++ } ++ } while(0); ++ ++ if(can_advance){ ++ // move range start forward ++ *clst+=188; ++ } ++ // next packet, if there is one ++ pkt+=188; ++ } while(1); ++ DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced)); ++ ++ // delete empty ranges and compact list ++ clst2=cluster; ++ for(clst=cluster;*clst!=NULL;clst+=2){ ++ // if not empty ++ if(*clst<*(clst+1)){ ++ // it will remain ++ *clst2=*clst; ++ *(clst2+1)=*(clst+1); ++ clst2+=2; ++ } ++ } ++ *clst2=NULL; ++ ++ if(grouped==0){ ++ // no processing needed ++ return advanced; ++ } ++ ++ // sort them, longest payload first ++ // we expect many n=23 packets and a few n<23 ++ DBG(fprintf(stderr,"PRESORTING\n")); ++ for(i=0;i=0;tsmall--){ ++ if(g_n[tsmall]==23) break; ++ } ++DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall)); ++ ++ if(tsmall-t23<1) break; ++ ++DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall)); ++ ++ g_swap(t23,tsmall); ++ ++ t23++; ++ tsmall--; ++DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall)); ++ } ++ DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped)); ++ DBG(fprintf(stderr,"MIDSORTING\n")); ++ for(i=0;ig_n[i]){ ++ g_swap(i,j); ++ } ++ } ++ } ++ DBG(fprintf(stderr,"POSTSORTING\n")); ++ for(i=0;i=0;i--){ ++ alive[i]+=alive[i+1]; ++ } ++ DBG(fprintf(stderr,"ALIVE\n")); ++ for(i=0;i<=23;i++){ ++ DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i])); ++ } ++ ++ // choose key ++ if(group_ev_od==0){ ++ k=&((struct csa_keys_t *)keys)->even; ++ } ++ else{ ++ k=&((struct csa_keys_t *)keys)->odd; ++ } ++ ++ //INIT ++//#define INITIALIZE_UNUSED_INPUT ++#ifdef INITIALIZE_UNUSED_INPUT ++// unnecessary zeroing. ++// without this, we operate on uninitialized memory ++// when grouped>>>>ITER 0\n")); ++ iter=0; ++ stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in); ++ // fill first ib ++ for(g=0;g0;iter++){ ++DBG(fprintf(stderr,">>>>>ITER %i\n",iter)); ++ // alive and just dead packets: calc block ++ block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); ++DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8)); ++ // all packets (dead too): calc stream ++ stream_cypher_group_normal(®s,stream_out); ++//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG); ++ ++ // alive packets: calc ib ++ for(g=0;g>>>>ITER 23\n")); ++ iter=23; ++ // calc block ++ block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); ++DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8)); ++ // just dead packets: write decrypted data ++ for(g=alive[iter];g=4?32-1:0))+j); ++ } ++} ++ ++typedef unsigned int batch; ++#define BYTES_PER_BATCH 4 ++#define B_FFN_ALL_29() 0x29292929 ++#define B_FFN_ALL_02() 0x02020202 ++#define B_FFN_ALL_04() 0x04040404 ++#define B_FFN_ALL_10() 0x10101010 ++#define B_FFN_ALL_40() 0x40404040 ++#define B_FFN_ALL_80() 0x80808080 ++ ++#define M_EMPTY() +diff -ruNp trunk.patches/ffdecsa/parallel_064_long.h trunk/ffdecsa/parallel_064_long.h +--- trunk.patches/ffdecsa/parallel_064_long.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_064_long.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,39 @@ ++/* 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 "parallel_std_def.h" ++ ++typedef unsigned long long group; ++#define GROUP_PARALLELISM 64 ++#define FF0() 0x0ULL ++#define FF1() 0xffffffffffffffffULL ++ ++typedef unsigned long long batch; ++#define BYTES_PER_BATCH 8 ++#define B_FFN_ALL_29() 0x2929292929292929ULL ++#define B_FFN_ALL_02() 0x0202020202020202ULL ++#define B_FFN_ALL_04() 0x0404040404040404ULL ++#define B_FFN_ALL_10() 0x1010101010101010ULL ++#define B_FFN_ALL_40() 0x4040404040404040ULL ++#define B_FFN_ALL_80() 0x8080808080808080ULL ++ ++#define M_EMPTY() ++ ++#include "fftable.h" +diff -ruNp trunk.patches/ffdecsa/parallel_128_sse2.h trunk/ffdecsa/parallel_128_sse2.h +--- trunk.patches/ffdecsa/parallel_128_sse2.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_128_sse2.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,82 @@ ++/* 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 ++ ++#define MEMALIGN_VAL 16 ++ ++union __u128i { ++ unsigned int u[4]; ++ __m128i v; ++}; ++ ++static const union __u128i ff0 = {{0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}}; ++static const union __u128i ff1 = {{0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU}}; ++ ++typedef __m128i group; ++#define GROUP_PARALLELISM 128 ++#define FF0() ff0.v ++#define FF1() ff1.v ++#define FFAND(a,b) _mm_and_si128((a),(b)) ++#define FFOR(a,b) _mm_or_si128((a),(b)) ++#define FFXOR(a,b) _mm_xor_si128((a),(b)) ++#define FFNOT(a) _mm_xor_si128((a),FF1()) ++#define MALLOC(X) _mm_malloc(X,16) ++#define FREE(X) _mm_free(X) ++ ++/* 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 __m128i 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) _mm_slli_epi64((a),(n)) ++#define B_FFSH8R(a,n) _mm_srli_epi64((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) ++{ ++ __m128i vs1 = _mm_load_si128((__m128i*)s1); ++ __m128i vs2 = _mm_load_si128((__m128i*)s2); ++ vs1 = _mm_xor_si128(vs1, vs2); ++ _mm_store_si128((__m128i*)d, vs1); ++} ++ ++#include "fftable.h" +diff -ruNp trunk.patches/ffdecsa/parallel_generic.h trunk/ffdecsa/parallel_generic.h +--- trunk.patches/ffdecsa/parallel_generic.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_generic.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,102 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 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. ++ */ ++ ++ ++ ++#if 0 ++//// generics ++#define COPY4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd = *ps; }while(0) ++#define COPY8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; }while(0) ++#define COPY16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; \ ++ *(pd+1) = *(ps+1); }while(0) ++#define COPY32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; \ ++ *(pd+1) = *(ps+1) \ ++ *(pd+2) = *(ps+2) \ ++ *(pd+3) = *(ps+3); }while(0) ++#define XOR4BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOR8BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOR16BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; \ ++ *(pd+8) = *(ps1+8) ^ *(ps2+8); }while(0) ++#define XOR32BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; \ ++ *(pd+1) = *(ps1+1) ^ *(ps2+1); \ ++ *(pd+2) = *(ps1+2) ^ *(ps2+2); \ ++ *(pd+3) = *(ps1+3) ^ *(ps2+3); }while(0) ++#define XOR32BV(d,s1,s2) do{ int *const pd=(int *const)(d), *ps1=(const int *const)(s1), *ps2=(const int *const)(s2); \ ++ int z; \ ++ for(z=0;z<8;z++){ \ ++ pd[z]=ps1[z]^ps2[z]; \ ++ } \ ++ }while(0) ++#define XOREQ4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define XOREQ8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define XOREQ16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; \ ++ *(pd+1) ^=*(ps+1); }while(0) ++#define XOREQ32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; \ ++ *(pd+1) ^=*(ps+1); \ ++ *(pd+2) ^=*(ps+2); \ ++ *(pd+3) ^=*(ps+3); }while(0) ++#define XOREQ32BY4(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd ^= *ps; \ ++ *(pd+1) ^=*(ps+1); \ ++ *(pd+2) ^=*(ps+2); \ ++ *(pd+3) ^=*(ps+3); \ ++ *(pd+4) ^=*(ps+4); \ ++ *(pd+5) ^=*(ps+5); \ ++ *(pd+6) ^=*(ps+6); \ ++ *(pd+7) ^=*(ps+7); }while(0) ++#define XOREQ32BV(d,s) do{ unsigned char *pd=(unsigned char *)(d), *ps=(unsigned char *)(s); \ ++ int z; \ ++ for(z=0;z<32;z++){ \ ++ pd[z]^=ps[z]; \ ++ } \ ++ }while(0) ++ ++#else ++#define XOR_4_BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOR_8_BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOREQ_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define XOREQ_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define COPY_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd = *ps; }while(0) ++#define COPY_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; }while(0) ++ ++#define BEST_SPAN 8 ++#define XOR_BEST_BY(d,s1,s2) do{ XOR_8_BY(d,s1,s2); }while(0); ++#define XOREQ_BEST_BY(d,s) do{ XOREQ_8_BY(d,s); }while(0); ++#define COPY_BEST_BY(d,s) do{ COPY_8_BY(d,s); }while(0); ++ ++#define END_MM do{ }while(0); ++#endif +diff -ruNp trunk.patches/ffdecsa/parallel_std_def.h trunk/ffdecsa/parallel_std_def.h +--- trunk.patches/ffdecsa/parallel_std_def.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_std_def.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,29 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 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. ++ */ ++ ++#define FFXOR(a,b) ((a)^(b)) ++#define FFAND(a,b) ((a)&(b)) ++#define FFOR(a,b) ((a)|(b)) ++#define FFNOT(a) (~(a)) ++ ++#define B_FFAND(a,b) ((a)&(b)) ++#define B_FFOR(a,b) ((a)|(b)) ++#define B_FFXOR(a,b) ((a)^(b)) ++#define B_FFSH8L(a,n) ((a)<<(n)) ++#define B_FFSH8R(a,n) ((a)>>(n)) +diff -ruNp trunk.patches/ffdecsa/stream.c trunk/ffdecsa/stream.c +--- trunk.patches/ffdecsa/stream.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/stream.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,906 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 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. ++ */ ++ ++ ++ ++// define statics only once, when STREAM_INIT ++#ifdef STREAM_INIT ++struct stream_regs { ++ group A[32+10][4]; // 32 because we will move back (virtual shift register) ++ group B[32+10][4]; // 32 because we will move back (virtual shift register) ++ group X[4]; ++ group Y[4]; ++ group Z[4]; ++ group D[4]; ++ group E[4]; ++ group F[4]; ++ group p; ++ group q; ++ group r; ++ }; ++ ++static inline void trasp64_32_88ccw(unsigned char *data){ ++/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ ++#define row ((unsigned int *)data) ++ int i,j; ++ for(j=0;j<64;j+=32){ ++ unsigned int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff) | ((b )<<16); ++ row[j+16+i]=((t )>>16) | (b&0xffff0000) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); ++ row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0x0f0f0f0f)<<4) | (b&0x0f0f0f0f); ++ row[j+4+i] = (t&0xf0f0f0f0) | ((b&0xf0f0f0f0)>>4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0x33333333)<<2) | (b&0x33333333); ++ row[j+2+i] = (t&0xcccccccc) | ((b&0xcccccccc)>>2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0x55555555)<<1) | (b&0x55555555); ++ row[j+1+i] = (t&0xaaaaaaaa) | ((b&0xaaaaaaaa)>>1); ++ } ++ } ++#undef row ++} ++ ++static inline void trasp64_32_88cw(unsigned char *data){ ++/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ ++#define row ((unsigned int *)data) ++ int i,j; ++ for(j=0;j<64;j+=32){ ++ unsigned int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff) | ((b )<<16); ++ row[j+16+i]=((t )>>16) | (b&0xffff0000) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); ++ row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0xf0f0f0f0)>>4) | (b&0xf0f0f0f0); ++ row[j+4+i]= (t&0x0f0f0f0f) | ((b&0x0f0f0f0f)<<4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0xcccccccc)>>2) | (b&0xcccccccc); ++ row[j+2+i]= (t&0x33333333) | ((b&0x33333333)<<2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0xaaaaaaaa)>>1) | (b&0xaaaaaaaa); ++ row[j+1+i]= (t&0x55555555) | ((b&0x55555555)<<1); ++ } ++ } ++#undef row ++} ++ ++//64-64---------------------------------------------------------- ++static inline void trasp64_64_88ccw(unsigned char *data){ ++/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ ++#define row ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=row[j+i]; ++ b=row[j+32+i]; ++ row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); ++ row[j+4+i] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); ++ row[j+2+i] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); ++ row[j+1+i] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); ++ } ++ } ++#undef row ++} ++ ++static inline void trasp64_64_88cw(unsigned char *data){ ++/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ ++#define row ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=row[j+i]; ++ b=row[j+32+i]; ++ row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); ++ row[j+4+i] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); ++ row[j+2+i] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); ++ row[j+1+i] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); ++ } ++ } ++#undef row ++} ++ ++//64-128---------------------------------------------------------- ++static inline void trasp64_128_88ccw(unsigned char *data){ ++/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ ++#define halfrow ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+32+i)]; ++ halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+32+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+16+i)]; ++ halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+16+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+8+i)]; ++ halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+8+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+4+i)]; ++ halfrow[2*(j+i)] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); ++ halfrow[2*(j+4+i)] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+4+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); ++ halfrow[2*(j+4+i)+1] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+2+i)]; ++ halfrow[2*(j+i)] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); ++ halfrow[2*(j+2+i)] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+2+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); ++ halfrow[2*(j+2+i)+1] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+1+i)]; ++ halfrow[2*(j+i)] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); ++ halfrow[2*(j+1+i)] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+1+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); ++ halfrow[2*(j+1+i)+1] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); ++ } ++ } ++#undef halfrow ++} ++ ++static inline void trasp64_128_88cw(unsigned char *data){ ++/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ ++#define halfrow ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+32+i)]; ++ halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+32+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+16+i)]; ++ halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+16+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+8+i)]; ++ halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+8+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+4+i)]; ++ halfrow[2*(j+i)] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); ++ halfrow[2*(j+4+i)] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+4+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); ++ halfrow[2*(j+4+i)+1] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+2+i)]; ++ halfrow[2*(j+i)] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); ++ halfrow[2*(j+2+i)] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+2+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); ++ halfrow[2*(j+2+i)+1] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+1+i)]; ++ halfrow[2*(j+i)] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); ++ halfrow[2*(j+1+i)] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+1+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); ++ halfrow[2*(j+1+i)+1] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); ++ } ++ } ++#undef halfrow ++} ++#endif ++ ++ ++#ifdef STREAM_INIT ++void stream_cypher_group_init( ++ struct stream_regs *regs, ++ group iA[8][4], // [In] iA00,iA01,...iA73 32 groups | Derived from key. ++ group iB[8][4], // [In] iB00,iB01,...iB73 32 groups | Derived from key. ++ unsigned char *sb) // [In] (SB0,SB1,...SB7)...x32 32*8 bytes | Extra input. ++#endif ++#ifdef STREAM_NORMAL ++void stream_cypher_group_normal( ++ struct stream_regs *regs, ++ unsigned char *cb) // [Out] (CB0,CB1,...CB7)...x32 32*8 bytes | Output. ++#endif ++{ ++#ifdef STREAM_INIT ++ group in1[4]; ++ group in2[4]; ++#endif ++ group extra_B[4]; ++ group fa,fb,fc,fd,fe; ++ group s1a,s1b,s2a,s2b,s3a,s3b,s4a,s4b,s5a,s5b,s6a,s6b,s7a,s7b; ++ group next_E[4]; ++ group tmp0,tmp1,tmp2,tmp3,tmp4; ++#ifdef STREAM_INIT ++ group *sb_g=(group *)sb; ++#endif ++#ifdef STREAM_NORMAL ++ group *cb_g=(group *)cb; ++#endif ++ int aboff; ++ int i,j,k,b; ++ int dbg; ++ ++#ifdef STREAM_INIT ++ DBG(fprintf(stderr,":::::::::: BEGIN STREAM INIT\n")); ++#endif ++#ifdef STREAM_NORMAL ++ DBG(fprintf(stderr,":::::::::: BEGIN STREAM NORMAL\n")); ++#endif ++#ifdef STREAM_INIT ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"precall prerot stream_in[%2i]=",j)); ++ DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); ++} ++ ++DBG(dump_mem("stream_prerot ",sb,GROUP_PARALLELISM*8,BYPG)); ++#if GROUP_PARALLELISM==32 ++trasp64_32_88ccw(sb); ++#endif ++#if GROUP_PARALLELISM==64 ++trasp64_64_88ccw(sb); ++#endif ++#if GROUP_PARALLELISM==128 ++trasp64_128_88ccw(sb); ++#endif ++DBG(dump_mem("stream_postrot",sb,GROUP_PARALLELISM*8,BYPG)); ++ ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"precall stream_in[%2i]=",j)); ++ DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); ++} ++#endif ++ ++ aboff=32; ++ ++#ifdef STREAM_INIT ++ // load first 32 bits of ck into A[aboff+0]..A[aboff+7] ++ // load last 32 bits of ck into B[aboff+0]..B[aboff+7] ++ // all other regs = 0 ++ for(i=0;i<8;i++){ ++ for(b=0;b<4;b++){ ++DBG(fprintf(stderr,"dbg from iA A[%i][%i]=",i,b)); ++DBG(dump_mem("",(unsigned char *)&iA[i][b],BYPG,BYPG)); ++DBG(fprintf(stderr," dbg from iB B[%i][%i]=",i,b)); ++DBG(dump_mem("",(unsigned char *)&iB[i][b],BYPG,BYPG)); ++ regs->A[aboff+i][b]=iA[i][b]; ++ regs->B[aboff+i][b]=iB[i][b]; ++ } ++ } ++ for(b=0;b<4;b++){ ++ regs->A[aboff+8][b]=FF0(); ++ regs->A[aboff+9][b]=FF0(); ++ regs->B[aboff+8][b]=FF0(); ++ regs->B[aboff+9][b]=FF0(); ++ } ++ for(b=0;b<4;b++){ ++ regs->X[b]=FF0(); ++ regs->Y[b]=FF0(); ++ regs->Z[b]=FF0(); ++ regs->D[b]=FF0(); ++ regs->E[b]=FF0(); ++ regs->F[b]=FF0(); ++ } ++ regs->p=FF0(); ++ regs->q=FF0(); ++ regs->r=FF0(); ++#endif ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"dbg A0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->A[aboff+0][dbg],BYPG,BYPG)); ++ DBG(fprintf(stderr,"dbg B0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->B[aboff+0][dbg],BYPG,BYPG)); ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++ ++ // EXTERNAL LOOP - 8 bytes per operation ++ for(i=0;i<8;i++){ ++ ++ DBG(fprintf(stderr,"--BEGIN EXTERNAL LOOP %i\n",i)); ++ ++#ifdef STREAM_INIT ++ for(b=0;b<4;b++){ ++ in1[b]=sb_g[8*i+4+b]; ++ in2[b]=sb_g[8*i+b]; ++ } ++#endif ++ ++ // INTERNAL LOOP - 2 bits per iteration ++ for(j=0; j<4; j++){ ++ ++ DBG(fprintf(stderr,"---BEGIN INTERNAL LOOP %i (EXT %i, INT %i)\n",j,i,j)); ++ ++ // from A0..A9, 35 bits are selected as inputs to 7 s-boxes ++ // 5 bits input per s-box, 2 bits output per s-box ++ ++ // we can select bits with zero masking and shifting operations ++ // and synthetize s-boxes with optimized boolean functions. ++ // this is the actual reason we do all the crazy transposition ++ // stuff to switch between normal and bit slice representations. ++ // this code really flies. ++ ++ fe=regs->A[aboff+3][0];fa=regs->A[aboff+0][2];fb=regs->A[aboff+5][1];fc=regs->A[aboff+6][3];fd=regs->A[aboff+8][0]; ++/* 1000 1110 1110 0001 : lev 7: */ //tmp0=( fa^( fb^( ( ( ( fa|fb )^fc )|( fc^fd ) )^ALL_ONES ) ) ); ++/* 1110 0010 0011 0011 : lev 6: */ //tmp1=( ( fa|fb )^( ( fc&( fa|( fb^fd ) ) )^ALL_ONES ) ); ++/* 0011 0110 1000 1101 : lev 5: */ //tmp2=( fa^( ( fb&fd )^( ( fa&fd )|fc ) ) ); ++/* 0101 0101 1001 0011 : lev 5: */ //tmp3=( ( fa&fc )^( fa^( ( fa&fb )|fd ) ) ); ++/* 1000 1110 1110 0001 : lev 7: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFOR(FFXOR(FFOR(fa,fb),fc),FFXOR(fc,fd)),FF1()))); ++/* 1110 0010 0011 0011 : lev 6: */ tmp1=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fa,FFXOR(fb,fd))),FF1())); ++/* 0011 0110 1000 1101 : lev 5: */ tmp2=FFXOR(fa,FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),fc))); ++/* 0101 0101 1001 0011 : lev 5: */ tmp3=FFXOR(FFAND(fa,fc),FFXOR(fa,FFOR(FFAND(fa,fb),fd))); ++ s1a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s1b=FFXOR(tmp2,FFAND(fe,tmp3)); ++//dump_mem("s1as1b-fe",&fe,BYPG,BYPG); ++//dump_mem("s1as1b-fa",&fa,BYPG,BYPG); ++//dump_mem("s1as1b-fb",&fb,BYPG,BYPG); ++//dump_mem("s1as1b-fc",&fc,BYPG,BYPG); ++//dump_mem("s1as1b-fd",&fd,BYPG,BYPG); ++ ++ fe=regs->A[aboff+1][1];fa=regs->A[aboff+2][2];fb=regs->A[aboff+5][3];fc=regs->A[aboff+6][0];fd=regs->A[aboff+8][1]; ++/* 1001 1110 0110 0001 : lev 6: */ //tmp0=( fa^( ( fb&( fc|fd ) )^( fc^( fd^ALL_ONES ) ) ) ); ++/* 0000 0011 0111 1011 : lev 5: */ //tmp1=( ( fa&( fb^fd ) )|( ( fa|fb )&fc ) ); ++/* 1100 0110 1101 0010 : lev 6: */ //tmp2=( ( fb&fd )^( ( fa&fd )|( fb^( fc^ALL_ONES ) ) ) ); ++/* 0001 1110 1111 0101 : lev 5: */ //tmp3=( ( fa&fd )|( fa^( fb^( fc&fd ) ) ) ); ++/* 1001 1110 0110 0001 : lev 6: */ tmp0=FFXOR(fa,FFXOR(FFAND(fb,FFOR(fc,fd)),FFXOR(fc,FFXOR(fd,FF1())))); ++/* 0000 0011 0111 1011 : lev 5: */ tmp1=FFOR(FFAND(fa,FFXOR(fb,fd)),FFAND(FFOR(fa,fb),fc)); ++/* 1100 0110 1101 0010 : lev 6: */ tmp2=FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),FFXOR(fb,FFXOR(fc,FF1())))); ++/* 0001 1110 1111 0101 : lev 5: */ tmp3=FFOR(FFAND(fa,fd),FFXOR(fa,FFXOR(fb,FFAND(fc,fd)))); ++ s2a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s2b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+0][3];fa=regs->A[aboff+1][0];fb=regs->A[aboff+4][1];fc=regs->A[aboff+4][3];fd=regs->A[aboff+5][2]; ++/* 0100 1011 1001 0110 : lev 5: */ //tmp0=( fa^( fb^( ( fc&( fa|fd ) )^fd ) ) ); ++/* 1101 0101 1000 1100 : lev 7: */ //tmp1=( ( fa&fc )^( ( fa^fd )|( ( fb|fc )^( fd^ALL_ONES ) ) ) ); ++/* 0010 0111 1101 1000 : lev 4: */ //tmp2=( fa^( ( ( fb^fc )&fd )^fc ) ); ++/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; ++/* 0100 1011 1001 0110 : lev 5: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFAND(fc,FFOR(fa,fd)),fd))); ++/* 1101 0101 1000 1100 : lev 7: */ tmp1=FFXOR(FFAND(fa,fc),FFOR(FFXOR(fa,fd),FFXOR(FFOR(fb,fc),FFXOR(fd,FF1())))); ++/* 0010 0111 1101 1000 : lev 4: */ tmp2=FFXOR(fa,FFXOR(FFAND(FFXOR(fb,fc),fd),fc)); ++/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); ++ s3a=FFXOR(tmp0,FFAND(FFNOT(fe),tmp1)); ++ s3b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+2][3];fa=regs->A[aboff+0][1];fb=regs->A[aboff+1][3];fc=regs->A[aboff+3][2];fd=regs->A[aboff+7][0]; ++/* 1011 0101 0100 1001 : lev 7: */ //tmp0=( fa^( ( fc&( fa^fd ) )|( fb^( fc|( fd^ALL_ONES ) ) ) ) ); ++/* 0010 1101 0110 0110 : lev 6: */ //tmp1=( ( fa&fb )^( fb^( ( ( fa|fc )&fd )^fc ) ) ); ++/* 0110 0111 1101 0000 : lev 7: */ //tmp2=( fa^( ( fb&fc )|( ( ( fa&( fb^fd ) )|fc )^fd ) ) ); ++/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; ++/* 1011 0101 0100 1001 : lev 7: */ tmp0=FFXOR(fa,FFOR(FFAND(fc,FFXOR(fa,fd)),FFXOR(fb,FFOR(fc,FFXOR(fd,FF1()))))); ++/* 0010 1101 0110 0110 : lev 6: */ tmp1=FFXOR(FFAND(fa,fb),FFXOR(fb,FFXOR(FFAND(FFOR(fa,fc),fd),fc))); ++/* 0110 0111 1101 0000 : lev 7: */ tmp2=FFXOR(fa,FFOR(FFAND(fb,fc),FFXOR(FFOR(FFAND(fa,FFXOR(fb,fd)),fc),fd))); ++/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); ++ s4a=FFXOR(tmp0,FFAND(fe,FFXOR(tmp1,tmp0))); ++ s4b=FFXOR(FFXOR(s4a,tmp2),FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+4][2];fa=regs->A[aboff+3][3];fb=regs->A[aboff+5][0];fc=regs->A[aboff+7][1];fd=regs->A[aboff+8][2]; ++/* 1000 1111 0011 0010 : lev 7: */ //tmp0=( ( ( fa&( fb|fc ) )^fb )|( ( ( fa^fc )|fd )^ALL_ONES ) ); ++/* 0110 1011 0000 1011 : lev 6: */ //tmp1=( fb^( ( fc^fd )&( fc^( fb|( fa^fd ) ) ) ) ); ++/* 0001 1010 0111 1001 : lev 6: */ //tmp2=( ( fa&fc )^( fb^( ( fb|( fa^fc ) )&fd ) ) ); ++/* 0101 1101 1101 0101 : lev 4: */ //tmp3=( ( ( fa^fb )&( fc^ALL_ONES ) )|fd ); ++/* 1000 1111 0011 0010 : lev 7: */ tmp0=FFOR(FFXOR(FFAND(fa,FFOR(fb,fc)),fb),FFXOR(FFOR(FFXOR(fa,fc),fd),FF1())); ++/* 0110 1011 0000 1011 : lev 6: */ tmp1=FFXOR(fb,FFAND(FFXOR(fc,fd),FFXOR(fc,FFOR(fb,FFXOR(fa,fd))))); ++/* 0001 1010 0111 1001 : lev 6: */ tmp2=FFXOR(FFAND(fa,fc),FFXOR(fb,FFAND(FFOR(fb,FFXOR(fa,fc)),fd))); ++/* 0101 1101 1101 0101 : lev 4: */ tmp3=FFOR(FFAND(FFXOR(fa,fb),FFXOR(fc,FF1())),fd); ++ s5a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s5b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+2][1];fa=regs->A[aboff+3][1];fb=regs->A[aboff+4][0];fc=regs->A[aboff+6][2];fd=regs->A[aboff+8][3]; ++/* 0011 0110 0010 1101 : lev 6: */ //tmp0=( ( ( fa&fc )&fd )^( ( fb&( fa|fd ) )^fc ) ); ++/* 1110 1110 1011 1011 : lev 3: */ //tmp1=( ( ( fa^fc )&fd )^ALL_ONES ); ++/* 0101 1000 0110 0111 : lev 6: */ //tmp2=( ( fa&( fb|fc ) )^( fb^( ( fb&fc )|fd ) ) ); ++/* 0001 0011 0000 0001 : lev 5: */ //tmp3=( fc&( ( fa&( fb^fd ) )^( fb|fd ) ) ); ++/* 0011 0110 0010 1101 : lev 6: */ tmp0=FFXOR(FFAND(FFAND(fa,fc),fd),FFXOR(FFAND(fb,FFOR(fa,fd)),fc)); ++/* 1110 1110 1011 1011 : lev 3: */ tmp1=FFXOR(FFAND(FFXOR(fa,fc),fd),FF1()); ++/* 0101 1000 0110 0111 : lev 6: */ tmp2=FFXOR(FFAND(fa,FFOR(fb,fc)),FFXOR(fb,FFOR(FFAND(fb,fc),fd))); ++/* 0001 0011 0000 0001 : lev 5: */ tmp3=FFAND(fc,FFXOR(FFAND(fa,FFXOR(fb,fd)),FFOR(fb,fd))); ++ s6a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s6b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+1][2];fa=regs->A[aboff+2][0];fb=regs->A[aboff+6][1];fc=regs->A[aboff+7][2];fd=regs->A[aboff+7][3]; ++/* 0111 1000 1001 0110 : lev 5: */ //tmp0=( fb^( ( fc&fd )|( fa^( fc^fd ) ) ) ); ++/* 0100 1001 0101 1011 : lev 6: */ //tmp1=( ( fb|fd )&( ( fa&fc )|( fb^( fc^fd ) ) ) ); ++/* 0100 1001 1011 1001 : lev 5: */ //tmp2=( ( fa|fb )^( ( fc&( fb|fd ) )^fd ) ); ++/* 1111 1111 1101 1101 : lev 3: */ //tmp3=( fd|( ( fa&fc )^ALL_ONES ) ); ++/* 0111 1000 1001 0110 : lev 5: */ tmp0=FFXOR(fb,FFOR(FFAND(fc,fd),FFXOR(fa,FFXOR(fc,fd)))); ++/* 0100 1001 0101 1011 : lev 6: */ tmp1=FFAND(FFOR(fb,fd),FFOR(FFAND(fa,fc),FFXOR(fb,FFXOR(fc,fd)))); ++/* 0100 1001 1011 1001 : lev 5: */ tmp2=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fb,fd)),fd)); ++/* 1111 1111 1101 1101 : lev 3: */ tmp3=FFOR(fd,FFXOR(FFAND(fa,fc),FF1())); ++ s7a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s7b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ ++/* ++ we have just done this: ++ ++ int sbox1[0x20] = {2,0,1,1,2,3,3,0, 3,2,2,0,1,1,0,3, 0,3,3,0,2,2,1,1, 2,2,0,3,1,1,3,0}; ++ int sbox2[0x20] = {3,1,0,2,2,3,3,0, 1,3,2,1,0,0,1,2, 3,1,0,3,3,2,0,2, 0,0,1,2,2,1,3,1}; ++ int sbox3[0x20] = {2,0,1,2,2,3,3,1, 1,1,0,3,3,0,2,0, 1,3,0,1,3,0,2,2, 2,0,1,2,0,3,3,1}; ++ int sbox4[0x20] = {3,1,2,3,0,2,1,2, 1,2,0,1,3,0,0,3, 1,0,3,1,2,3,0,3, 0,3,2,0,1,2,2,1}; ++ int sbox5[0x20] = {2,0,0,1,3,2,3,2, 0,1,3,3,1,0,2,1, 2,3,2,0,0,3,1,1, 1,0,3,2,3,1,0,2}; ++ int sbox6[0x20] = {0,1,2,3,1,2,2,0, 0,1,3,0,2,3,1,3, 2,3,0,2,3,0,1,1, 2,1,1,2,0,3,3,0}; ++ int sbox7[0x20] = {0,3,2,2,3,0,0,1, 3,0,1,3,1,2,2,1, 1,0,3,3,0,1,1,2, 2,3,1,0,2,3,0,2}; ++ ++ s12 = sbox1[ (((A3>>0)&1)<<4) | (((A0>>2)&1)<<3) | (((A5>>1)&1)<<2) | (((A6>>3)&1)<<1) | (((A8>>0)&1)<<0) ] ++ |sbox2[ (((A1>>1)&1)<<4) | (((A2>>2)&1)<<3) | (((A5>>3)&1)<<2) | (((A6>>0)&1)<<1) | (((A8>>1)&1)<<0) ]; ++ s34 = sbox3[ (((A0>>3)&1)<<4) | (((A1>>0)&1)<<3) | (((A4>>1)&1)<<2) | (((A4>>3)&1)<<1) | (((A5>>2)&1)<<0) ] ++ |sbox4[ (((A2>>3)&1)<<4) | (((A0>>1)&1)<<3) | (((A1>>3)&1)<<2) | (((A3>>2)&1)<<1) | (((A7>>0)&1)<<0) ]; ++ s56 = sbox5[ (((A4>>2)&1)<<4) | (((A3>>3)&1)<<3) | (((A5>>0)&1)<<2) | (((A7>>1)&1)<<1) | (((A8>>2)&1)<<0) ] ++ |sbox6[ (((A2>>1)&1)<<4) | (((A3>>1)&1)<<3) | (((A4>>0)&1)<<2) | (((A6>>2)&1)<<1) | (((A8>>3)&1)<<0) ]; ++ s7 = sbox7[ (((A1>>2)&1)<<4) | (((A2>>0)&1)<<3) | (((A6>>1)&1)<<2) | (((A7>>2)&1)<<1) | (((A7>>3)&1)<<0) ]; ++*/ ++ ++ // use 4x4 xor to produce extra nibble for T3 ++ ++ extra_B[3]=FFXOR(FFXOR(FFXOR(regs->B[aboff+2][0],regs->B[aboff+5][1]),regs->B[aboff+6][2]),regs->B[aboff+8][3]); ++ extra_B[2]=FFXOR(FFXOR(FFXOR(regs->B[aboff+5][0],regs->B[aboff+7][1]),regs->B[aboff+2][3]),regs->B[aboff+3][2]); ++ extra_B[1]=FFXOR(FFXOR(FFXOR(regs->B[aboff+4][3],regs->B[aboff+7][2]),regs->B[aboff+3][0]),regs->B[aboff+4][1]); ++ extra_B[0]=FFXOR(FFXOR(FFXOR(regs->B[aboff+8][2],regs->B[aboff+5][3]),regs->B[aboff+2][1]),regs->B[aboff+7][0]); ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"extra_B[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)&extra_B[dbg],BYPG,BYPG)); ++} ++ ++ // T1 = xor all inputs ++ // in1, in2, D are only used in T1 during initialisation, not generation ++ for(b=0;b<4;b++){ ++ regs->A[aboff-1][b]=FFXOR(regs->A[aboff+9][b],regs->X[b]); ++ } ++ ++#ifdef STREAM_INIT ++ for(b=0;b<4;b++){ ++ regs->A[aboff-1][b]=FFXOR(FFXOR(regs->A[aboff-1][b],regs->D[b]),((j % 2) ? in2[b] : in1[b])); ++ } ++#endif ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"next_A0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->A[aboff-1][dbg],BYPG,BYPG)); ++} ++ ++ // T2 = xor all inputs ++ // in1, in2 are only used in T1 during initialisation, not generation ++ // if p=0, use this, if p=1, rotate the result left ++ for(b=0;b<4;b++){ ++ regs->B[aboff-1][b]=FFXOR(FFXOR(regs->B[aboff+6][b],regs->B[aboff+9][b]),regs->Y[b]); ++ } ++ ++#ifdef STREAM_INIT ++ for(b=0;b<4;b++){ ++ regs->B[aboff-1][b]=FFXOR(regs->B[aboff-1][b],((j % 2) ? in1[b] : in2[b])); ++ } ++#endif ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"next_B0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); ++} ++ ++ // if p=1, rotate left (yes, this is what we're doing) ++ tmp3=regs->B[aboff-1][3]; ++ regs->B[aboff-1][3]=FFXOR(regs->B[aboff-1][3],FFAND(FFXOR(regs->B[aboff-1][3],regs->B[aboff-1][2]),regs->p)); ++ regs->B[aboff-1][2]=FFXOR(regs->B[aboff-1][2],FFAND(FFXOR(regs->B[aboff-1][2],regs->B[aboff-1][1]),regs->p)); ++ regs->B[aboff-1][1]=FFXOR(regs->B[aboff-1][1],FFAND(FFXOR(regs->B[aboff-1][1],regs->B[aboff-1][0]),regs->p)); ++ regs->B[aboff-1][0]=FFXOR(regs->B[aboff-1][0],FFAND(FFXOR(regs->B[aboff-1][0],tmp3),regs->p)); ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"next_B0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); ++} ++ ++ // T3 = xor all inputs ++ for(b=0;b<4;b++){ ++ regs->D[b]=FFXOR(FFXOR(regs->E[b],regs->Z[b]),extra_B[b]); ++ } ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"D[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->D[dbg],BYPG,BYPG)); ++} ++ ++ // T4 = sum, carry of Z + E + r ++ for(b=0;b<4;b++){ ++ next_E[b]=regs->F[b]; ++ } ++ ++ tmp0=FFXOR(regs->Z[0],regs->E[0]); ++ tmp1=FFAND(regs->Z[0],regs->E[0]); ++ regs->F[0]=FFXOR(regs->E[0],FFAND(regs->q,FFXOR(regs->Z[0],regs->r))); ++ tmp3=FFAND(tmp0,regs->r); ++ tmp4=FFOR(tmp1,tmp3); ++ ++ tmp0=FFXOR(regs->Z[1],regs->E[1]); ++ tmp1=FFAND(regs->Z[1],regs->E[1]); ++ regs->F[1]=FFXOR(regs->E[1],FFAND(regs->q,FFXOR(regs->Z[1],tmp4))); ++ tmp3=FFAND(tmp0,tmp4); ++ tmp4=FFOR(tmp1,tmp3); ++ ++ tmp0=FFXOR(regs->Z[2],regs->E[2]); ++ tmp1=FFAND(regs->Z[2],regs->E[2]); ++ regs->F[2]=FFXOR(regs->E[2],FFAND(regs->q,FFXOR(regs->Z[2],tmp4))); ++ tmp3=FFAND(tmp0,tmp4); ++ tmp4=FFOR(tmp1,tmp3); ++ ++ tmp0=FFXOR(regs->Z[3],regs->E[3]); ++ tmp1=FFAND(regs->Z[3],regs->E[3]); ++ regs->F[3]=FFXOR(regs->E[3],FFAND(regs->q,FFXOR(regs->Z[3],tmp4))); ++ tmp3=FFAND(tmp0,tmp4); ++ regs->r=FFXOR(regs->r,FFAND(regs->q,FFXOR(FFOR(tmp1,tmp3),regs->r))); // ultimate carry ++ ++/* ++ we have just done this: (believe it or not) ++ ++ if (q) { ++ F = Z + E + r; ++ r = (F >> 4) & 1; ++ F = F & 0x0f; ++ } ++ else { ++ F = E; ++ } ++*/ ++ for(b=0;b<4;b++){ ++ regs->E[b]=next_E[b]; ++ } ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"F[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->F[dbg],BYPG,BYPG)); ++} ++DBG(fprintf(stderr,"r=")); ++DBG(dump_mem("",(unsigned char *)®s->r,BYPG,BYPG)); ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"E[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->E[dbg],BYPG,BYPG)); ++} ++ ++ // this simple instruction is virtually shifting all the shift registers ++ aboff--; ++ ++/* ++ we've just done this: ++ ++ A9=A8;A8=A7;A7=A6;A6=A5;A5=A4;A4=A3;A3=A2;A2=A1;A1=A0;A0=next_A0; ++ B9=B8;B8=B7;B7=B6;B6=B5;B5=B4;B4=B3;B3=B2;B2=B1;B1=B0;B0=next_B0; ++*/ ++ ++ regs->X[0]=s1a; ++ regs->X[1]=s2a; ++ regs->X[2]=s3b; ++ regs->X[3]=s4b; ++ regs->Y[0]=s3a; ++ regs->Y[1]=s4a; ++ regs->Y[2]=s5b; ++ regs->Y[3]=s6b; ++ regs->Z[0]=s5a; ++ regs->Z[1]=s6a; ++ regs->Z[2]=s1b; ++ regs->Z[3]=s2b; ++ regs->p=s7a; ++ regs->q=s7b; ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"X[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->X[dbg],BYPG,BYPG)); ++} ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"Y[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->Y[dbg],BYPG,BYPG)); ++} ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"Z[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->Z[dbg],BYPG,BYPG)); ++} ++DBG(fprintf(stderr,"p=")); ++DBG(dump_mem("",(unsigned char *)®s->p,BYPG,BYPG)); ++DBG(fprintf(stderr,"q=")); ++DBG(dump_mem("",(unsigned char *)®s->q,BYPG,BYPG)); ++ ++#ifdef STREAM_NORMAL ++ // require 4 loops per output byte ++ // 2 output bits are a function of the 4 bits of D ++ // xor 2 by 2 ++ cb_g[8*i+7-2*j]=FFXOR(regs->D[2],regs->D[3]); ++ cb_g[8*i+6-2*j]=FFXOR(regs->D[0],regs->D[1]); ++for(dbg=0;dbg<8;dbg++){ ++ DBG(fprintf(stderr,"op[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)&cb_g[8*i+dbg],BYPG,BYPG)); ++} ++#endif ++ ++DBG(fprintf(stderr,"---END INTERNAL LOOP\n")); ++ ++ } // INTERNAL LOOP ++ ++DBG(fprintf(stderr,"--END EXTERNAL LOOP\n")); ++ ++ } // EXTERNAL LOOP ++ ++ // move 32 steps forward, ready for next call ++ for(k=0;k<10;k++){ ++ for(b=0;b<4;b++){ ++DBG(fprintf(stderr,"moving forward AB k=%i b=%i\n",k,b)); ++ regs->A[32+k][b]=regs->A[k][b]; ++ regs->B[32+k][b]=regs->B[k][b]; ++ } ++ } ++ ++ ++//////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef STREAM_NORMAL ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"postcall prerot cb[%2i]=",j)); ++ DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); ++} ++ ++#if GROUP_PARALLELISM==32 ++trasp64_32_88cw(cb); ++#endif ++#if GROUP_PARALLELISM==64 ++trasp64_64_88cw(cb); ++#endif ++#if GROUP_PARALLELISM==128 ++trasp64_128_88cw(cb); ++#endif ++ ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"postcall postrot cb[%2i]=",j)); ++ DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); ++} ++#endif ++ ++#ifdef STREAM_INIT ++ DBG(fprintf(stderr,":::::::::: END STREAM INIT\n")); ++#endif ++#ifdef STREAM_NORMAL ++ DBG(fprintf(stderr,":::::::::: END STREAM NORMAL\n")); ++#endif ++ ++} ++ +diff -ruNp trunk.patches/globals.h trunk/globals.h +--- trunk.patches/globals.h 2018-04-03 03:02:59.558440627 +0300 ++++ trunk/globals.h 2018-04-03 03:20:07.658045369 +0300 +@@ -392,17 +392,17 @@ typedef unsigned char uchar; + #define CS_ECM_RINGBUFFER_MAX 0x10 // max size for ECM last responsetimes ringbuffer. Keep this set to power of 2 values! + + // Support for multiple CWs per channel and other encryption algos +-//#define WITH_EXTENDED_CW 1 ++#define WITH_EXTENDED_CW 1 + + #if defined(READER_DRE) || defined(READER_DRECAS) || defined(READER_VIACCESS) + #define MAX_ECM_SIZE 1024 + #define MAX_EMM_SIZE 1024 + #else +-#define MAX_ECM_SIZE 596 +-#define MAX_EMM_SIZE 512 ++#define MAX_ECM_SIZE 1024 ++#define MAX_EMM_SIZE 1024 + #endif + +-#define CS_EMMCACHESIZE 512 //nr of EMMs that each reader will cache ++#define CS_EMMCACHESIZE 1024 //nr of EMMs that each reader will cache + #define MSGLOGSIZE 64 //size of string buffer for a ecm to return messages + + #define D_TRACE 0x0001 // Generate very detailed error/trace messages per routine +@@ -434,6 +434,7 @@ typedef unsigned char uchar; + #define R_SMART 0x7 // Smartreader+ + #define R_PCSC 0x8 // PCSC + #define R_DRECAS 0x9 // Reader DRECAS ++#define R_EMU 0x17 // Reader EMU + /////////////////// proxy readers after R_CS378X + #define R_CAMD35 0x20 // Reader cascading camd 3.5x + #define R_CAMD33 0x21 // Reader cascading camd 3.3x +@@ -861,6 +862,13 @@ typedef struct s_entitlement + uint32_t class; // the class needed for some systems + time_t start; // startdate + time_t end; // enddate ++#ifdef WITH_EMU ++ bool isKey; ++ bool isData; ++ char name[8]; ++ uint8_t *key; ++ uint32_t keyLength; ++#endif + } S_ENTITLEMENT; + + struct s_client ; +@@ -985,6 +993,7 @@ struct s_cardsystem + void (*post_process)(struct s_reader *); + int32_t (*get_emm_type)(struct emm_packet_t *, struct s_reader *); + int32_t (*get_emm_filter)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *); ++ int32_t (*get_emm_filter_adv)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *, uint16_t, uint32_t, uint16_t); + int32_t (*get_tunemm_filter)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *); + }; + +@@ -1717,6 +1726,14 @@ struct s_reader + #ifdef MODULE_GHTTP + uint8_t ghttp_use_ssl; + #endif ++#ifdef WITH_EMU ++ FTAB emu_auproviders; // AU providers for Emu reader ++ int8_t emu_datecodedenabled; // date-coded keys for BISS ++ char *extee36; // path to "ee36.bin" - Set by the user via the webif ++ char *extee56; // path to "ee56.bin" - Set by the user via the webif ++ uint8_t dre36_force_group; ++ uint8_t dre56_force_group; ++#endif + uint8_t cnxlastecm; // == 0 - las ecm has not been paired ecm, > 0 last ecm has been paired ecm + LLIST *emmstat; //emm stats + CS_MUTEX_LOCK emmstat_lock; +@@ -2167,6 +2184,7 @@ struct s_config + int8_t dvbapi_read_sdt; + int8_t dvbapi_write_sdt_prov; + int8_t dvbapi_extended_cw_api; ++ int8_t dvbapi_extended_cw_pids; // pid limiter + #endif + + #ifdef CS_ANTICASC +@@ -2213,6 +2231,18 @@ struct s_config + IN_ADDR_T scam_srvip; + struct s_ip *scam_allowed; + #endif ++ ++#ifdef WITH_EMU ++ char *emu_stream_source_host; ++ int32_t emu_stream_source_port; ++ char *emu_stream_source_auth_user; ++ char *emu_stream_source_auth_password; ++ int32_t emu_stream_relay_port; ++ uint32_t emu_stream_ecm_delay; ++ int8_t emu_stream_relay_enabled; ++ int8_t emu_stream_emm_enabled; ++#endif ++ + int32_t max_cache_time; //seconds ecms are stored in ecmcwcache + int32_t max_hitcache_time; //seconds hits are stored in cspec_hitcache (to detect dyn wait_time) + +@@ -2394,4 +2424,8 @@ static inline bool caid_is_bulcrypt(uint + static inline bool caid_is_dre(uint16_t caid) { return caid == 0x4AE0 || caid == 0x4AE1 || caid == 0x2710;} + const char *get_cardsystem_desc_by_caid(uint16_t caid); + ++#ifdef WITH_EMU ++FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid); ++#endif ++ + #endif +diff -ruNp trunk.patches/Makefile trunk/Makefile +--- trunk.patches/Makefile 2018-04-03 03:01:12.325689204 +0300 ++++ trunk/Makefile 2018-04-03 03:20:07.654045339 +0300 +@@ -67,6 +67,13 @@ STRIP = $(CROSS_DIR)$(CROSS)strip + + LDFLAGS = -Wl,--gc-sections + ++TARGETHELP := $(shell $(CC) --target-help 2>&1) ++ifneq (,$(findstring sse2,$(TARGETHELP))) ++override CFLAGS += -fexpensive-optimizations -mmmx -msse -msse2 -msse3 ++else ++override CFLAGS += -fexpensive-optimizations ++endif ++ + # The linker for powerpc have bug that prevents --gc-sections from working + # Check for the linker version and if it matches disable --gc-sections + # For more information about the bug see: +@@ -270,6 +277,21 @@ SRC-$(CONFIG_CS_CACHEEX) += module-cccam + SRC-$(CONFIG_MODULE_CCCAM) += module-cccam.c + SRC-$(CONFIG_MODULE_CCCSHARE) += module-cccshare.c + SRC-$(CONFIG_MODULE_CONSTCW) += module-constcw.c ++SRC-$(CONFIG_WITH_EMU) += module-emulator.c ++SRC-$(CONFIG_WITH_EMU) += module-emulator-osemu.c ++SRC-$(CONFIG_WITH_EMU) += module-emulator-stream.c ++SRC-$(CONFIG_WITH_EMU) += ffdecsa/ffdecsa.c ++UNAME := $(shell uname -s) ++ifneq ($(UNAME),Darwin) ++ifndef ANDROID_NDK ++ifndef ANDROID_STANDALONE_TOOLCHAIN ++ifeq "$(CONFIG_WITH_EMU)" "y" ++TOUCH_SK := $(shell touch SoftCam.Key) ++override LDFLAGS += -Wl,--format=binary -Wl,SoftCam.Key -Wl,--format=default ++endif ++endif ++endif ++endif + SRC-$(CONFIG_CS_CACHEEX) += module-csp.c + SRC-$(CONFIG_CW_CYCLE_CHECK) += module-cw-cycle-check.c + SRC-$(CONFIG_WITH_AZBOX) += module-dvbapi-azbox.c +@@ -368,7 +390,7 @@ SRC := $(subst config.c,$(OBJDIR)/config + # starts the compilation. + all: + @./config.sh --use-flags "$(USE_FLAGS)" --objdir "$(OBJDIR)" --make-config.mak +- @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/webif ++ @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/ffdecsa $(OBJDIR)/webif + @-printf "\ + +-------------------------------------------------------------------------------\n\ + | OSCam ver: $(VER) rev: $(SVN_REV) target: $(TARGET)\n\ +diff -ruNp trunk.patches/module-dvbapi.c trunk/module-dvbapi.c +--- trunk.patches/module-dvbapi.c 2018-04-03 03:06:13.063827549 +0300 ++++ trunk/module-dvbapi.c 2018-04-03 03:20:07.658045369 +0300 +@@ -1471,7 +1471,15 @@ void dvbapi_start_emm_filter(int32_t dem + } + if(match) + { +- csystem = get_cardsystem_by_caid(caid); ++ if(rdr->typ == R_EMU) ++ { ++ csystem = rdr->csystem; ++ } ++ else ++ { ++ csystem = get_cardsystem_by_caid(caid); ++ } ++ + if(csystem) + { + if(caid != ncaid) +@@ -1490,7 +1498,14 @@ void dvbapi_start_emm_filter(int32_t dem + } + else if (csystem->get_emm_filter) + { +- csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ if(rdr->typ == R_EMU) ++ { ++ csystem->get_emm_filter_adv(rdr, &dmx_filter, &filter_count, caid, provid, demux[demux_index].program_number); ++ } ++ else ++ { ++ csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ } + } + } + else +@@ -2076,6 +2091,8 @@ int32_t dvbapi_start_descrambling(int32_ + er->vpid = demux[demux_id].ECMpids[pid].VPID; + er->pmtpid = demux[demux_id].pmtpid; + er->onid = demux[demux_id].onid; ++ er->tsid = demux[demux_id].tsid; ++ er->ens = demux[demux_id].enigma_namespace; + er->msgid = msgid; + + #ifdef WITH_STAPI5 +@@ -2113,19 +2130,30 @@ int32_t dvbapi_start_descrambling(int32_ + if(caid_is_fake(demux[demux_id].ECMpids[pid].CAID) || caid_is_biss(demux[demux_id].ECMpids[pid].CAID)) + { + int32_t j, n; +- er->ecmlen = 5; ++ er->ecmlen = 7; + er->ecm[0] = 0x80; // to pass the cache check it must be 0x80 or 0x81 + er->ecm[1] = 0x00; +- er->ecm[2] = 0x02; ++ er->ecm[2] = 0x04; + i2b_buf(2, er->srvid, er->ecm + 3); ++ i2b_buf(2, er->pmtpid, er->ecm + 5); + +- for(j = 0, n = 5; j < demux[demux_id].STREAMpidcount; j++, n += 2) ++ for(j = 0, n = 7; j < demux[demux_id].STREAMpidcount; j++, n += 2) + { + i2b_buf(2, demux[demux_id].STREAMpids[j], er->ecm + n); + er->ecm[2] += 2; + er->ecmlen += 2; + } + ++ er->ens &= 0x0FFFFFFF; // clear top 4 bits (in case of DVB-T/C or garbage), prepare for flagging ++ er->ens |= 0xA0000000; // flag to emu: this is the namespace, not a pid ++ ++ i2b_buf(2, er->tsid, er->ecm + 3 + er->ecm[2]); // place tsid after the last stream pid ++ i2b_buf(2, er->onid, er->ecm + 3 + er->ecm[2] + 2); // place onid right after tsid ++ i2b_buf(4, er->ens, er->ecm + 3 + er->ecm[2] + 4); // place namespace at the end of the ecm ++ ++ er->ecm[2] += 8; ++ er->ecmlen += 8; ++ + cs_log("Demuxer %d trying to descramble PID %d CAID %04X PROVID %06X ECMPID %04X ANY CHID PMTPID %04X VPID %04X", demux_id, pid, + demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID, + demux[demux_id].pmtpid, demux[demux_id].ECMpids[pid].VPID); +@@ -3192,6 +3220,7 @@ int32_t dvbapi_parse_capmt(unsigned char + { + uint32_t i = 0, start_descrambling = 0; + int32_t j = 0; ++ int32_t max_pids = 64; + int32_t demux_id = -1; + uint16_t demux_index, adapter_index, pmtpid; + uint32_t ca_mask; +@@ -3354,6 +3383,12 @@ int32_t dvbapi_parse_capmt(unsigned char + uint32_t es_info_length = 0, vpid = 0; + struct s_dvbapi_priority *addentry; + ++ // pid limiter for PowerVu ++ if(demux[demux_id].ECMpids[0].CAID >> 8 == 0x0E) ++ { ++ max_pids = cfg.dvbapi_extended_cw_pids; ++ } ++ + for(i = program_info_length + program_info_start; i + 4 < length; i += es_info_length + 5) + { + uint8_t stream_type = buffer[i]; +@@ -3361,7 +3396,7 @@ int32_t dvbapi_parse_capmt(unsigned char + uint8_t is_audio = 0; + es_info_length = b2i(2, buffer + i +3)&0x0FFF; + +- if(demux[demux_id].STREAMpidcount < ECM_PIDS) ++ if(demux[demux_id].STREAMpidcount < max_pids) // was "ECM_PIDS" (pid limiter) + { + + demux[demux_id].STREAMpids[demux[demux_id].STREAMpidcount] = elementary_pid; +@@ -4375,6 +4410,7 @@ void dvbapi_process_input(int32_t demux_ + if(filtertype == TYPE_ECM) + { + uint32_t chid = 0x10000; ++ int8_t pvu_skip = 0; + ECM_REQUEST *er; + + if(len != 0) // len = 0 receiver encountered an internal bufferoverflow! +@@ -4401,9 +4437,24 @@ void dvbapi_process_input(int32_t demux_ + return; + } + +- if(curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) // wait for odd / even ecm change (only not for irdeto!) ++ if(curpid->CAID >> 8 == 0x0E) + { +- ++ pvu_skip = 1; ++ ++ if(sctlen - 11 > buffer[9]) ++ { ++ if(buffer[11 + buffer[9]] > curpid->pvu_counter || (curpid->pvu_counter == 255 && buffer[11 + buffer[9]] == 0) ++ || ((curpid->pvu_counter - buffer[11 + buffer[9]]) > 5)) ++ { ++ curpid->pvu_counter = buffer[11 + buffer[9]]; ++ pvu_skip = 0; ++ } ++ } ++ } ++ ++ if((curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) || pvu_skip) // wait for odd / even ecm change (only not for irdeto!) ++ { ++ + if(!(er = get_ecmtask())) + { + return; +@@ -4685,6 +4736,40 @@ void dvbapi_process_input(int32_t demux_ + dvbapi_stop_filternum(demux_id, filter_num, msgid); + return; + } ++ ++#ifdef WITH_EMU ++ if((demux[demux_id].demux_fd[filter_num].caid>>8) == 0x10) ++ { ++ uint32_t i; ++ uint32_t emmhash; ++ ++ if(sctlen < 4) ++ { ++ return; ++ } ++ ++ for(i=0; i+2caid>>8 != 0x0E || !cfg.emu_stream_relay_enabled) ++#endif + switch(selected_api) + { + #if defined(WITH_STAPI) || defined(WITH_STAPI5) +diff -ruNp trunk.patches/module-dvbapi.h trunk/module-dvbapi.h +--- trunk.patches/module-dvbapi.h 2018-04-03 02:48:24.956386446 +0300 ++++ trunk/module-dvbapi.h 2018-04-03 03:20:07.658045369 +0300 +@@ -136,6 +136,7 @@ struct s_ecmpids + int8_t useMultipleIndices; + uint32_t streams; + uint32_t cadata; ++ int16_t pvu_counter; + }; + + typedef struct filter_s +@@ -158,6 +159,9 @@ typedef struct filter_s + uint32_t SlotHandle[10]; + uint32_t BufferHandle[10]; + #endif ++#ifdef WITH_EMU ++ uint32_t cadata; ++#endif + } FILTERTYPE; + + struct s_emmpids +diff -ruNp trunk.patches/module-emulator.c trunk/module-emulator.c +--- trunk.patches/module-emulator.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator.c 2018-04-03 03:20:07.662045399 +0300 +@@ -0,0 +1,904 @@ ++#define MODULE_LOG_PREFIX "emu" ++ ++#include "globals.h" ++#include "oscam-string.h" ++#include "oscam-config.h" ++#include "oscam-conf-chk.h" ++#include "oscam-time.h" ++#include "oscam-reader.h" ++#include "module-emulator-osemu.h" ++#include "module-emulator-stream.h" ++ ++/* ++ * Readers in OSCam consist of 2 basic parts. ++ * The hardware or the device part. This is where physical smart cards are inserted ++ * and made available to OSCam. ++ * The software or the emulation part. This is where the actual card reading is done, ++ * including ecm and emm processing (i.e emulation of the various cryptosystems). ++ * In the Emu reader, the device part has no meaning, but we have to create it in ++ * order to be compatible with OSCam's reader structure. ++*/ ++ ++/* ++ * Create the Emu "emulation" part. This is of type s_cardsystem. ++ * Similar structures are found in the main sources folder (files reader-xxxxxx.c) ++ * for every cryptosystem supported by OSCam. ++ * Here we read keys from our virtual card (aka the SoftCam.Key file) and we inform ++ * OSCam about them. This is done with the emu_card_info() function. Keep in mind ++ * that Emu holds all its keys to separate structures for faster access. ++ * In addition, ECM and EMM requests are processed here, with the emu_do_ecm() and ++ * emu_do_emm() functions. ++*/ ++ ++#define CS_OK 1 ++#define CS_ERROR 0 ++ ++static uint8_t oneByte = 0x01; ++extern char cs_confdir[128]; ++ ++static void set_hexserial_to_version(struct s_reader *rdr) ++{ ++ char cVersion[32]; ++ uint32_t version = GetOSemuVersion(); ++ uint8_t hversion[2]; ++ memset(hversion, 0, 2); ++ snprintf(cVersion, sizeof(cVersion), "%04d", version); ++ CharToBin(hversion, cVersion, 4); ++ rdr->hexserial[3] = hversion[0]; ++ rdr->hexserial[4] = hversion[1]; ++} ++ ++static void set_prids(struct s_reader *rdr) ++{ ++ int32_t i, j; ++ ++ rdr->nprov = 0; ++ ++ for (i = 0; (i < rdr->emu_auproviders.nfilts) && (rdr->nprov < CS_MAXPROV); i++) ++ { ++ for (j = 0; (j < rdr->emu_auproviders.filts[i].nprids) && (rdr->nprov < CS_MAXPROV); j++) ++ { ++ i2b_buf(4, rdr->emu_auproviders.filts[i].prids[j], rdr->prid[i]); ++ rdr->nprov++; ++ } ++ } ++} ++ ++static void emu_add_entitlement(struct s_reader *rdr, uint16_t caid, uint32_t provid, uint8_t *key, char *keyName, uint32_t keyLength, uint8_t isData) ++{ ++ if (!rdr->ll_entitlements) ++ { ++ rdr->ll_entitlements = ll_create("ll_entitlements"); ++ } ++ ++ S_ENTITLEMENT *item; ++ if (cs_malloc(&item, sizeof(S_ENTITLEMENT))) ++ { ++ // fill item ++ item->caid = caid; ++ item->provid = provid; ++ item->id = 0; ++ item->class = 0; ++ item->start = 0; ++ item->end = 2147472000; ++ item->type = 0; ++ item->isKey = 1; ++ memcpy(item->name, keyName, 8); ++ item->key = key; ++ item->keyLength = keyLength; ++ item->isData = isData; ++ ++ // add item ++ ll_append(rdr->ll_entitlements, item); ++ } ++} ++ ++static void refresh_entitlements(struct s_reader *rdr) ++{ ++ uint32_t i; ++ KeyData *tmpKeyData; ++ ++ cs_clear_entitlement(rdr); ++ ++ for (i = 0; i < CwKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, CwKeys.EmuKeys[i].provider >> 8, CwKeys.EmuKeys[i].provider & 0xFF, ++ CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < ViKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x500, ViKeys.EmuKeys[i].provider, ViKeys.EmuKeys[i].key, ++ ViKeys.EmuKeys[i].keyName, ViKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < NagraKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x1801, NagraKeys.EmuKeys[i].provider, NagraKeys.EmuKeys[i].key, ++ NagraKeys.EmuKeys[i].keyName, NagraKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < IrdetoKeys.keyCount; i++) ++ { ++ tmpKeyData = &IrdetoKeys.EmuKeys[i]; ++ do ++ { ++ emu_add_entitlement(rdr, tmpKeyData->provider >> 8, tmpKeyData->provider & 0xFF, ++ tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0); ++ ++ tmpKeyData = tmpKeyData->nextKey; ++ } ++ while (tmpKeyData != NULL); ++ } ++ ++ for (i = 0; i < NDSKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, NDSKeys.EmuKeys[i].provider, 0, NDSKeys.EmuKeys[i].key, ++ NDSKeys.EmuKeys[i].keyName, NDSKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ emu_add_entitlement(rdr, 0x090F, 0, viasat_const, "00", 64, 1); ++ emu_add_entitlement(rdr, 0x093E, 0, viasat_const, "00", 64, 1); ++ ++ for (i = 0; i < BissKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x2600, BissKeys.EmuKeys[i].provider, BissKeys.EmuKeys[i].key, ++ BissKeys.EmuKeys[i].keyName, BissKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ emu_add_entitlement(rdr, 0xFFFF, 0, &oneByte, "00", 1, 1); ++ ++ for (i = 0; i < PowervuKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x0E00, PowervuKeys.EmuKeys[i].provider, PowervuKeys.EmuKeys[i].key, ++ PowervuKeys.EmuKeys[i].keyName, PowervuKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < DreKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x4AE1, DreKeys.EmuKeys[i].provider, DreKeys.EmuKeys[i].key, ++ DreKeys.EmuKeys[i].keyName, DreKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < TandbergKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x1010, TandbergKeys.EmuKeys[i].provider, TandbergKeys.EmuKeys[i].key, ++ TandbergKeys.EmuKeys[i].keyName, TandbergKeys.EmuKeys[i].keyLength, 0); ++ } ++} ++ ++static int32_t emu_do_ecm(struct s_reader *rdr, const struct ecm_request_t *er, struct s_ecm_answer *ea) ++{ ++ ++ if (!ProcessECM(rdr, er->ecmlen, er->caid, er->prid, er->ecm, ea->cw, er->srvid, er->pid, &ea->cw_ex)) ++ { ++ return CS_OK; ++ } ++ ++ return CS_ERROR; ++} ++ ++static int32_t emu_do_emm(struct s_reader *rdr, struct emm_packet_t *emm) ++{ ++ uint32_t keysAdded = 0; ++ ++ if (emm->emmlen < 3) ++ { ++ return CS_ERROR; ++ } ++ ++ if (SCT_LEN(emm->emm) > emm->emmlen) ++ { ++ return CS_ERROR; ++ } ++ ++ if (!ProcessEMM(rdr, b2i(2, emm->caid), b2i(4, emm->provid), emm->emm, &keysAdded)) ++ { ++ if (keysAdded > 0) ++ { ++ refresh_entitlements(rdr); ++ } ++ ++ return CS_OK; ++ } ++ ++ return CS_ERROR; ++} ++ ++static int32_t emu_card_info(struct s_reader *rdr) ++{ ++ // Delete keys from Emu's memory ++ clear_emu_keydata(); ++ ++ // Read keys built in the OSCam-Emu binary ++#if !defined(__APPLE__) && !defined(__ANDROID__) ++ read_emu_keymemory(rdr); ++#endif ++ ++ // Read keys from SoftCam.Key file ++ set_emu_keyfile_path(cs_confdir); ++ ++ if (!read_emu_keyfile(rdr, cs_confdir)) ++ { ++ if (read_emu_keyfile(rdr, "/var/keys/")) ++ { ++ set_emu_keyfile_path("/var/keys/"); ++ } ++ } ++ ++ // Load keys from external files (set via the webif or the reader config directly) ++ read_emu_eebin(rdr->extee36, "ee36.bin"); // Read "ee36.bin" ++ read_emu_eebin(rdr->extee56, "ee56.bin"); // Read "ee56.bin" ++ read_emu_deskey(rdr->des_key, rdr->des_key_length); // Read overcrypt keys for DreCrypt ADEC ++ ++ cs_log("Total keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ ++ CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ ++ IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ ++ PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); ++ ++ // Inform OSCam about all available keys. ++ // This is used for listing the "entitlements" in the webif's reader page. ++ refresh_entitlements(rdr); ++ ++ set_prids(rdr); ++ ++ set_hexserial_to_version(rdr); ++ ++ return CS_OK; ++} ++ ++/* ++static int32_t emu_card_init(struct s_reader *UNUSED(rdr), struct s_ATR *UNUSED(atr)) ++{ ++ return CS_ERROR; ++} ++*/ ++ ++int32_t emu_get_via3_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ uint32_t provid = 0; ++ ++ if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03) ++ { ++ provid = b2i(3, ep->emm+5); ++ provid &=0xFFFFF0; ++ i2b_buf(4, provid, ep->provid); ++ } ++ ++ switch(ep->emm[0]) ++ { ++ case 0x88: ++ ep->type = UNIQUE; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 4, 4); ++ rdr_log_dbg(rdr, D_EMM, "UNIQUE"); ++ return 1; ++ ++ case 0x8A: ++ case 0x8B: ++ ep->type = GLOBAL; ++ rdr_log_dbg(rdr, D_EMM, "GLOBAL"); ++ return 1; ++ ++ case 0x8C: ++ case 0x8D: ++ ep->type = SHARED; ++ rdr_log_dbg(rdr, D_EMM, "SHARED (part)"); ++ // We need those packets to pass otherwise we would never ++ // be able to complete EMM reassembly ++ return 1; ++ ++ case 0x8E: ++ ep->type = SHARED; ++ rdr_log_dbg(rdr, D_EMM, "SHARED"); ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 3, 3); ++ return 1; ++ ++ default: ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ return 1; ++ } ++} ++ ++int32_t emu_get_ird2_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ int32_t l = (ep->emm[3] & 0x07); ++ int32_t base = (ep->emm[3] >> 3); ++ char dumprdrserial[l * 3], dumpemmserial[l * 3]; ++ ++ switch(l) ++ { ++ ++ case 0: ++ // global emm, 0 bytes addressed ++ ep->type = GLOBAL; ++ rdr_log_dbg(rdr, D_EMM, "GLOBAL base = %02x", base); ++ return 1; ++ ++ case 2: ++ // shared emm, 2 bytes addressed ++ ep->type = SHARED; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 4, l); ++ cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); ++ cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); ++ rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED l = %d ep = {%s} rdr = {%s} base = %02x", l, ++ dumpemmserial, dumprdrserial, base); ++ return 1; ++ ++ case 3: ++ // unique emm, 3 bytes addressed ++ ep->type = UNIQUE; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 4, l); ++ cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); ++ cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); ++ rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE l = %d ep = {%s} rdr = {%s} base = %02x", l, ++ dumpemmserial, dumprdrserial, base); ++ return 1; ++ ++ default: ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ return 1; ++ } ++} ++ ++int32_t emu_get_pvu_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ if(ep->emm[0] == 0x82) ++ { ++ ep->type = UNIQUE; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 12, 4); ++ } ++ else ++ { ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ } ++ return 1; ++} ++ ++int32_t emu_get_dre2_emm_type(EMM_PACKET *ep, struct s_reader *UNUSED(rdr)) ++{ ++ switch (ep->emm[0]) ++ { ++ case 0x82: ++ ep->type = GLOBAL; ++ return 1; ++ ++ case 0x86: ++ ep->type = SHARED; ++ memset(ep->hexserial, 0, 8); ++ ep->hexserial[0] = ep->emm[3]; ++ return 1; ++ ++ //case 0x87: ++ // ep->type = UNIQUE; ++ // return 1; //FIXME: no filling of ep->hexserial ++ ++ case 0x88: ++ ep->type = UNIQUE; ++ return 1; //FIXME: no filling of ep->hexserial ++ ++ case 0x91: ++ ep->type = GLOBAL; ++ return 1; ++ ++ default: ++ ep->type = UNKNOWN; ++ return 1; ++ } ++} ++ ++int32_t emu_get_tan_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ if(ep->emm[0] == 0x82 || ep->emm[0] == 0x83) ++ { ++ ep->type = GLOBAL; ++ } ++ else ++ { ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ } ++ return 1; ++} ++ ++static int32_t emu_get_emm_type(struct emm_packet_t *ep, struct s_reader *rdr) ++{ ++ switch(b2i(2, ep->caid)>>8) ++ { ++ case 0x05: ++ return emu_get_via3_emm_type(ep, rdr); ++ ++ case 0x06: ++ return emu_get_ird2_emm_type(ep, rdr); ++ ++ case 0x0E: ++ return emu_get_pvu_emm_type(ep, rdr); ++ ++ case 0x4A: ++ return emu_get_dre2_emm_type(ep, rdr); ++ ++ case 0x10: ++ return emu_get_tan_emm_type(ep, rdr); ++ ++ default: ++ break; ++ } ++ ++ return CS_ERROR; ++} ++ ++FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid) ++{ ++ int32_t i; ++ ++ for(i = 0; i < rdr->emu_auproviders.nfilts; i++) ++ { ++ if(caid == rdr->emu_auproviders.filts[i].caid) ++ { ++ return &rdr->emu_auproviders.filts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int32_t emu_get_via3_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) ++{ ++ if(*emm_filters == NULL) ++ { ++ const unsigned int max_filter_count = 1; ++ ++ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) ++ { return CS_ERROR; } ++ ++ struct s_csystem_emm_filter *filters = *emm_filters; ++ *filter_count = 0; ++ ++ int32_t idx = 0; ++ ++ filters[idx].type = EMM_GLOBAL; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x8A; ++ filters[idx].mask[0] = 0xFE; ++ filters[idx].filter[3] = 0x80; ++ filters[idx].mask[3] = 0x80; ++ idx++; ++ ++ *filter_count = idx; ++ } ++ ++ return CS_OK; ++} ++ ++static int32_t emu_get_ird2_emm_filter(struct s_reader* rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t UNUSED(provid)) ++{ ++ uint8_t hexserial[3], prid[4]; ++ FILTER* emu_provids; ++ int8_t have_provid = 0, have_serial = 0; ++ int32_t i; ++ ++ if(GetIrdeto2Hexserial(caid, hexserial)) ++ { have_serial = 1; } ++ ++ emu_provids = get_emu_prids_for_caid(rdr, caid); ++ if(emu_provids != NULL && emu_provids->nprids > 0) ++ { have_provid = 1; } ++ ++ if(*emm_filters == NULL) ++ { ++ const unsigned int max_filter_count = have_serial + (2*(have_provid ? emu_provids->nprids : 0)); ++ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) ++ { return CS_ERROR; } ++ ++ struct s_csystem_emm_filter *filters = *emm_filters; ++ *filter_count = 0; ++ ++ unsigned int idx = 0; ++ ++ if(have_serial) ++ { ++ filters[idx].type = EMM_UNIQUE; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x82; ++ filters[idx].mask[0] = 0xFF; ++ filters[idx].filter[1] = 0xFB; ++ filters[idx].mask[1] = 0x07; ++ memcpy(&filters[idx].filter[2], hexserial, 3); ++ memset(&filters[idx].mask[2], 0xFF, 3); ++ idx++; ++ } ++ ++ for(i=0; have_provid && inprids; i++) ++ { ++ i2b_buf(4, emu_provids->prids[i], prid); ++ ++ filters[idx].type = EMM_UNIQUE; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x82; ++ filters[idx].mask[0] = 0xFF; ++ filters[idx].filter[1] = 0xFB; ++ filters[idx].mask[1] = 0x07; ++ memcpy(&filters[idx].filter[2], &prid[1], 3); ++ memset(&filters[idx].mask[2], 0xFF, 3); ++ idx++; ++ ++ filters[idx].type = EMM_SHARED; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x82; ++ filters[idx].mask[0] = 0xFF; ++ filters[idx].filter[1] = 0xFA; ++ filters[idx].mask[1] = 0x07; ++ memcpy(&filters[idx].filter[2], &prid[1], 2); ++ memset(&filters[idx].mask[2], 0xFF, 2); ++ idx++; ++ } ++ ++ *filter_count = idx; ++ } ++ ++ return CS_OK; ++} ++ ++static int32_t emu_get_pvu_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid), uint16_t srvid) ++{ ++ uint8_t hexserials[16][4]; ++ int32_t i, count = 0; ++ ++ if(!GetPowervuHexserials(srvid, hexserials, 16, &count)) ++ { return CS_ERROR; } ++ ++ if(*emm_filters == NULL) ++ { ++ const unsigned int max_filter_count = count; ++ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) ++ { return CS_ERROR; } ++ ++ struct s_csystem_emm_filter *filters = *emm_filters; ++ *filter_count = 0; ++ ++ int32_t idx = 0; ++ ++ for(i=0; i>8) ++ { ++ case 0x05: ++ return emu_get_via3_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ case 0x06: ++ return emu_get_ird2_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ case 0x0E: ++ return emu_get_pvu_emm_filter(rdr, emm_filters, filter_count, caid, provid, srvid); ++ ++ case 0x4A: ++ return emu_get_dre2_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ case 0x10: ++ return emu_get_tan_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ default: ++ break; ++ } ++ ++ return CS_ERROR; ++} ++ ++const struct s_cardsystem reader_emu = ++{ ++ .desc = "emu", ++ .caids = (uint16_t[]){ 0x0D, 0x09, 0x0500, 0x18, 0x06, 0x26, 0xFFFF, 0x0E, 0x4A, 0x10, 0 }, ++ .do_ecm = emu_do_ecm, ++ .do_emm = emu_do_emm, ++ .card_info = emu_card_info, ++ //.card_init = emu_card_init, // apparently this is not needed at all ++ .get_emm_type = emu_get_emm_type, ++ .get_emm_filter = emu_get_emm_filter, // needed to pass checks ++ .get_emm_filter_adv = emu_get_emm_filter_adv, ++}; ++ ++/* ++ * Create the Emu virtual "device" part. This is of type s_cardreader. ++ * Similar structures are found in the csctapi (Card System Card Terminal API) ++ * folder for every IFD (InterFace Device), aka smart card reader. ++ * Since we have no hardware to initialize, we start our Stream Relay server ++ * with the emu_reader_init() function. ++ * At Emu shutdown, we remove keys from memory with the emu_close() function. ++*/ ++ ++#define CR_OK 0 ++#define CR_ERROR 1 ++ ++static int32_t emu_reader_init(struct s_reader *UNUSED(reader)) ++{ ++ int32_t i; ++ char authtmp[128]; ++ ++ if (cfg.emu_stream_relay_enabled && (stream_server_thread_init == 0)) ++ { ++ stream_server_thread_init = 1; ++ SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL); ++ ++ for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) ++ { ++ SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL); ++ ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys"); ++ memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data)); ++ } ++ ++ start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1); ++ cs_log("Stream key delayer initialized"); ++ ++ cs_strncpy(emu_stream_source_host, cfg.emu_stream_source_host, sizeof(emu_stream_source_host)); ++ emu_stream_source_port = cfg.emu_stream_source_port; ++ emu_stream_relay_port = cfg.emu_stream_relay_port; ++ emu_stream_emm_enabled = cfg.emu_stream_emm_enabled; ++ ++ if (cfg.emu_stream_source_auth_user && cfg.emu_stream_source_auth_password) ++ { ++ snprintf(authtmp, sizeof(authtmp), "%s:%s", cfg.emu_stream_source_auth_user, cfg.emu_stream_source_auth_password); ++ b64encode(authtmp, strlen(authtmp), &emu_stream_source_auth); ++ } ++ else ++ { ++ NULLFREE(emu_stream_source_auth); ++ } ++ ++ start_thread("stream_server", stream_server, NULL, NULL, 1, 1); ++ cs_log("Stream relay server initialized"); ++ } ++ ++ return CR_OK; ++} ++ ++static int32_t emu_close(struct s_reader *UNUSED(reader)) ++{ ++ cs_log("Reader is shutting down"); ++ ++ // Delete keys from Emu's memory ++ clear_emu_keydata(); ++ ++ return CR_OK; ++} ++ ++static int32_t emu_get_status(struct s_reader *UNUSED(reader), int32_t *in) { *in = 1; return CR_OK; } ++static int32_t emu_activate(struct s_reader *UNUSED(reader), struct s_ATR *UNUSED(atr)) { return CR_OK; } ++static int32_t emu_transmit(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(expectedlen), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } ++static int32_t emu_receive(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } ++static int32_t emu_write_settings(struct s_reader *UNUSED(reader), struct s_cardreader_settings *UNUSED(s)) { return CR_OK; } ++static int32_t emu_card_write(struct s_reader *UNUSED(pcsc_reader),const uchar *UNUSED(buf) ,uint8_t *UNUSED(cta_res), uint16_t *UNUSED(cta_lr),int32_t UNUSED(l)) { return CR_OK; } ++static int32_t emu_set_protocol(struct s_reader *UNUSED(rdr),uint8_t *UNUSED(params),uint32_t *UNUSED(length), uint32_t UNUSED(len_request)) { return CR_OK; } ++ ++const struct s_cardreader cardreader_emu = ++{ ++ .desc = "emu", ++ .typ = R_EMU, ++ .skip_extra_atr_parsing = 1, ++ .reader_init = emu_reader_init, ++ .get_status = emu_get_status, ++ .activate = emu_activate, ++ .transmit = emu_transmit, ++ .receive = emu_receive, ++ .close = emu_close, ++ .write_settings = emu_write_settings, ++ .card_write = emu_card_write, ++ .set_protocol = emu_set_protocol, ++}; ++ ++void add_emu_reader(void) ++{ ++ // This function is called inside oscam.c and creates an emu [reader] with default ++ // settings in oscam.server file. If an emu [reader] already exists, it uses that. ++ ++ LL_ITER itr; ++ struct s_reader *rdr; ++ int8_t haveEmuReader = 0; ++ char *emuName = "emulator"; ++ char *ctab, *ftab, *emu_auproviders; ++ ++ // Check if emu [reader] entry already exists in oscam.server file and get it ++ itr = ll_iter_create(configured_readers); ++ while ((rdr = ll_iter_next(&itr))) ++ { ++ if (rdr->typ == R_EMU) ++ { ++ haveEmuReader = 1; ++ break; ++ } ++ } ++ ++ rdr = NULL; ++ ++ // If there's no emu [reader] in oscam.server, create one with default settings ++ if (!haveEmuReader) ++ { ++ if (!cs_malloc(&rdr, sizeof(struct s_reader))) ++ { ++ return; ++ } ++ ++ reader_set_defaults(rdr); ++ ++ rdr->enable = 1; ++ rdr->typ = R_EMU; ++ strncpy(rdr->label, emuName, strlen(emuName)); ++ strncpy(rdr->device, emuName, strlen(emuName)); ++ ++ // CAIDs ++ ctab = strdup("090F,0500,1801,0604,2600,FFFF,0E00,4AE1,1010"); ++ chk_caidtab(ctab, &rdr->ctab); ++ NULLFREE(ctab); ++ ++ // Idents ++ ftab = strdup("090F:000000;" ++ "0500:000000,023800,021110,007400,007800;" ++ "1801:000000,007301,001101,002111;" ++ "0604:000000;" ++ "2600:000000;" ++ "FFFF:000000;" ++ "0E00:000000;" ++ "4AE1:000011,000014,0000FE;" ++ "1010:000000;" ++ ); ++ chk_ftab(ftab, &rdr->ftab); ++ NULLFREE(ftab); ++ ++ // AU providers ++ emu_auproviders = strdup("0604:010200;0E00:000000;4AE1:000011,000014,0000FE;1010:000000;"); ++ chk_ftab(emu_auproviders, &rdr->emu_auproviders); ++ NULLFREE(emu_auproviders); ++ ++ // EMM cache ++ rdr->cachemm = 2; ++ rdr->rewritemm = 1; ++ rdr->logemm = 2; ++ rdr->deviceemm = 1; ++ ++ // User group ++ rdr->grp = 0x1ULL; ++ ++ // Add the "device" part to our emu reader ++ rdr->crdr = &cardreader_emu; ++ ++ reader_fixups_fn(rdr); ++ ll_append(configured_readers, rdr); ++ } ++ ++ // Set DVB Api delayer option ++#ifdef HAVE_DVBAPI ++ if (cfg.dvbapi_enabled && cfg.dvbapi_delayer < 60) ++ { ++ cfg.dvbapi_delayer = 60; ++ } ++#endif ++ ++ cs_log("OSCam-Emu version %d", GetOSemuVersion()); ++} +diff -ruNp trunk.patches/module-emulator-osemu.c trunk/module-emulator-osemu.c +--- trunk.patches/module-emulator-osemu.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator-osemu.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,6488 @@ ++#define MODULE_LOG_PREFIX "emu" ++ ++#include "globals.h" ++#include "ffdecsa/ffdecsa.h" ++#include "cscrypt/bn.h" ++#include "cscrypt/des.h" ++#include "cscrypt/idea.h" ++#include "cscrypt/md5.h" ++ ++#ifdef WITH_EMU ++#include "oscam-aes.h" ++#include "oscam-string.h" ++#include "oscam-config.h" ++#include "oscam-conf-chk.h" ++#include "oscam-time.h" ++#include "module-newcamd-des.h" ++#include "reader-dre-common.h" ++// from reader-viaccess.c: ++void hdSurEncPhase1_D2_0F_11(uint8_t *CWs); ++void hdSurEncPhase2_D2_0F_11(uint8_t *CWs); ++void hdSurEncPhase1_D2_13_15(uint8_t *cws); ++void hdSurEncPhase2_D2_13_15(uint8_t *cws); ++#else ++#include "cscrypt/viades.h" ++#include "via3surenc.h" ++#include "dre2overcrypt.h" ++#endif ++ ++#include "module-emulator-osemu.h" ++#include "module-emulator-stream.h" ++ ++// Version info ++uint32_t GetOSemuVersion(void) ++{ ++ return atoi("$Version: 769 $"+10); ++} ++ ++/* ++ * Key DB ++ * ++ * The Emu reader gets keys from the OSCcam-Emu binary and the "SoftCam.Key" file. ++ * ++ * The keys are stored in structures of type "KeyDataContainer", one per CAS. Each ++ * container points to a dynamically allocated array of type "KeyData", which holds ++ * the actual keys. The array initially holds up to 64 keys (64 * KeyData), and it ++ * is expanded by 16 every time it's filled with keys. The "KeyDataContainer" also ++ * includes info about the number of keys it contains ("KeyCount") and the maximum ++ * number of keys it can store ("KeyMax"). ++ * ++ * The "KeyData" structure on the other hand, stores the actual key information, ++ * including the "identifier", "provider", "keyName", "key" and "keyLength". There ++ * is also a "nextKey" pointer to a similar "KeyData" structure which is only used ++ * for Irdeto multiple keys, in a linked list style structure. For all other CAS, ++ * the "nextKey" is a "NULL" pointer. ++ * ++ * For storing keys, the "SetKey" function is used. Duplicate keys are not allowed. ++ * When storing a key that is already present in the database, its "key" value is ++ * updated with the new one. For reading keys from the database, the "FindKey" ++ * function is used. To delete all keys in a container, the "DeleteKeysInContainer" ++ * function can be called. ++*/ ++ ++static char *emu_keyfile_path = NULL; ++ ++void set_emu_keyfile_path(const char *path) ++{ ++ if(emu_keyfile_path != NULL) { ++ free(emu_keyfile_path); ++ } ++ emu_keyfile_path = (char*)malloc(strlen(path)+1); ++ if(emu_keyfile_path == NULL) { ++ return; ++ } ++ memcpy(emu_keyfile_path, path, strlen(path)); ++ emu_keyfile_path[strlen(path)] = 0; ++} ++ ++int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen) ++{ ++ uint32_t i, tmp; ++ for(i=0; i= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { ++ // cut file name ++ path[pathLength-fileNameLen] = '\0'; ++ } ++ ++ pathLength = strlen(path); ++ if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { ++ // cut trailing / ++ path[pathLength-1] = '\0'; ++ } ++ ++ pDir = opendir(path); ++ if (pDir == NULL) { ++ cs_log("Cannot open key file path: %s", path); ++ free(path); ++ return; ++ } ++ ++ while((pDirent = readdir(pDir)) != NULL) { ++ if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { ++ strncpy(filename, pDirent->d_name, sizeof(filename)); ++ break; ++ } ++ } ++ closedir(pDir); ++ ++ if(pDirent == NULL) { ++ strncpy(filename, EMU_KEY_FILENAME, sizeof(filename)); ++ } ++ ++ pathLength = strlen(path)+1+strlen(filename)+1; ++ filepath = (char*)malloc(pathLength); ++ if(filepath == NULL) { ++ free(path); ++ return; ++ } ++ snprintf(filepath, pathLength, "%s/%s", path, filename); ++ free(path); ++ ++ cs_log("Writing key file: %s", filepath); ++ ++ file = fopen(filepath, "a"); ++ free(filepath); ++ if(file == NULL) { ++ return; ++ } ++ ++ Date2Str(dateText, sizeof(dateText), 0, 1); ++ ++ keyValue = (char*)malloc((keyLength*2)+1); ++ if(keyValue == NULL) { ++ fclose(file); ++ return; ++ } ++ cs_hexdump(0, key, keyLength, keyValue, (keyLength*2)+1); ++ ++ if(comment) ++ { ++ snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s %s\n", identifier, provider, keyName, keyValue, dateText, comment); ++ } ++ else ++ { ++ snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s\n", identifier, provider, keyName, keyValue, dateText); ++ } ++ ++ cs_log("Key written: %c %.4X %s %s", identifier, provider, keyName, keyValue); ++ ++ free(keyValue); ++ ++ fwrite(line, strlen(line), 1, file); ++ fclose(file); ++} ++ ++int32_t SetKey(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, ++ uint8_t writeKey, char *comment, struct s_reader *rdr) ++{ ++ uint32_t i, j; ++ uint8_t *tmpKey = NULL; ++ KeyDataContainer *KeyDB; ++ KeyData *tmpKeyData, *newKeyData; ++ identifier = (char)toupper((int)identifier); ++ ++ KeyDB = GetKeyContainer(identifier); ++ if(KeyDB == NULL) { ++ return 0; ++ } ++ ++ keyName = strtoupper(keyName); ++ ++ if (identifier == 'F') // Prepare BISS keys before saving to the db ++ { ++ // Convert legacy BISS "00" & "01" keynames ++ if (0 == strcmp(keyName, "00") || 0 == strcmp(keyName, "01")) ++ { ++ keyName = "00000000"; ++ } ++ ++ // All keyNames should have a length of 8 after converting ++ if (strlen(keyName) != 8) ++ { ++ cs_log("WARNING: Wrong key format in %s: F %08X %s", EMU_KEY_FILENAME, provider, keyName); ++ return 0; ++ } ++ ++ // Verify date-coded keyName (if enabled), ignoring old (expired) keys ++ if (rdr->emu_datecodedenabled) ++ { ++ char timeStr[9]; ++ Date2Str(timeStr, sizeof(timeStr), 0, 3); ++ ++ // Reject old date-coded keys, but allow our "00000000" evergreen label ++ if (strcmp("00000000", keyName) != 0 && strcmp(timeStr, keyName) >= 0) ++ { ++ return 0; ++ } ++ } ++ } ++ ++ // fix checksum for BISS keys with a length of 6 ++ if (identifier == 'F' && keyLength == 6) ++ { ++ tmpKey = (uint8_t*)malloc(8*sizeof(uint8_t)); ++ if(tmpKey == NULL) { ++ return 0; ++ } ++ ++ tmpKey[0] = orgKey[0]; ++ tmpKey[1] = orgKey[1]; ++ tmpKey[2] = orgKey[2]; ++ tmpKey[3] = ((orgKey[0] + orgKey[1] + orgKey[2]) & 0xff); ++ tmpKey[4] = orgKey[3]; ++ tmpKey[5] = orgKey[4]; ++ tmpKey[6] = orgKey[5]; ++ tmpKey[7] = ((orgKey[3] + orgKey[4] + orgKey[5]) & 0xff); ++ ++ keyLength = 8; ++ } ++ else // All keys with a length of 8, including BISS ++ { ++ tmpKey = (uint8_t*)malloc(keyLength*sizeof(uint8_t)); ++ if(tmpKey == NULL) { ++ return 0; ++ } ++ ++ memcpy(tmpKey, orgKey, keyLength); ++ } ++ ++ // fix patched mgcamd format for Irdeto ++ if(identifier == 'I' && provider < 0xFFFF) { ++ provider = provider<<8; ++ } ++ ++ // key already exists on db, update its value ++ for(i=0; ikeyCount; i++) { ++ ++ if(KeyDB->EmuKeys[i].provider != provider) { ++ continue; ++ } ++ ++ // Don't match keyName (i.e. expiration date) for BISS ++ if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { ++ continue; ++ } ++ ++ // allow multiple keys for Irdeto ++ if(identifier == 'I') ++ { ++ // reject duplicates ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ do { ++ if(memcmp(tmpKeyData->key, tmpKey, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) { ++ free(tmpKey); ++ return 0; ++ } ++ tmpKeyData = tmpKeyData->nextKey; ++ } ++ while(tmpKeyData != NULL); ++ ++ // add new key ++ newKeyData = (KeyData*)malloc(sizeof(KeyData)); ++ if(newKeyData == NULL) { ++ free(tmpKey); ++ return 0; ++ } ++ newKeyData->identifier = identifier; ++ newKeyData->provider = provider; ++ if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { ++ strncpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ else { ++ memcpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ newKeyData->keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; ++ newKeyData->key = tmpKey; ++ newKeyData->keyLength = keyLength; ++ newKeyData->nextKey = NULL; ++ ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ j = 0; ++ while(tmpKeyData->nextKey != NULL) { ++ if(j == 0xFE) ++ { ++ break; ++ } ++ tmpKeyData = tmpKeyData->nextKey; ++ j++; ++ } ++ if(tmpKeyData->nextKey) ++ { ++ NULLFREE(tmpKeyData->nextKey->key); ++ NULLFREE(tmpKeyData->nextKey); ++ } ++ tmpKeyData->nextKey = newKeyData; ++ ++ if(writeKey) { ++ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); ++ } ++ } ++ else // identifier != 'I' ++ { ++ free(KeyDB->EmuKeys[i].key); ++ KeyDB->EmuKeys[i].key = tmpKey; ++ KeyDB->EmuKeys[i].keyLength = keyLength; ++ ++ if (identifier == 'F') // Update keyName (i.e. expiration date) for BISS ++ { ++ strncpy(KeyDB->EmuKeys[i].keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ ++ if(writeKey) { ++ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); ++ } ++ } ++ ++ return 1; ++ } ++ ++ // key does not exist on db ++ if(KeyDB->keyCount+1 > KeyDB->keyMax) ++ { ++ if(KeyDB->EmuKeys == NULL) // db is empty ++ { ++ KeyDB->EmuKeys = (KeyData*)malloc(sizeof(KeyData)*(KeyDB->keyMax+64)); ++ if(KeyDB->EmuKeys == NULL) { ++ free(tmpKey); ++ return 0; ++ } ++ KeyDB->keyMax+=64; ++ } ++ else // db is full, expand it ++ { ++ tmpKeyData = (KeyData*)realloc(KeyDB->EmuKeys, sizeof(KeyData)*(KeyDB->keyMax+16)); ++ if(tmpKeyData == NULL) { ++ free(tmpKey); ++ return 0; ++ } ++ KeyDB->EmuKeys = tmpKeyData; ++ KeyDB->keyMax+=16; ++ } ++ } ++ ++ KeyDB->EmuKeys[KeyDB->keyCount].identifier = identifier; ++ KeyDB->EmuKeys[KeyDB->keyCount].provider = provider; ++ if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { ++ strncpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ else { ++ memcpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ KeyDB->EmuKeys[KeyDB->keyCount].keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; ++ KeyDB->EmuKeys[KeyDB->keyCount].key = tmpKey; ++ KeyDB->EmuKeys[KeyDB->keyCount].keyLength = keyLength; ++ KeyDB->EmuKeys[KeyDB->keyCount].nextKey = NULL; ++ KeyDB->keyCount++; ++ ++ if(writeKey) { ++ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); ++ } ++ ++ return 1; ++} ++ ++int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, ++ uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider) ++{ ++ uint32_t i; ++ uint16_t j; ++ uint8_t provider_matching_key_count = 0; ++ KeyDataContainer *KeyDB; ++ KeyData *tmpKeyData; ++ ++ KeyDB = GetKeyContainer(identifier); ++ if(KeyDB == NULL) { ++ return 0; ++ } ++ ++ for(i=0; ikeyCount; i++) { ++ ++ if((KeyDB->EmuKeys[i].provider & ~providerIgnoreMask) != provider) { ++ continue; ++ } ++ ++ // Don't match keyName (i.e. expiration date) for BISS ++ if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { ++ continue; ++ } ++ ++ //matchLength cannot be used when multiple keys are allowed ++ //for a single provider/keyName combination. ++ //Currently this is only the case for Irdeto keys. ++ if(matchLength && KeyDB->EmuKeys[i].keyLength != maxKeyLength) { ++ continue; ++ } ++ ++ if(providerIgnoreMask) { ++ if(provider_matching_key_count < keyRef) { ++ provider_matching_key_count++; ++ continue; ++ } ++ else { ++ keyRef = 0; ++ } ++ } ++ ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ ++ j = 0; ++ while(jnextKey != NULL) { ++ j++; ++ tmpKeyData = tmpKeyData->nextKey; ++ } ++ ++ if(j == keyRef) { ++ memcpy(key, tmpKeyData->key, tmpKeyData->keyLength > maxKeyLength ? maxKeyLength : tmpKeyData->keyLength); ++ if(tmpKeyData->keyLength < maxKeyLength) { ++ memset(key+tmpKeyData->keyLength, 0, maxKeyLength - tmpKeyData->keyLength); ++ } ++ ++ if (identifier == 'F') // Report the keyName of found key back to BissGetKey() ++ { ++ strncpy(keyName, tmpKeyData->keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ ++ if(getProvider != NULL) { ++ (*getProvider) = tmpKeyData->provider; ++ } ++ return 1; ++ } ++ else { ++ break; ++ } ++ } ++ ++ if (isCriticalKey) ++ { ++ cs_log("Key not found: %c %X %s", identifier, provider, keyName); ++ } ++ ++ return 0; ++} ++ ++static int32_t UpdateKey(char identifier, uint32_t provider, char *keyName, uint8_t *key, uint32_t keyLength, uint8_t writeKey, char *comment) ++{ ++ uint32_t keyRef = 0; ++ uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); ++ if(tmpKey == NULL) ++ { ++ return 0; ++ } ++ ++ while(FindKey(identifier, provider, 0, keyName, tmpKey, keyLength, 0, keyRef, 0, NULL)) ++ { ++ if(memcmp(tmpKey, key, keyLength) == 0) ++ { ++ free(tmpKey); ++ return 0; ++ } ++ ++ keyRef++; ++ } ++ ++ free(tmpKey); ++ return SetKey(identifier, provider, keyName, key, keyLength, writeKey, comment, NULL); ++} ++ ++static int32_t UpdateKeysByProviderMask(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, ++ uint32_t keyLength, char *comment) ++{ ++ int32_t ret = 0; ++ uint32_t foundProvider = 0; ++ uint32_t keyRef = 0; ++ uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); ++ if(tmpKey == NULL) ++ { ++ return 0; ++ } ++ ++ while(FindKey(identifier, (provider & ~providerIgnoreMask), providerIgnoreMask, keyName, tmpKey, keyLength, 0, keyRef, 0, &foundProvider)) ++ { ++ keyRef++; ++ ++ if(memcmp(tmpKey, key, keyLength) == 0) ++ { ++ continue; ++ } ++ ++ if(SetKey(identifier, foundProvider, keyName, key, keyLength, 1, comment, NULL)) ++ { ++ ret = 1; ++ } ++ } ++ ++ free(tmpKey); ++ return ret; ++} ++ ++int32_t DeleteKeysInContainer(char identifier) ++{ ++ // Deletes all keys stored in memory for the specified identifier, ++ // but keeps the container itself, re-initialized at { NULL, 0, 0 }. ++ // Returns the count of deleted keys. ++ ++ uint32_t oldKeyCount, i; ++ KeyData *tmpKeyData; ++ KeyDataContainer *KeyDB = GetKeyContainer(identifier); ++ ++ if (KeyDB == NULL || KeyDB->EmuKeys == NULL || KeyDB->keyCount == 0) ++ { ++ return 0; ++ } ++ ++ for (i = 0; i < KeyDB->keyCount; i++) ++ { ++ // For Irdeto multiple keys only (linked list structure) ++ while (KeyDB->EmuKeys[i].nextKey != NULL) ++ { ++ tmpKeyData = KeyDB->EmuKeys[i].nextKey; ++ KeyDB->EmuKeys[i].nextKey = KeyDB->EmuKeys[i].nextKey->nextKey; ++ free(tmpKeyData->key); // Free key ++ free(tmpKeyData); // Free KeyData ++ } ++ ++ // For single keys (all identifiers, including Irdeto) ++ free(KeyDB->EmuKeys[i].key); // Free key ++ } ++ ++ // Free the KeyData array ++ NULLFREE(KeyDB->EmuKeys); ++ oldKeyCount = KeyDB->keyCount; ++ KeyDB->keyCount = 0; ++ KeyDB->keyMax = 0; ++ ++ return oldKeyCount; ++} ++ ++void clear_emu_keydata(void) ++{ ++ uint32_t total = 0; ++ ++ total = CwKeys.keyCount; ++ total += ViKeys.keyCount; ++ total += NagraKeys.keyCount; ++ total += IrdetoKeys.keyCount; ++ total += NDSKeys.keyCount; ++ total += BissKeys.keyCount; ++ total += PowervuKeys.keyCount; ++ total += DreKeys.keyCount; ++ total += TandbergKeys.keyCount; ++ ++ if (total != 0) ++ { ++ cs_log("Freeing keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ ++ CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ ++ IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ ++ PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); ++ ++ DeleteKeysInContainer('W'); ++ DeleteKeysInContainer('V'); ++ DeleteKeysInContainer('N'); ++ DeleteKeysInContainer('I'); ++ DeleteKeysInContainer('S'); ++ DeleteKeysInContainer('F'); ++ DeleteKeysInContainer('P'); ++ DeleteKeysInContainer('D'); ++ DeleteKeysInContainer('T'); ++ } ++} ++ ++uint8_t read_emu_keyfile(struct s_reader *rdr, const char *opath) ++{ ++ char line[1200], keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; ++ uint32_t pathLength, provider, keyLength; ++ uint8_t *key; ++ struct dirent *pDirent; ++ DIR *pDir; ++ char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1]; ++ FILE *file = NULL; ++ char identifier; ++ uint8_t fileNameLen = strlen(EMU_KEY_FILENAME); ++ ++ pathLength = strlen(opath); ++ path = (char*)malloc(pathLength+1); ++ if(path == NULL) { ++ return 0; ++ } ++ strncpy(path, opath, pathLength+1); ++ ++ pathLength = strlen(path); ++ if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { ++ // cut file name ++ path[pathLength-fileNameLen] = '\0'; ++ } ++ ++ pathLength = strlen(path); ++ if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { ++ // cut trailing / ++ path[pathLength-1] = '\0'; ++ } ++ ++ pDir = opendir(path); ++ if (pDir == NULL) { ++ cs_log("Cannot open key file path: %s", path); ++ free(path); ++ return 0; ++ } ++ ++ while((pDirent = readdir(pDir)) != NULL) { ++ if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { ++ strncpy(filename, pDirent->d_name, sizeof(filename)); ++ break; ++ } ++ } ++ closedir(pDir); ++ ++ if(pDirent == NULL) { ++ cs_log("Key file not found in: %s", path); ++ free(path); ++ return 0; ++ } ++ ++ pathLength = strlen(path)+1+strlen(filename)+1; ++ filepath = (char*)malloc(pathLength); ++ if(filepath == NULL) { ++ free(path); ++ return 0; ++ } ++ snprintf(filepath, pathLength, "%s/%s", path, filename); ++ free(path); ++ ++ cs_log("Reading key file: %s", filepath); ++ ++ file = fopen(filepath, "r"); ++ free(filepath); ++ if(file == NULL) { ++ return 0; ++ } ++ ++ set_emu_keyfile_path(opath); ++ ++ while(fgets(line, 1200, file)) { ++ if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { ++ continue; ++ } ++ ++ keyLength = strlen(keyString)/2; ++ key = (uint8_t*)malloc(keyLength); ++ if(key == NULL) { ++ fclose(file); ++ return 0; ++ } ++ ++ if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK ++ { ++ SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); ++ } ++ else // Non-hex characters in keyString ++ { ++ if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. ++ identifier != '=' && identifier != '-' && ++ identifier != ' ') && ++ !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines ++ { ++ // Alert user regarding faulty line ++ cs_log("WARNING: non-hex value in %s at %c %04X %s %s", EMU_KEY_FILENAME, identifier, provider, keyName, keyString); ++ } ++ } ++ free(key); ++ } ++ fclose(file); ++ ++ return 1; ++} ++ ++#if !defined(__APPLE__) && !defined(__ANDROID__) ++extern uint8_t SoftCamKey_Data[] __asm__("_binary_SoftCam_Key_start"); ++extern uint8_t SoftCamKey_DataEnd[] __asm__("_binary_SoftCam_Key_end"); ++ ++void read_emu_keymemory(struct s_reader *rdr) ++{ ++ char *keyData, *line, *saveptr, keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; ++ uint32_t provider, keyLength; ++ uint8_t *key; ++ char identifier; ++ ++ keyData = (char*)malloc(SoftCamKey_DataEnd-SoftCamKey_Data+1); ++ if(keyData == NULL) { ++ return; ++ } ++ memcpy(keyData, SoftCamKey_Data, SoftCamKey_DataEnd-SoftCamKey_Data); ++ keyData[SoftCamKey_DataEnd-SoftCamKey_Data] = 0x00; ++ ++ line = strtok_r(keyData, "\n", &saveptr); ++ while(line != NULL) { ++ if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { ++ line = strtok_r(NULL, "\n", &saveptr); ++ continue; ++ } ++ keyLength = strlen(keyString)/2; ++ key = (uint8_t*)malloc(keyLength); ++ if(key == NULL) { ++ free(keyData); ++ return; ++ } ++ ++ if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK ++ { ++ SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); ++ } ++ else // Non-hex characters in keyString ++ { ++ if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. ++ identifier != '=' && identifier != '-' && ++ identifier != ' ') && ++ !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines ++ { ++ // Alert user regarding faulty line ++ cs_log("WARNING: non-hex value in internal keyfile at %c %04X %s %s", identifier, provider, keyName, keyString); ++ } ++ } ++ free(key); ++ line = strtok_r(NULL, "\n", &saveptr); ++ } ++ free(keyData); ++} ++#endif ++ ++void read_emu_eebin(const char *path, const char *name) ++{ ++ char tmp[256]; ++ FILE *file = NULL; ++ uint8_t i, buffer[64][32], dummy[2][32]; ++ uint32_t prvid; ++ ++ // Set path ++ if (path != NULL) ++ { ++ snprintf(tmp, 256, "%s%s", path, name); ++ } ++ else // No path set, use SoftCam.Keys's path ++ { ++ snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); ++ } ++ ++ // Read file to buffer ++ if ((file = fopen(tmp, "rb")) != NULL) ++ { ++ cs_log("Reading key file: %s", tmp); ++ ++ if (fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) ++ { ++ cs_log("Corrupt key file: %s", tmp); ++ fclose(file); ++ return; ++ } ++ ++ fclose(file); ++ } ++ else ++ { ++ if (path != NULL) ++ { ++ cs_log("Cannot open key file: %s", tmp); ++ } ++ ++ return; ++ } ++ ++ // Save keys to db ++ memset(dummy[0], 0x00, 32); ++ memset(dummy[1], 0xFF, 32); ++ prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; ++ ++ for (i = 0; i < 32; i++) // Set "3B" type keys ++ { ++ // Write keys if they have "real" values ++ if ((memcmp(buffer[i], dummy[0], 32) !=0) && (memcmp(buffer[i], dummy[1], 32) != 0)) ++ { ++ snprintf(tmp, 5, "3B%02X", i); ++ SetKey('D', prvid, tmp, buffer[i], 32, 0, NULL, NULL); ++ } ++ } ++ ++ for (i = 0; i < 32; i++) // Set "56" type keys ++ { ++ // Write keys if they have "real" values ++ if ((memcmp(buffer[32 + i], dummy[0], 32) !=0) && (memcmp(buffer[32 + i], dummy[1], 32) != 0)) ++ { ++ snprintf(tmp, 5, "56%02X", i); ++ SetKey('D', prvid, tmp, buffer[32 + i], 32, 0, NULL, NULL); ++ } ++ } ++} ++ ++void read_emu_deskey(uint8_t *dreOverKey, uint8_t len) ++{ ++ uint8_t i; ++ ++ if (len == 128) ++ { ++ cs_log("Reading DreCrypt overcrypt (ADEC) key"); ++ ++ for (i = 0; i < 16; i++) ++ { ++ SetKey('D', i, "OVER", dreOverKey + (i * 8), 8, 0, NULL, NULL); ++ } ++ } ++ else if ((len != 0 && len < 128) || len > 128) ++ { ++ cs_log("DreCrypt overcrypt (ADEC) key has wrong length"); ++ } ++} ++ ++// Shared functions ++ ++static inline uint16_t GetEcmLen(const uint8_t *ecm) ++{ ++ return (((ecm[1] & 0x0f)<< 8) | ecm[2]) +3; ++} ++ ++static void ReverseMem(uint8_t *in, int32_t len) ++{ ++ uint8_t temp; ++ int32_t i; ++ for(i = 0; i < (len / 2); i++) { ++ temp = in[i]; ++ in[i] = in[len - i - 1]; ++ in[len - i - 1] = temp; ++ } ++} ++ ++static void ReverseMemInOut(uint8_t *out, const uint8_t *in, int32_t n) ++{ ++ if(n>0) { ++ out+=n; ++ do { ++ *(--out)=*(in++); ++ } ++ while(--n); ++ } ++} ++ ++static int8_t EmuRSAInput(BIGNUM *d, const uint8_t *in, int32_t n, int8_t le) ++{ ++ int8_t result = 0; ++ ++ if(le) { ++ uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t)*n); ++ if(tmp == NULL) { ++ return 0; ++ } ++ ReverseMemInOut(tmp,in,n); ++ result = BN_bin2bn(tmp,n,d)!=0; ++ free(tmp); ++ } ++ else { ++ result = BN_bin2bn(in,n,d)!=0; ++ } ++ return result; ++} ++ ++static int32_t EmuRSAOutput(uint8_t *out, int32_t n, BIGNUM *r, int8_t le) ++{ ++ int32_t s = BN_num_bytes(r); ++ if(s>n) { ++ uint8_t *buff = (uint8_t *)malloc(sizeof(uint8_t)*s); ++ if(buff == NULL) { ++ return 0; ++ } ++ BN_bn2bin(r,buff); ++ memcpy(out,buff+s-n,n); ++ free(buff); ++ } ++ else if(s> 1) & 0xFE)); ++ key[2] = ((tmpKey[1] << 6) | ((tmpKey[2] >> 2) & 0xFE)); ++ key[3] = ((tmpKey[2] << 5) | ((tmpKey[3] >> 3) & 0xFE)); ++ key[4] = ((tmpKey[3] << 4) | ((tmpKey[4] >> 4) & 0xFE)); ++ key[5] = ((tmpKey[4] << 3) | ((tmpKey[5] >> 5) & 0xFE)); ++ key[6] = ((tmpKey[5] << 2) | ((tmpKey[6] >> 6) & 0xFE)); ++ key[7] = (tmpKey[6] << 1); ++ ++ for (i = 0; i < 8; i++) ++ { ++ parity = 1; ++ for (j = 1; j < 8; j++) if ((key[i] >> j) & 0x1) { parity = ~parity & 0x01; } ++ key[i] |= parity; ++ } ++} ++ ++// Cryptoworks EMU ++static int8_t GetCwKey(uint8_t *buf,uint32_t ident, uint8_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) ++{ ++ ++ char keyName[EMU_MAX_CHAR_KEYNAME]; ++ uint32_t tmp; ++ ++ if((ident >> 4) == 0xD02A) { ++ keyIndex &=0xFE; // map to even number key indexes ++ } ++ if((ident >> 4) == 0xD00C) { ++ ident = 0x0D00C0; // map provider C? to C0 ++ } ++ else if(keyIndex == 6 && ((ident >> 8) == 0x0D05)) { ++ ident = 0x0D0504; // always use provider 04 system key ++ } ++ ++ tmp = keyIndex; ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", tmp); ++ if(FindKey('W', ident, 0, keyName, buf, keyLength, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static const uint8_t cw_sbox1[64] = { ++ 0xD8,0xD7,0x83,0x3D,0x1C,0x8A,0xF0,0xCF,0x72,0x4C,0x4D,0xF2,0xED,0x33,0x16,0xE0, ++ 0x8F,0x28,0x7C,0x82,0x62,0x37,0xAF,0x59,0xB7,0xE0,0x00,0x3F,0x09,0x4D,0xF3,0x94, ++ 0x16,0xA5,0x58,0x83,0xF2,0x4F,0x67,0x30,0x49,0x72,0xBF,0xCD,0xBE,0x98,0x81,0x7F, ++ 0xA5,0xDA,0xA7,0x7F,0x89,0xC8,0x78,0xA7,0x8C,0x05,0x72,0x84,0x52,0x72,0x4D,0x38 ++}; ++static const uint8_t cw_sbox2[64] = { ++ 0xD8,0x35,0x06,0xAB,0xEC,0x40,0x79,0x34,0x17,0xFE,0xEA,0x47,0xA3,0x8F,0xD5,0x48, ++ 0x0A,0xBC,0xD5,0x40,0x23,0xD7,0x9F,0xBB,0x7C,0x81,0xA1,0x7A,0x14,0x69,0x6A,0x96, ++ 0x47,0xDA,0x7B,0xE8,0xA1,0xBF,0x98,0x46,0xB8,0x41,0x45,0x9E,0x5E,0x20,0xB2,0x35, ++ 0xE4,0x2F,0x9A,0xB5,0xDE,0x01,0x65,0xF8,0x0F,0xB2,0xD2,0x45,0x21,0x4E,0x2D,0xDB ++}; ++static const uint8_t cw_sbox3[64] = { ++ 0xDB,0x59,0xF4,0xEA,0x95,0x8E,0x25,0xD5,0x26,0xF2,0xDA,0x1A,0x4B,0xA8,0x08,0x25, ++ 0x46,0x16,0x6B,0xBF,0xAB,0xE0,0xD4,0x1B,0x89,0x05,0x34,0xE5,0x74,0x7B,0xBB,0x44, ++ 0xA9,0xC6,0x18,0xBD,0xE6,0x01,0x69,0x5A,0x99,0xE0,0x87,0x61,0x56,0x35,0x76,0x8E, ++ 0xF7,0xE8,0x84,0x13,0x04,0x7B,0x9B,0xA6,0x7A,0x1F,0x6B,0x5C,0xA9,0x86,0x54,0xF9 ++}; ++static const uint8_t cw_sbox4[64] = { ++ 0xBC,0xC1,0x41,0xFE,0x42,0xFB,0x3F,0x10,0xB5,0x1C,0xA6,0xC9,0xCF,0x26,0xD1,0x3F, ++ 0x02,0x3D,0x19,0x20,0xC1,0xA8,0xBC,0xCF,0x7E,0x92,0x4B,0x67,0xBC,0x47,0x62,0xD0, ++ 0x60,0x9A,0x9E,0x45,0x79,0x21,0x89,0xA9,0xC3,0x64,0x74,0x9A,0xBC,0xDB,0x43,0x66, ++ 0xDF,0xE3,0x21,0xBE,0x1E,0x16,0x73,0x5D,0xA2,0xCD,0x8C,0x30,0x67,0x34,0x9C,0xCB ++}; ++static const uint8_t AND_bit1[8] = {0x00,0x40,0x04,0x80,0x21,0x10,0x02,0x08}; ++static const uint8_t AND_bit2[8] = {0x80,0x08,0x01,0x40,0x04,0x20,0x10,0x02}; ++static const uint8_t AND_bit3[8] = {0x82,0x40,0x01,0x10,0x00,0x20,0x04,0x08}; ++static const uint8_t AND_bit4[8] = {0x02,0x10,0x04,0x40,0x80,0x08,0x01,0x20}; ++ ++static void CW_SWAP_KEY(uint8_t *key) ++{ ++ uint8_t k[8]; ++ memcpy(k, key, 8); ++ memcpy(key, key + 8, 8); ++ memcpy(key + 8, k, 8); ++} ++ ++static void CW_SWAP_DATA(uint8_t *k) ++{ ++ uint8_t d[4]; ++ memcpy(d, k + 4, 4); ++ memcpy(k + 4 ,k ,4); ++ memcpy(k, d, 4); ++} ++ ++static void CW_DES_ROUND(uint8_t *d, uint8_t *k) ++{ ++ uint8_t aa[44] = {1,0,3,1,2,2,3,2,1,3,1,1,3,0,1,2,3,1,3,2,2,0,7,6,5,4,7,6,5,7,6,5,6,7,5,7,5,7,6,6,7,5,4,4}; ++ uint8_t bb[44] = {0x80,0x08,0x10,0x02,0x08,0x40,0x01,0x20,0x40,0x80,0x04,0x10,0x04,0x01,0x01,0x02,0x20,0x20,0x02,0x01, ++ 0x80,0x04,0x02,0x02,0x08,0x02,0x10,0x80,0x01,0x20,0x08,0x80,0x01,0x08,0x40,0x01,0x02,0x80,0x10,0x40,0x40,0x10,0x08,0x01 ++ }; ++ uint8_t ff[4] = {0x02,0x10,0x04,0x04}; ++ uint8_t l[24] = {0,2,4,6,7,5,3,1,4,5,6,7,7,6,5,4,7,4,5,6,4,7,6,5}; ++ ++ uint8_t des_td[8], i, o, n, c = 1, m = 0, r = 0, *a = aa, *b = bb, *f = ff, *p1 = l, *p2 = l+8, *p3 = l+16; ++ ++ for (m = 0; m < 2; m++) { ++ for(i = 0; i < 4; i++) { ++ des_td[*p1++] = ++ (m) ? ((d[*p2++]*2) & 0x3F) | ((d[*p3++] & 0x80) ? 0x01 : 0x00): (d[*p2++]/2) | ((d[*p3++] & 0x01) ? 0x80 : 0x00); ++ } ++ } ++ ++ for (i = 0; i < 8; i++) { ++ c = (c) ? 0 : 1; ++ r = (c) ? 6 : 7; ++ n = (i) ? i-1 : 1; ++ o = (c) ? ((k[n] & *f++) ? 1 : 0) : des_td[n]; ++ for (m = 1; m < r; m++) { ++ o = (c) ? (o*2) | ((k[*a++] & *b++) ? 0x01 : 0x00) : (o/2) | ((k[*a++] & *b++) ? 0x80 : 0x00); ++ } ++ n = (i) ? n+1 : 0; ++ des_td[n] = (c) ? des_td[n] ^ o : (o ^ des_td[n] )/4; ++ } ++ ++ for( i = 0; i < 8; i++) { ++ d[0] ^= (AND_bit1[i] & cw_sbox1[des_td[i]]); ++ d[1] ^= (AND_bit2[i] & cw_sbox2[des_td[i]]); ++ d[2] ^= (AND_bit3[i] & cw_sbox3[des_td[i]]); ++ d[3] ^= (AND_bit4[i] & cw_sbox4[des_td[i]]); ++ } ++ ++ CW_SWAP_DATA(d); ++} ++ ++static void CW_48_Key(uint8_t *inkey, uint8_t *outkey, uint8_t algotype) ++{ ++ uint8_t Round_Counter, i = 8, *key128 = inkey, *key48 = inkey + 0x10; ++ Round_Counter = 7 - (algotype & 7); ++ ++ memset(outkey, 0, 16); ++ memcpy(outkey, key48, 6); ++ ++ for( ; i > Round_Counter; i--) { ++ if (i > 1) { ++ outkey[i-2] = key128[i]; ++ } ++ } ++} ++ ++static void CW_LS_DES_KEY(uint8_t *key,uint8_t Rotate_Counter) ++{ ++ uint8_t round[] = {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}; ++ uint8_t i, n; ++ uint16_t k[8]; ++ ++ n = round[Rotate_Counter]; ++ ++ for (i = 0; i < 8; i++) { ++ k[i] = key[i]; ++ } ++ ++ for (i = 1; i < n + 1; i++) { ++ k[7] = (k[7]*2) | ((k[4] & 0x008) ? 1 : 0); ++ k[6] = (k[6]*2) | ((k[7] & 0xF00) ? 1 : 0); ++ k[7] &=0xff; ++ k[5] = (k[5]*2) | ((k[6] & 0xF00) ? 1 : 0); ++ k[6] &=0xff; ++ k[4] = ((k[4]*2) | ((k[5] & 0xF00) ? 1 : 0)) & 0xFF; ++ k[5] &= 0xff; ++ k[3] = (k[3]*2) | ((k[0] & 0x008) ? 1 : 0); ++ k[2] = (k[2]*2) | ((k[3] & 0xF00) ? 1 : 0); ++ k[3] &= 0xff; ++ k[1] = (k[1]*2) | ((k[2] & 0xF00) ? 1 : 0); ++ k[2] &= 0xff; ++ k[0] = ((k[0]*2) | ((k[1] & 0xF00) ? 1 : 0)) & 0xFF; ++ k[1] &= 0xff; ++ } ++ for (i = 0; i < 8; i++) { ++ key[i] = (uint8_t) k[i]; ++ } ++} ++ ++static void CW_RS_DES_KEY(uint8_t *k, uint8_t Rotate_Counter) ++{ ++ uint8_t i,c; ++ for (i = 1; i < Rotate_Counter+1; i++) { ++ c = (k[3] & 0x10) ? 0x80 : 0; ++ k[3] /= 2; ++ if (k[2] & 1) { ++ k[3] |= 0x80; ++ } ++ k[2] /= 2; ++ if (k[1] & 1) { ++ k[2] |= 0x80; ++ } ++ k[1] /= 2; ++ if (k[0] & 1) { ++ k[1] |= 0x80; ++ } ++ k[0] /= 2; ++ k[0] |= c ; ++ c = (k[7] & 0x10) ? 0x80 : 0; ++ k[7] /= 2; ++ if (k[6] & 1) { ++ k[7] |= 0x80; ++ } ++ k[6] /= 2; ++ if (k[5] & 1) { ++ k[6] |= 0x80; ++ } ++ k[5] /= 2; ++ if (k[4] & 1) { ++ k[5] |= 0x80; ++ } ++ k[4] /= 2; ++ k[4] |= c; ++ } ++} ++ ++static void CW_RS_DES_SUBKEY(uint8_t *k, uint8_t Rotate_Counter) ++{ ++ uint8_t round[] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; ++ CW_RS_DES_KEY(k, round[Rotate_Counter]); ++} ++ ++static void CW_PREP_KEY(uint8_t *key ) ++{ ++ uint8_t DES_key[8],j; ++ int32_t Round_Counter = 6,i,a; ++ key[7] = 6; ++ memset(DES_key, 0 , 8); ++ do { ++ a = 7; ++ i = key[7]; ++ j = key[Round_Counter]; ++ do { ++ DES_key[i] = ( (DES_key[i] * 2) | ((j & 1) ? 1: 0) ) & 0xFF; ++ j /=2; ++ i--; ++ if (i < 0) { ++ i = 6; ++ } ++ a--; ++ } ++ while (a >= 0); ++ key[7] = i; ++ Round_Counter--; ++ } ++ while ( Round_Counter >= 0 ); ++ a = DES_key[4]; ++ DES_key[4] = DES_key[6]; ++ DES_key[6] = a; ++ DES_key[7] = (DES_key[3] * 16) & 0xFF; ++ memcpy(key,DES_key,8); ++ CW_RS_DES_KEY(key,4); ++} ++ ++static void CW_L2DES(uint8_t *data, uint8_t *key, uint8_t algo) ++{ ++ uint8_t i, k0[22], k1[22]; ++ memcpy(k0,key,22); ++ memcpy(k1,key,22); ++ CW_48_Key(k0, k1,algo); ++ CW_PREP_KEY(k1); ++ for (i = 0; i< 2; i++) { ++ CW_LS_DES_KEY( k1,15); ++ CW_DES_ROUND( data ,k1); ++ } ++} ++ ++static void CW_R2DES(uint8_t *data, uint8_t *key, uint8_t algo) ++{ ++ uint8_t i, k0[22],k1[22]; ++ memcpy(k0,key,22); ++ memcpy(k1,key,22); ++ CW_48_Key(k0, k1, algo); ++ CW_PREP_KEY(k1); ++ for (i = 0; i< 2; i++) { ++ CW_LS_DES_KEY(k1,15); ++ } ++ for (i = 0; i< 2; i++) { ++ CW_DES_ROUND( data ,k1); ++ CW_RS_DES_SUBKEY(k1,1); ++ } ++ CW_SWAP_DATA(data); ++} ++ ++static void CW_DES(uint8_t *data, uint8_t *inkey, uint8_t m) ++{ ++ uint8_t key[22], i; ++ memcpy(key, inkey + 9, 8); ++ CW_PREP_KEY( key ); ++ for (i = 16; i > 0; i--) { ++ if (m == 1) { ++ CW_LS_DES_KEY(key, (uint8_t) (i-1)); ++ } ++ CW_DES_ROUND( data ,key); ++ if (m == 0) { ++ CW_RS_DES_SUBKEY(key, (uint8_t) (i-1)); ++ } ++ } ++} ++ ++static void CW_DEC_ENC(uint8_t *d, uint8_t *k, uint8_t a,uint8_t m) ++{ ++ uint8_t n = m & 1; ++ CW_L2DES(d , k, a); ++ CW_DES (d , k, n); ++ CW_R2DES(d , k, a); ++ if (m & 2) { ++ CW_SWAP_KEY(k); ++ } ++} ++ ++static void Cryptoworks3DES(uint8_t *data, uint8_t *key) ++{ ++ uint32_t ks1[32], ks2[32]; ++ ++ des_set_key(key, ks1); ++ des_set_key(key+8, ks2); ++ ++ des(data, ks1, 0); ++ des(data, ks2, 1); ++ des(data, ks1, 0); ++} ++ ++static uint8_t CryptoworksProcessNano80(uint8_t *data, uint32_t caid, int32_t provider, uint8_t *opKey, uint8_t nanoLength, uint8_t nano80Algo) ++{ ++ int32_t i, j; ++ uint8_t key[16], desKey[16], t[8], dat1[8], dat2[8], k0D00C000[16]; ++ if(nanoLength < 11) { ++ return 0; ++ } ++ if(caid == 0x0D00 && provider != 0xA0 && !GetCwKey(k0D00C000, 0x0D00C0, 0, 16, 1)) { ++ return 0; ++ } ++ ++ if(nano80Algo > 1) { ++ return 0; ++ } ++ ++ memset(t, 0, 8); ++ memcpy(dat1, data, 8); ++ ++ if(caid == 0x0D00 && provider != 0xA0) { ++ memcpy(key, k0D00C000, 16); ++ } ++ else { ++ memcpy(key, opKey, 16); ++ } ++ Cryptoworks3DES(data, key); ++ memcpy(desKey, data, 8); ++ ++ memcpy(data, dat1, 8); ++ if(caid == 0x0D00 && provider != 0xA0) { ++ memcpy(key, &k0D00C000[8], 8); ++ memcpy(&key[8], k0D00C000, 8); ++ } ++ else { ++ memcpy(key, &opKey[8], 8); ++ memcpy(&key[8], opKey, 8); ++ } ++ Cryptoworks3DES(data, key); ++ memcpy(&desKey[8], data, 8); ++ ++ for(i=8; i+7 7) { ++ if (first) { ++ CW_L2DES(signature, key, algo); ++ } ++ CW_DES(signature, key, 1); ++ ++ sigPos = 0; ++ first = 0; ++ } ++ } ++ if(sigPos > 0) { ++ CW_DES(signature, key, 1); ++ } ++ CW_R2DES(signature, key, algo); ++} ++ ++static void CryptoworksDecryptDes(uint8_t *data, uint8_t algo, uint8_t *key) ++{ ++ int32_t i; ++ uint8_t k[22], t[8]; ++ ++ algo &= 7; ++ if(algo<7) { ++ CW_DEC_ENC(data, key, algo, 0); ++ } ++ else { ++ memcpy(k, key, 22); ++ for(i=0; i<3; i++) { ++ CW_DEC_ENC(data, k, algo, i&1); ++ memcpy(t,k,8); ++ memcpy(k,k+8,8); ++ memcpy(k+8,t,8); ++ } ++ } ++} ++ ++static int8_t CryptoworksECM(uint32_t caid, uint8_t *ecm, uint8_t *cw) ++{ ++ uint32_t ident; ++ uint8_t keyIndex = 0, nanoLength, newEcmLength, key[22], signature[8], nano80Algo = 1; ++ int32_t provider = -1; ++ uint16_t i, j, ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 8) { ++ return 1; ++ } ++ if(ecm[7] != ecmLen - 8) { ++ return 1; ++ } ++ ++ memset(key, 0, 22); ++ ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { ++ if(ecm[i] == 0x83 && i+2 < ecmLen) { ++ provider = ecm[i+2] & 0xFC; ++ keyIndex = ecm[i+2] & 3; ++ keyIndex = keyIndex ? 1 : 0; ++ } ++ else if(ecm[i] == 0x84 && i+3 < ecmLen) { ++ //nano80Provider = ecm[i+2] & 0xFC; ++ //nano80KeyIndex = ecm[i+2] & 3; ++ //nano80KeyIndex = nano80KeyIndex ? 1 : 0; ++ nano80Algo = ecm[i+3]; ++ } ++ } ++ ++ if(provider < 0) { ++ switch(caid) { ++ case 0x0D00: ++ provider = 0xC0; ++ break; ++ case 0x0D02: ++ provider = 0xA0; ++ break; ++ case 0x0D03: ++ provider = 0x04; ++ break; ++ case 0x0D05: ++ provider = 0x04; ++ break; ++ default: ++ return 1; ++ } ++ } ++ ++ ident = (caid << 8) | provider; ++ if(!GetCwKey(key, ident, keyIndex, 16, 1)) { ++ return 2; ++ } ++ if(!GetCwKey(&key[16], ident, 6, 6, 1)) { ++ return 2; ++ } ++ ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { ++ if(ecm[i] == 0x80 && i+2+7 < ecmLen && i+2+ecm[i+1] <= ecmLen ++ && (provider == 0xA0 || provider == 0xC0 || provider == 0xC4 || provider == 0xC8)) { ++ nanoLength = ecm[i+1]; ++ newEcmLength = CryptoworksProcessNano80(ecm+i+2, caid, provider, key, nanoLength, nano80Algo); ++ if(newEcmLength == 0 || newEcmLength > ecmLen-(i+2+3)) { ++ return 1; ++ } ++ ecm[i+2+3] = 0x81; ++ ecm[i+2+4] = 0x70; ++ ecm[i+2+5] = newEcmLength; ++ ecm[i+2+6] = 0x81; ++ ecm[i+2+7] = 0xFF; ++ return CryptoworksECM(caid, ecm+i+2+3, cw); ++ } ++ } ++ ++ if(ecmLen - 15 < 1) { ++ return 1; ++ } ++ CryptoworksSignature(ecm + 5, ecmLen - 15, key, signature); ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { ++ switch(ecm[i]) { ++ case 0xDA: ++ case 0xDB: ++ case 0xDC: ++ if(i+2+ecm[i+1] > ecmLen) { ++ break; ++ } ++ for(j=0; j+7 ecmLen) { ++ break; ++ } ++ if(memcmp(&ecm[i+2], signature, 8)) { ++ return 6; ++ } ++ break; ++ } ++ } ++ ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { ++ switch(ecm[i]) { ++ case 0xDB: ++ if(i+2+ecm[i+1] <= ecmLen && ecm[i+1] == 16) { ++ memcpy(cw, &ecm[i+2], 16); ++ return 0; ++ } ++ break; ++ } ++ } ++ ++ return 5; ++} ++ ++// SoftNDS EMU ++static const uint8_t nds_const[]= {0x0F,0x1E,0x2D,0x3C,0x4B,0x5A,0x69,0x78,0x87,0x96,0xA5,0xB4,0xC3,0xD2,0xE1,0xF0}; ++ ++uint8_t viasat_const[]= { ++ 0x15,0x85,0xC5,0xE4,0xB8,0x52,0xEC,0xF7,0xC3,0xD9,0x08,0xBA,0x22,0x4A,0x66,0xF2, ++ 0x82,0x15,0x4F,0xB2,0x18,0x48,0x63,0x97,0xDC,0x19,0xD8,0x51,0x9A,0x39,0xFC,0xCA, ++ 0x1C,0x24,0xD0,0x65,0xA9,0x66,0x2D,0xD6,0x53,0x3B,0x86,0xBA,0x40,0xEA,0x4C,0x6D, ++ 0xD9,0x1E,0x41,0x14,0xFE,0x15,0xAF,0xC3,0x18,0xC5,0xF8,0xA7,0xA8,0x01,0x00,0x01, ++}; ++ ++static int8_t SoftNDSECM(uint16_t caid, uint8_t *ecm, uint8_t *dw) ++{ ++ int32_t i; ++ uint8_t *tDW, irdEcmLen, offsetCw = 0, offsetP2 = 0; ++ uint8_t digest[16], md5_const[64]; ++ MD5_CTX mdContext; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 7) { ++ return 1; ++ } ++ ++ if(ecm[3] != 0x00 || ecm[4] != 0x00 || ecm[5] != 0x01) { ++ return 1; ++ } ++ ++ irdEcmLen = ecm[6]; ++ if(irdEcmLen < (10+3+8+4) || irdEcmLen+6 >= ecmLen) { ++ return 1; ++ } ++ ++ for(i=0; 10+i+2 < irdEcmLen; i++) { ++ if(ecm[17+i] == 0x0F && ecm[17+i+1] == 0x40 && ecm[17+i+2] == 0x00) { ++ offsetCw = 17+i+3; ++ offsetP2 = offsetCw+9; ++ } ++ } ++ ++ if(offsetCw == 0 || offsetP2 == 0) { ++ return 1; ++ } ++ ++ if(offsetP2-7+4 > irdEcmLen) { ++ return 1; ++ } ++ ++ if(caid == 0x090F || caid == 0x093E) { ++ memcpy(md5_const, viasat_const, 64); ++ } ++ else if(!FindKey('S', caid, 0, "00", md5_const, 64, 1, 0, 0, NULL)) { ++ return 2; ++ } ++ ++ memset(dw,0,16); ++ tDW = &dw[ecm[0] == 0x81 ? 8 : 0]; ++ ++ MD5_Init(&mdContext); ++ MD5_Update(&mdContext, ecm+7, 10); ++ MD5_Update(&mdContext, ecm+offsetP2, 4); ++ MD5_Update(&mdContext, md5_const, 64); ++ MD5_Update(&mdContext, nds_const, 16); ++ MD5_Final(digest, &mdContext); ++ ++ for (i=0; i<8; i++) { ++ tDW[i] = digest[i+8] ^ ecm[offsetCw+i]; ++ } ++ ++ if(((tDW[0]+tDW[1]+tDW[2])&0xFF)-tDW[3]) { ++ return 6; ++ } ++ if(((tDW[4]+tDW[5]+tDW[6])&0xFF)-tDW[7]) { ++ return 6; ++ } ++ ++ return 0; ++} ++ ++// Viaccess EMU ++static int8_t GetViaKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) ++{ ++ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('V', ident, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ if(ident == 0xD00040 && FindKey('V', 0x030B00, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void Via1Mod(const uint8_t* key2, uint8_t* data) ++{ ++ int32_t kb, db; ++ for (db=7; db>=0; db--) { ++ for (kb=7; kb>3; kb--) { ++ int32_t a0=kb^db; ++ int32_t pos=7; ++ if (a0&4) { ++ a0^=7; ++ pos^=7; ++ } ++ a0=(a0^(kb&3)) + (kb&3); ++ if (!(a0&4)) { ++ data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); ++ } ++ } ++ } ++ for (db=0; db<8; db++) { ++ for (kb=0; kb<4; kb++) { ++ int32_t a0=kb^db; ++ int32_t pos=7; ++ if (a0&4) { ++ a0^=7; ++ pos^=7; ++ } ++ a0=(a0^(kb&3)) + (kb&3); ++ if (!(a0&4)) { ++ data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); ++ } ++ } ++ } ++} ++ ++static void Via1Decode(uint8_t *data, uint8_t *key) ++{ ++ Via1Mod(key+8, data); ++ nc_des(key, DES_ECM_CRYPT, data); ++ Via1Mod(key+8, data); ++} ++ ++static void Via1Hash(uint8_t *data, uint8_t *key) ++{ ++ Via1Mod(key+8, data); ++ nc_des(key, DES_ECM_HASH, data); ++ Via1Mod(key+8, data); ++} ++ ++static inline void Via1DoHash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey) ++{ ++ hashbuffer[*pH] ^= data; ++ (*pH)++; ++ ++ if(*pH == 8) { ++ Via1Hash(hashbuffer, hashkey); ++ *pH = 0; ++ } ++} ++ ++static int8_t Via1Decrypt(uint8_t* ecm, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t work_key[16]; ++ uint8_t *data, *des_data1, *des_data2; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ int32_t msg_pos; ++ int32_t encStart = 0, hash_start, i; ++ uint8_t signature[8], hashbuffer[8], prepared_key[16], hashkey[16]; ++ uint8_t tmp, k, pH, foundData = 0; ++ ++ if (ident == 0) { ++ return 4; ++ } ++ memset(work_key, 0, 16); ++ if(!GetViaKey(work_key, ident, '0', desKeyIndex, 8, 1)) { ++ return 2; ++ } ++ ++ if(ecmLen < 11) { ++ return 1; ++ } ++ data = ecm+9; ++ des_data1 = dw; ++ des_data2 = dw+8; ++ ++ msg_pos = 0; ++ pH = 0; ++ memset(hashbuffer, 0, sizeof(hashbuffer)); ++ memcpy(hashkey, work_key, sizeof(hashkey)); ++ memset(signature, 0, 8); ++ ++ while(9+msg_pos+2 < ecmLen) { ++ switch (data[msg_pos]) { ++ case 0xea: ++ if(9+msg_pos+2+15 < ecmLen) { ++ encStart = msg_pos + 2; ++ memcpy(des_data1, &data[msg_pos+2], 8); ++ memcpy(des_data2, &data[msg_pos+2+8], 8); ++ foundData |= 1; ++ } ++ break; ++ case 0xf0: ++ if(9+msg_pos+2+7 < ecmLen) { ++ memcpy(signature, &data[msg_pos+2], 8); ++ foundData |= 2; ++ } ++ break; ++ } ++ msg_pos += data[msg_pos+1]+2; ++ } ++ ++ if(foundData != 3) { ++ return 1; ++ } ++ ++ pH=i=0; ++ ++ if(data[0] == 0x9f && 10+data[1] <= ecmLen) { ++ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); ++ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); ++ ++ for (hash_start=0; hash_start < data[1]; hash_start++) { ++ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); ++ } ++ ++ while (pH != 0) { ++ Via1DoHash(hashbuffer, &pH, 0, hashkey); ++ } ++ } ++ ++ if (work_key[7] == 0) { ++ for (; i < encStart + 16; i++) { ++ Via1DoHash(hashbuffer, &pH, data[i], hashkey); ++ } ++ memcpy(prepared_key, work_key, 8); ++ } ++ else { ++ prepared_key[0] = work_key[2]; ++ prepared_key[1] = work_key[3]; ++ prepared_key[2] = work_key[4]; ++ prepared_key[3] = work_key[5]; ++ prepared_key[4] = work_key[6]; ++ prepared_key[5] = work_key[0]; ++ prepared_key[6] = work_key[1]; ++ prepared_key[7] = work_key[7]; ++ memcpy(prepared_key+8, work_key+8, 8); ++ ++ if (work_key[7] & 1) { ++ for (; i < encStart; i++) { ++ Via1DoHash(hashbuffer, &pH, data[i], hashkey); ++ } ++ ++ k = ((work_key[7] & 0xf0) == 0) ? 0x5a : 0xa5; ++ ++ for (i=0; i<8; i++) { ++ tmp = des_data1[i]; ++ des_data1[i] = (k & hashbuffer[pH] ) ^ tmp; ++ Via1DoHash(hashbuffer, &pH, tmp, hashkey); ++ } ++ ++ for (i = 0; i < 8; i++) { ++ tmp = des_data2[i]; ++ des_data2[i] = (k & hashbuffer[pH] ) ^ tmp; ++ Via1DoHash(hashbuffer, &pH, tmp, hashkey); ++ } ++ } ++ else { ++ for (; i < encStart + 16; i++) { ++ Via1DoHash(hashbuffer, &pH, data[i], hashkey); ++ } ++ } ++ } ++ Via1Decode(des_data1, prepared_key); ++ Via1Decode(des_data2, prepared_key); ++ Via1Hash(hashbuffer, hashkey); ++ if(memcmp(signature, hashbuffer, 8)) { ++ return 6; ++ } ++ return 0; ++} ++ ++static int8_t Via26ProcessDw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t pv1,pv2, i; ++ uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8]; ++ uint32_t ks1[32], ks2[32]; ++ ++ if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(KeyDes1, ident, 'D', 1, 16, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(KeyDes2, ident, '0', desKeyIndex, 16, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { ++ return 2; ++ } ++ ++ for (i=0; i<8; i++) { ++ pv1 = indata[i]; ++ Tmp[i] = T1Key[pv1]; ++ } ++ for (i=0; i<8; i++) { ++ pv1 = P1Key[i]; ++ pv2 = Tmp[pv1]; ++ indata[i]=pv2; ++ } ++ ++ des_set_key(KeyDes1, ks1); ++ des(indata, ks1, 1); ++ ++ for (i=0; i<8; i++) { ++ indata[i] ^= XorKey[i]; ++ } ++ ++ des_set_key(KeyDes2, ks1); ++ des_set_key(KeyDes2+8, ks2); ++ des(indata, ks1, 0); ++ des(indata, ks2, 1); ++ des(indata, ks1, 0); ++ ++ for (i=0; i<8; i++) { ++ indata[i] ^= XorKey[i]; ++ } ++ ++ des_set_key(KeyDes1, ks1); ++ des(indata, ks1, 0); ++ ++ for (i=0; i<8; i++) { ++ pv1 = indata[i]; ++ pv2 = P1Key[i]; ++ Tmp[pv2] = pv1; ++ } ++ for (i=0; i<8; i++) { ++ pv1 = Tmp[i]; ++ pv2 = T1Key[pv1]; ++ indata[i] = pv2; ++ } ++ return 0; ++} ++ ++static int8_t Via26Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t tmpData[8], C1[8]; ++ uint8_t *pXorVector; ++ int32_t i,j; ++ ++ if (ident == 0) { ++ return 4; ++ } ++ if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { ++ return 2; ++ } ++ ++ for (i=0; i<2; i++) { ++ memcpy(tmpData, source+ i*8, 8); ++ Via26ProcessDw(tmpData, ident, desKeyIndex); ++ if (i!=0) { ++ pXorVector = source; ++ } ++ else { ++ pXorVector = &C1[0]; ++ } ++ for (j=0; j<8; j++) { ++ dw[i*8+j] = tmpData[j]^pXorVector[j]; ++ } ++ } ++ return 0; ++} ++ ++static void Via3Core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) ++{ ++ uint8_t i; ++ uint32_t lR2, lR3, lR4, lR6, lR7; ++ ++ switch (ident) { ++ case 0x032820: { ++ for (i=0; i<4; i++) { ++ data[i]^= XorKey[(Off+i) & 0x07]; ++ } ++ lR2 = (data[0]^0xBD)+data[0]; ++ lR3 = (data[3]^0xEB)+data[3]; ++ lR2 = (lR2-lR3)^data[2]; ++ lR3 = ((0x39*data[1])<<2); ++ data[4] = (lR2|lR3)+data[2]; ++ lR3 = ((((data[0]+6)^data[0]) | (data[2]<<1))^0x65)+data[0]; ++ lR2 = (data[1]^0xED)+data[1]; ++ lR7 = ((data[3]+0x29)^data[3])*lR2; ++ data[5] = lR7+lR3; ++ lR2 = ((data[2]^0x33)+data[2]) & 0x0A; ++ lR3 = (data[0]+0xAD)^data[0]; ++ lR3 = lR3+lR2; ++ lR2 = data[3]*data[3]; ++ lR7 = (lR2 | 1) + data[1]; ++ data[6] = (lR3|lR7)+data[1]; ++ lR3 = data[1] & 0x07; ++ lR2 = (lR3-data[2]) & (data[0] | lR2 |0x01); ++ data[7] = lR2+data[3]; ++ for (i=0; i<4; i++) { ++ data[i+4] = T1Key[data[i+4]]; ++ } ++ } ++ break; ++ case 0x030B00: { ++ for (i=0; i<4; i++) { ++ data[i]^= XorKey[(Off+i) & 0x07]; ++ } ++ lR6 = (data[3] + 0x6E) ^ data[3]; ++ lR6 = (lR6*(data[2] << 1)) + 0x17; ++ lR3 = (data[1] + 0x77) ^ data[1]; ++ lR4 = (data[0] + 0xD7) ^ data[0]; ++ data[4] = ((lR4 & lR3) | lR6) + data[0]; ++ lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90; ++ lR6 = (data[1] + 0x1B) ^ data[1]; ++ lR4 = (lR4*lR6) ^ data[0]; ++ data[5] = (lR4 ^ (data[2] << 1)) + data[1]; ++ lR3 = (data[3] * data[3])| 0x01; ++ lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2]; ++ lR6 = data[1] ^ (data[0] + 0x4A); ++ data[6] = lR6 + lR4; ++ lR3 = (data[0] * (data[2] << 1)) | data[1]; ++ lR4 = 0xFE - data[3]; ++ lR3 = lR4 ^ lR3; ++ data[7] = lR3 + data[3]; ++ for (i=0; i<4; i++) { ++ data[4+i] = T1Key[data[4+i]]; ++ } ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void Via3Fct1(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) ++{ ++ uint8_t t; ++ Via3Core(data, 0, ident, XorKey, T1Key); ++ ++ switch (ident) { ++ case 0x032820: { ++ t = data[4]; ++ data[4] = data[7]; ++ data[7] = t; ++ } ++ break; ++ case 0x030B00: { ++ t = data[5]; ++ data[5] = data[7]; ++ data[7] = t; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void Via3Fct2(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) ++{ ++ uint8_t t; ++ Via3Core(data, 4, ident, XorKey, T1Key); ++ ++ switch (ident) { ++ case 0x032820: { ++ t = data[4]; ++ data[4] = data[7]; ++ data[7] = data[5]; ++ data[5] = data[6]; ++ data[6] = t; ++ } ++ break; ++ case 0x030B00: { ++ t = data[6]; ++ data[6] = data[7]; ++ data[7] = t; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static int8_t Via3ProcessDw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t i; ++ uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8]; ++ uint32_t ks1[32], ks2[32]; ++ ++ if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(KeyDes, ident, '0', desKeyIndex, 16, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { ++ return 2; ++ } ++ ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i+4]; ++ } ++ Via3Fct1(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i]^tmp[i+4]; ++ } ++ Via3Fct2(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i]^= XorKey[i+4]; ++ } ++ for (i=0; i<4; i++) { ++ data[i] = data[i+4]^tmp[i+4]; ++ data[i+4] = tmp[i]; ++ } ++ ++ des_set_key(KeyDes, ks1); ++ des_set_key(KeyDes+8, ks2); ++ ++ des(data, ks1, 0); ++ des(data, ks2, 1); ++ des(data, ks1, 0); ++ ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i+4]; ++ } ++ Via3Fct2(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i]^tmp[i+4]; ++ } ++ Via3Fct1(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i]^= XorKey[i]; ++ } ++ for (i=0; i<4; i++) { ++ data[i] = data[i+4]^tmp[i+4]; ++ data[i+4] = tmp[i]; ++ } ++ return 0; ++} ++ ++static void Via3FinalMix(uint8_t *dw) ++{ ++ uint8_t tmp[4]; ++ ++ memcpy(tmp, dw, 4); ++ memcpy(dw, dw + 4, 4); ++ memcpy(dw + 4, tmp, 4); ++ ++ memcpy(tmp, dw + 8, 4); ++ memcpy(dw + 8, dw + 12, 4); ++ memcpy(dw + 12, tmp, 4); ++} ++ ++static int8_t Via3Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex, uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix) ++{ ++ int8_t aesAfterCore = 0; ++ int8_t needsAES = (aesKeyIndex != 0xFF); ++ uint8_t tmpData[8], C1[8]; ++ uint8_t *pXorVector; ++ char aesKey[16]; ++ int32_t i, j; ++ ++ if(ident == 0) { ++ return 4; ++ } ++ if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { ++ return 2; ++ } ++ if(needsAES && !GetViaKey((uint8_t*)aesKey, ident, 'E', aesKeyIndex, 16, 1)) { ++ return 2; ++ } ++ if(aesMode == 0x0D || aesMode == 0x11 || aesMode == 0x15) { ++ aesAfterCore = 1; ++ } ++ ++ if(needsAES && !aesAfterCore) { ++ if(aesMode == 0x0F) { ++ hdSurEncPhase1_D2_0F_11(source); ++ hdSurEncPhase2_D2_0F_11(source); ++ } ++ else if(aesMode == 0x13) { ++ hdSurEncPhase1_D2_13_15(source); ++ } ++ struct aes_keys aes; ++ aes_set_key(&aes, aesKey); ++ aes_decrypt(&aes, source, 16); ++ if(aesMode == 0x0F) { ++ hdSurEncPhase1_D2_0F_11(source); ++ } ++ else if(aesMode == 0x13) { ++ hdSurEncPhase2_D2_13_15(source); ++ } ++ } ++ ++ for(i=0; i<2; i++) { ++ memcpy(tmpData, source+i*8, 8); ++ Via3ProcessDw(tmpData, ident, desKeyIndex); ++ if (i!=0) { ++ pXorVector = source; ++ } ++ else { ++ pXorVector = &C1[0]; ++ } ++ for (j=0; j<8; j++) { ++ dw[i*8+j] = tmpData[j]^pXorVector[j]; ++ } ++ } ++ ++ if(needsAES && aesAfterCore) { ++ if(aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(dw); ++ hdSurEncPhase2_D2_0F_11(dw); ++ } ++ else if(aesMode == 0x15) { ++ hdSurEncPhase1_D2_13_15(dw); ++ } ++ struct aes_keys aes; ++ aes_set_key(&aes, aesKey); ++ aes_decrypt(&aes, dw, 16); ++ if(aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(dw); ++ } ++ if(aesMode == 0x15) { ++ hdSurEncPhase2_D2_13_15(dw); ++ } ++ } ++ ++ if(ident == 0x030B00) { ++ if(doFinalMix) { ++ Via3FinalMix(dw); ++ } ++ if(!isValidDCW(dw)) { ++ return 6; ++ } ++ } ++ return 0; ++} ++ ++static int8_t ViaccessECM(uint8_t *ecm, uint8_t *dw) ++{ ++ uint32_t currentIdent = 0; ++ uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0, desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF; ++ int8_t doFinalMix = 0, result = 1; ++ uint16_t i = 0, keySelectPos = 0, ecmLen = GetEcmLen(ecm); ++ ++ for (i=4; i+2 ecmLen) { ++ return 1; ++ } ++ ++ switch (nanoCmd) { ++ case 0x40: ++ if (nanoLen < 0x03) { ++ break; ++ } ++ version = ecm[i]; ++ if (nanoLen == 3) { ++ currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); ++ desKeyIndex = ecm[i+2]&0x0F; ++ keySelectPos = i+3; ++ } ++ else { ++ currentIdent = (ecm[i]<<16)|(ecm[i+1]<<8)|((ecm[i+2]>>4)&0x0F); ++ desKeyIndex = ecm[i+3]; ++ keySelectPos = i+4; ++ } ++ providerKeyLen = nanoLen; ++ break; ++ case 0x90: ++ if (nanoLen < 0x03) { ++ break; ++ } ++ version = ecm[i]; ++ currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); ++ desKeyIndex = ecm[i+2]&0x0F; ++ keySelectPos = i+4; ++ if((version == 3) && (nanoLen > 3)) { ++ desKeyIndex = ecm[i+(nanoLen-4)]&0x0F; ++ } ++ providerKeyLen = nanoLen; ++ break; ++ case 0x80: ++ nanoLen = 0; ++ break; ++ case 0xD2: ++ if (nanoLen < 0x02) { ++ break; ++ } ++ aesMode = ecm[i]; ++ aesKeyIndex = ecm[i+1]; ++ break; ++ case 0xDD: ++ nanoLen = 0; ++ break; ++ case 0xEA: ++ if (nanoLen < 0x10) { ++ break; ++ } ++ ++ if (version < 2) { ++ return Via1Decrypt(ecm, dw, currentIdent, desKeyIndex); ++ } ++ else if (version == 2) { ++ return Via26Decrypt(ecm + i, dw, currentIdent, desKeyIndex); ++ } ++ else if (version == 3) { ++ doFinalMix = 0; ++ if (currentIdent == 0x030B00 && providerKeyLen>3) { ++ if(keySelectPos+2 >= ecmLen) { ++ break; ++ } ++ if (ecm[keySelectPos] == 0x05 && ecm[keySelectPos+1] == 0x67 && (ecm[keySelectPos+2] == 0x00 || ecm[keySelectPos+2] == 0x01)) { ++ if(ecm[keySelectPos+2] == 0x01) { ++ doFinalMix = 1; ++ } ++ } ++ else { ++ break; ++ } ++ } ++ return Via3Decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix); ++ } ++ break; ++ default: ++ break; ++ } ++ i += nanoLen; ++ } ++ return result; ++} ++ ++// Nagra EMU ++static int8_t GetNagraKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('N', ident, 0, keyStr, buf, keyName == 'M' ? 64 : 16, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int8_t Nagra2Signature(const uint8_t *vkey, const uint8_t *sig, const uint8_t *msg, int32_t len) ++{ ++ uint8_t buff[16]; ++ uint8_t iv[8]; ++ int32_t i,j; ++ ++ memcpy(buff,vkey,sizeof(buff)); ++ for(i=0; i+7=0; j--) { ++ buff[j+8]^=msg[i+j]; ++ } ++ } ++ buff[8]&=0x7F; ++ return (memcmp(sig, buff+8, 8) == 0); ++} ++ ++static int8_t DecryptNagra2ECM(uint8_t *in, uint8_t *out, const uint8_t *key, int32_t len, const uint8_t *vkey, uint8_t *keyM) ++{ ++ BIGNUM *exp, *mod; ++ uint8_t iv[8]; ++ int32_t i = 0, sign = in[0] & 0x80; ++ uint8_t binExp = 3; ++ int8_t result = 1; ++ ++ exp = BN_new(); ++ mod = BN_new(); ++ BN_bin2bn(&binExp, 1, exp); ++ BN_bin2bn(keyM, 64, mod); ++ ++ if(EmuRSA(out,in+1,64,exp,mod,1)<=0) { ++ BN_free(exp); ++ BN_free(mod); ++ return 0; ++ } ++ out[63]|=sign; ++ if(len>64) { ++ memcpy(out+64,in+65,len-64); ++ } ++ ++ memset(iv,0,sizeof(iv)); ++ if(in[0]&0x04) { ++ uint8_t key1[8], key2[8]; ++ ReverseMemInOut(key1,&key[0],8); ++ ReverseMemInOut(key2,&key[8],8); ++ ++ for(i=7; i>=0; i--) { ++ ReverseMem(out+8*i,8); ++ } ++ des_ede2_cbc_decrypt(out, iv, key1, key2, len); ++ for(i=7; i>=0; i--) { ++ ReverseMem(out+8*i,8); ++ } ++ } ++ else { ++ IDEA_KEY_SCHEDULE ek; ++ idea_set_encrypt_key(key, &ek); ++ idea_cbc_encrypt(out, out, len&~7, &ek, iv, IDEA_DECRYPT); ++ } ++ ++ ReverseMem(out,64); ++ if(result && EmuRSA(out,out,64,exp,mod,0)<=0) { ++ result = 0; ++ } ++ if(result && vkey && !Nagra2Signature(vkey,out,out+8,len-8)) { ++ result = 0; ++ } ++ ++ BN_free(exp); ++ BN_free(mod); ++ return result; ++} ++ ++static int8_t Nagra2ECM(uint8_t *ecm, uint8_t *dw) ++{ ++ uint32_t ident, identMask, tmp1, tmp2, tmp3; ++ uint8_t cmdLen, ideaKeyNr, *dec, ideaKey[16], vKey[16], m1Key[64], mecmAlgo = 0; ++ int8_t useVerifyKey = 0; ++ int32_t l=0, s; ++ uint16_t i = 0, ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 8) { ++ return 1; ++ } ++ cmdLen = ecm[4] - 5; ++ ident = (ecm[5] << 8) + ecm[6]; ++ ideaKeyNr = (ecm[7]&0x10)>>4; ++ if(ideaKeyNr) { ++ ideaKeyNr = 1; ++ } ++ if(ident == 1283 || ident == 1285 || ident == 1297) { ++ ident = 1281; ++ } ++ if(cmdLen <= 63 || ecmLen < cmdLen + 10) { ++ return 1; ++ } ++ ++ if(!GetNagraKey(ideaKey, ident, '0', ideaKeyNr, 1)) { ++ return 2; ++ } ++ if(GetNagraKey(vKey, ident, 'V', 0, 0)) { ++ useVerifyKey = 1; ++ } ++ if(!GetNagraKey(m1Key, ident, 'M', 1, 1)) { ++ return 2; ++ } ++ ReverseMem(m1Key, 64); ++ ++ dec = (uint8_t*)malloc(sizeof(uint8_t)*cmdLen); ++ if(dec == NULL) { ++ return 7; ++ } ++ if(!DecryptNagra2ECM(ecm+9, dec, ideaKey, cmdLen, useVerifyKey?vKey:0, m1Key)) { ++ free(dec); ++ return 1; ++ } ++ ++ for(i=(dec[14]&0x10)?16:20; i0) { ++ return 1; ++ } ++ ++ identMask = ident & 0xFF00; ++ if (identMask == 0x1100 || identMask == 0x500 || identMask == 0x3100) { ++ memcpy(&tmp1, dw, 4); ++ memcpy(&tmp2, dw + 4, 4); ++ memcpy(&tmp3, dw + 12, 4); ++ memcpy(dw, dw + 8, 4); ++ memcpy(dw + 4, &tmp3, 4); ++ memcpy(dw + 8, &tmp1, 4); ++ memcpy(dw + 12, &tmp2, 4); ++ } ++ return 0; ++} ++ ++// Irdeto EMU ++static int8_t GetIrdetoKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey, uint32_t *keyRef) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ ++ if(*keyRef > 0xFF) ++ { ++ return 0; ++ } ++ ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('I', ident, 0, keyStr, buf, 16, *keyRef > 0 ? 0 : isCriticalKey, *keyRef, 0, NULL)) { ++ (*keyRef)++; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void Irdeto2Encrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) ++{ ++ const uint8_t *tmp = seed;; ++ int32_t i; ++ uint32_t ks1[32], ks2[32]; ++ ++ des_set_key(key, ks1); ++ des_set_key(key+8, ks2); ++ ++ len&=~7; ++ ++ for(i=0; i+7> 16; ++ ++ switch (pos) ++ { ++ case 29: // Rascom QAF 1R ++ case 31: // Eutelsat 3B ++ { ++ pos = 30; ++ break; ++ } ++ ++ case 49: ++ case 50: // SES 5 ++ { ++ pos = 48; // Astra 4A ++ break; ++ } ++ ++ case 215: ++ { ++ pos = 216; // Eutelsat 21B ++ break; ++ } ++ ++ case 285: // Astra 2E ++ { ++ pos = 282; // Astra 2F/2G ++ break; ++ } ++ ++ case 328: // Intelsat 28 ++ case 329: ++ case 331: // Eutelsat 33C ++ { ++ pos = 330; ++ break; ++ } ++ ++ case 359: // Eutelsat 36B ++ case 361: // Express AMU1 ++ { ++ pos = 360; ++ break; ++ } ++ ++ case 451: // Intelsat 904 ++ { ++ pos = 450; // Intelsat 12 ++ break; ++ } ++ ++ case 550: ++ case 551: // G-Sat 8/16 ++ { ++ pos = 549; // Yamal 402 ++ break; ++ } ++ ++ case 748: ++ case 749: // ABS 2A ++ { ++ pos = 750; ++ break; ++ } ++ ++ case 848: // Horizons 2 ++ case 852: // Intelsat 15 ++ { ++ pos = 850; ++ break; ++ } ++ ++ case 914: // Mesasat 3a ++ { ++ pos = 915; // Mesasat 3/3b ++ break; ++ } ++ ++ case 934: // G-Sat 17 ++ case 936: // Insat 4B ++ { ++ pos = 935; // G-Sat 15 ++ break; ++ } ++ ++ case 3600 - 911: // Nimiq 6 ++ { ++ pos = 3600 - 910; // Galaxy 17 ++ } ++ ++ case 3600 - 870: // SES 2 ++ case 3600 - 872: // TKSat 1 ++ { ++ pos = 3600 - 871; ++ break; ++ } ++ ++ case 3600 - 432: // Sky Brasil 1 ++ case 3600 - 430: // Intelsat 11 ++ { ++ pos = 3600 - 431; ++ break; ++ } ++ ++ case 3600 - 376: // Telstar 11N ++ case 3600 - 374: // NSS 10 ++ { ++ pos = 3600 - 375; ++ break; ++ } ++ ++ case 3600 - 359: // Hispasat 36W-1 ++ { ++ pos = 3600 - 360; // Eutelsat 36 West A ++ break; ++ } ++ ++ case 3600 - 81: // Eutelsat 8 West B ++ { ++ pos = 3600 - 80; ++ break; ++ } ++ ++ case 3600 - 73: // Eutelsat 7 West A ++ case 3600 - 72: ++ case 3600 - 71: ++ { ++ pos = 3600 - 70; // Nilesat 201 ++ break; ++ } ++ ++ case 3600 - 10: // Intelsat 10-02 ++ case 3600 - 9: // Thor 6 ++ case 3600 - 7: // Thor 7 ++ case 3600 - 6: // Thor 7 ++ { ++ pos = 3600 - 8; // Thor 5 ++ break; ++ } ++ } ++ ++ *namespace = (*namespace & 0xF000FFFF) | (pos << 16); ++} ++ ++static void BissAnnotate(char *buf, uint8_t len, const uint8_t *ecm, uint16_t ecmLen, uint32_t hash, int8_t isNamespaceHash, int8_t datecoded) ++{ ++ // Extract useful information to append to the "Example key ..." message. ++ // ++ // For feeds, the orbital position & frequency are usually embedded in the namespace. ++ // See https://github.com/openatv/enigma2/blob/master/lib/dvb/frontend.cpp#L496 ++ // hash = (sat.orbital_position << 16); ++ // hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15); ++ // ++ // If the onid & tsid appear to be a unique DVB identifier, enigma2 strips the frequency ++ // from our namespace. See https://github.com/openatv/enigma2/blob/master/lib/dvb/scan.cpp#L59 ++ // In that case, our annotation contains the onid:tsid:sid triplet in lieu of frequency. ++ // ++ // For the universal case, we print the number of elementary stream pids & pmtpid. ++ // The sid and current time are included for all. Examples: ++ // ++ // F 1A2B3C4D 00000000 XXXXXXXXXXXXXXXX ; 110.5W 12345H sid:0001 added: 2017-10-17 @ 13:14:15 // namespace ++ // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; 33.5E ABCD:9876:1234 added: 2017-10-17 @ 13:14:15 // stripped namespace ++ // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; av:5 pmt:0134 sid:0001 added: 2017-10-17 @ 13:14:15 // universal ++ ++ uint8_t pidcount; ++ uint16_t frequency, degrees, pmtpid, srvid, tsid, onid; ++ uint32_t ens; ++ char compass, polarisation, timeStr1[9], timeStr2[19]; ++ ++ if (datecoded) ++ { ++ Date2Str(timeStr1, sizeof(timeStr1), 4, 3); ++ } ++ else ++ { ++ snprintf(timeStr1, sizeof(timeStr1), "00000000"); ++ } ++ ++ Date2Str(timeStr2, sizeof(timeStr2), 0, 2); ++ ++ if (isNamespaceHash) // Namespace hash ++ { ++ ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes of the ecm ++ degrees = (ens >> 16) & 0x0FFF; // Remove not-a-pid flag ++ ++ if (degrees > 1800) ++ { ++ degrees = 3600 - degrees; ++ compass = 'W'; ++ } ++ else ++ { ++ compass = 'E'; ++ } ++ ++ if (0 == (ens & 0xFFFF)) // Stripped namespace hash ++ { ++ srvid = b2i(2, ecm + 3); ++ tsid = b2i(2, ecm + ecmLen - 8); ++ onid = b2i(2, ecm + ecmLen - 6); ++ // Printing degree sign "\u00B0" requires c99 standard ++ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %04X:%04X:%04X added: %s", ++ hash, timeStr1, degrees / 10.0, compass, onid, tsid, srvid, timeStr2); ++ } ++ else // Full namespace hash ++ { ++ srvid = b2i(2, ecm + 3); ++ frequency = ens & 0x7FFF; // Remove polarity bit ++ polarisation = ens & 0x8000 ? 'V' : 'H'; ++ // Printing degree sign "\u00B0" requires c99 standard ++ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %5d%c sid:%04X added: %s", ++ hash, timeStr1, degrees / 10.0, compass, frequency, polarisation, srvid, timeStr2); ++ } ++ } ++ else // Universal hash ++ { ++ srvid = b2i(2, ecm + 3); ++ pmtpid = b2i(2, ecm + 5); ++ pidcount = (ecmLen - 15) / 2; // video + audio pids count ++ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; av:%d pmt:%04X sid:%04X added: %s", ++ hash, timeStr1, pidcount, pmtpid, srvid, timeStr2); ++ } ++} ++ ++static int8_t BissIsCommonHash(uint32_t hash) ++{ ++ // Check universal hash against a number of commnon universal ++ // hashes in order to warn users about potential key clashes ++ ++ switch (hash) ++ { ++ case 0xBAFCD9FD: // 0001 0020 0200 1010 1020 (most common hash) ++ return 1; ++ case 0xA6A4FBD4: // 0001 0800 0200 1010 1020 ++ return 1; ++ case 0xEFAB7A4D: // 0001 0800 1010 1020 0200 ++ return 1; ++ case 0x83FA15D1: // 0001 0020 0134 0100 0101 ++ return 1; ++ case 0x58934C38: // 0001 0800 1010 1020 1030 0200 ++ return 1; ++ case 0x2C3CEC17: // 0001 0020 0134 0100 ++ return 1; ++ case 0x73DF7F7E: // 0001 0020 0200 1010 1020 1030 ++ return 1; ++ case 0xAFA85BC8: // 0001 0020 0021 0022 0023 ++ return 1; ++ case 0x8C51F31D: // 0001 0800 0200 1010 1020 1030 1040 ++ return 1; ++ case 0xE2F9BD29: // 0001 0800 0200 1010 1020 1030 ++ return 1; ++ case 0xB9EBE0FF: // 0001 0100 0200 1010 1020 (less common hash) ++ return 1; ++ default: ++ return 0; ++ } ++} ++ ++static int8_t BissIsValidNamespace(uint32_t namespace) ++{ ++ // Note to developers: ++ // If we ever have a satellite at 0.0E, edit to allow stripped namespace ++ // '0xA0000000' with an additional test on tsid and onid being != 0 ++ ++ uint16_t orbital, frequency; ++ ++ orbital = (namespace >> 16) & 0x0FFF; ++ frequency = namespace & 0x7FFF; ++ ++ if ((namespace & 0xA0000000) != 0xA0000000) return 0; // Value isn't flagged as namespace ++ if (namespace == 0xA0000000) return 0; // Empty namespace ++ if (orbital > 3599) return 0; // Allow only DVB-S ++ if (frequency == 0) return 1; // Stripped namespace ++ if (frequency >= 3400 && frequency <= 4200) return 1; // Super extended C band ++ if (frequency >= 10700 && frequency <= 12750) return 1; // Ku band Europe ++ ++ return 0; ++} ++ ++static int8_t BissGetKey(uint32_t provider, uint8_t *key, int8_t dateCoded, int8_t printMsg) ++{ ++ // If date-coded keys are enabled in the webif, this function evaluates the expiration date ++ // of the keys found. Expired keys are not sent to BissECM(). If date-coded keys are disabled, ++ // then all keys found are sent without any evaluation. It takes the "provider" as input and ++ // outputs the "key". Returns 0 (Key not found, or expired) or 1 (Key found). ++ ++ // printMsg: 0 => No message ++ // printMsg: 1 => Print message only if key is found ++ // printMsg: 2 => Always print message, regardless if key is found or not ++ ++ char keyExpDate[9] = "00000000"; ++ ++ if (FindKey('F', provider, 0, keyExpDate, key, 8, 0, 0, 0, NULL)) // Key found ++ { ++ if (dateCoded) // Date-coded keys are enabled, evaluate expiration date ++ { ++ char currentDate[9]; ++ Date2Str(currentDate, sizeof(currentDate), 0, 3); ++ ++ if (strncmp("00000000", keyExpDate, 9) == 0 || strncmp(currentDate, keyExpDate, 9) < 0) // Evergreen or not expired ++ { ++ if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); ++ return 1; ++ } ++ else // Key expired ++ { ++ key = NULL; // Make sure we don't send any expired key ++ if (printMsg == 2) cs_log("Key expired: F %08X %s", provider, keyExpDate); ++ return 0; ++ } ++ } ++ else // Date-coded keys are disabled, don't evaluate expiration date ++ { ++ if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); ++ return 1; ++ } ++ } ++ else // Key not found ++ { ++ if (printMsg == 2) cs_log("Key not found: F %08X", provider); ++ return 0; ++ } ++} ++ ++static int8_t BissECM(struct s_reader *rdr, const uint8_t *ecm, int16_t ecmDataLen, uint8_t *dw, uint16_t srvid, uint16_t ecmpid) ++{ ++ // Oscam's fake ecm consists of [sid] [pmtpid] [pid1] [pid2] ... [pidx] [tsid] [onid] [namespace] ++ // ++ // On enigma boxes tsid, onid and namespace should be non zero, while on non-enigma ++ // boxes they are usually all zero. ++ // The emulator creates a unique channel hash using srvid and enigma namespace or ++ // srvid, tsid, onid and namespace (in case of namespace without frequency) and ++ // another weaker (not unique) hash based on every pid of the channel. This universal ++ // hash should be available on all types of stbs (enigma and non-enigma). ++ ++ // Flags inside [namespace] ++ // ++ // emu r748- : no namespace, no flag ++ // emu r749 : 0x80000000 (full namespase), 0xC0000000 (stripped namespace, injected with tsid^onid^ecmpid^0x1FFF) ++ // emu r752+ : 0xA0000000 (pure namespace, either full, stripped, or null) ++ ++ // Key searches are made in order: ++ // Highest priority / tightest test first ++ // Lowest priority / loosest test last ++ // ++ // 1st: namespace hash (only on enigma boxes) ++ // 2nd: universal hash (all box types with emu r752+) ++ // 3rd: valid tsid, onid combination ++ // 4th: faulty ecmpid (other than 0x1FFF) ++ // 5th: reverse order pid (audio, video, pmt pids) ++ // 6th: standard BISS ecmpid (0x1FFF) ++ // 7th: default "All Feeds" key ++ ++ // If enabled in the webif, a date based key search can be performed. If the expiration ++ // date has passed, the key is not sent from BissGetKey(). This search method is only ++ // used in the namespace hash, universal hash and the default "All Feeds" key. ++ ++ uint8_t ecmCopy[EMU_MAX_ECM_LEN]; ++ uint16_t ecmLen = 0, pid = 0; ++ uint32_t i, ens = 0, hash = 0; ++ char tmpBuffer1[17], tmpBuffer2[90] = "0", tmpBuffer3[90] = "0"; ++ ++ if (ecmDataLen >= 3) ++ { ++ ecmLen = GetEcmLen(ecm); ++ } ++ ++ // First try using the unique namespace hash (enigma only) ++ if (ecmLen >= 13 && ecmLen <= ecmDataLen) // ecmLen >= 13, allow patching the ecmLen for r749 ecms ++ { ++ memcpy(ecmCopy, ecm, ecmLen); ++ ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes ++ ++ if (BissIsValidNamespace(ens)) // An r752+ extended ecm with valid namespace ++ { ++ BissUnifyOrbitals(&ens); ++ i2b_buf(4, ens, ecmCopy + ecmLen - 4); ++ ++ for (i = 0; i < 5; i++) // Find key matching hash made with frequency modified to: f+0, then f-1, f+1, f-2, lastly f+2 ++ { ++ ecmCopy[ecmLen - 1] = (i & 1) ? ecmCopy[ecmLen - 1] - i : ecmCopy[ecmLen - 1] + i; // frequency +/- 1, 2 MHz ++ ++ if (0 != (ens & 0xFFFF)) // Full namespace - Calculate hash with srvid and namespace only ++ { ++ i2b_buf(2, srvid, ecmCopy + ecmLen - 6); // Put [srvid] right before [namespace] ++ hash = crc32(0x2600, ecmCopy + ecmLen - 6, 6); ++ } ++ else // Namespace without frequency - Calculate hash with srvid, tsid, onid and namespace ++ { ++ i2b_buf(2, srvid, ecmCopy + ecmLen - 10); // Put [srvid] right before [tsid] [onid] [namespace] sequence ++ hash = crc32(0x2600, ecmCopy + ecmLen - 10, 10); ++ } ++ ++ if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, i == 0 ? 2 : 1)) // Do not print "key not found" for frequency off by 1, 2 ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ ++ if (i == 0) // No key found matching our hash: create example SoftCam.Key BISS line for the live log ++ { ++ BissAnnotate(tmpBuffer2, sizeof(tmpBuffer2), ecmCopy, ecmLen, hash, 1, rdr->emu_datecodedenabled); ++ } ++ ++ if (0 == (ens & 0xFFFF)) // Namespace without frequency - Do not iterate ++ { ++ break; ++ } ++ } ++ } ++ ++ if ((ens & 0xA0000000) == 0x80000000) // r749 ecms only (exclude r752+ ecms) ++ { ++ cs_log("Hey! Network buddy, you need to upgrade your OSCam-Emu"); ++ ecmCopy[ecmLen] = 0xA0; // Patch ecm to look like r752+ ++ ecmLen += 4; ++ ecmDataLen += 4; ++ } ++ } ++ ++ // Try using the universal channel hash (namespace not available) ++ if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms ++ { ++ ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes ++ ++ if ((ens & 0xE0000000) == 0xA0000000) // We have an r752+ style ecm which contains pmtpid ++ { ++ memcpy(ecmCopy, ecm, ecmLen - 8); // Make a new ecmCopy from the original ecm as the old ecmCopy may be altered in namespace hash (skip [tsid] [onid] [namespace]) ++ hash = crc32(0x2600, ecmCopy + 3, ecmLen - 3 - 8); // ecmCopy doesn't have [tsid] [onid] [namespace] part ++ ++ if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, 2)) // Key found ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ ++ // No key found matching our hash: create example SoftCam.Key BISS line for the live log ++ BissAnnotate(tmpBuffer3, sizeof(tmpBuffer3), ecmCopy, ecmLen, hash, 0, rdr->emu_datecodedenabled); ++ } ++ } ++ ++ // Try using only [tsid][onid] (useful when many channels on a transpoder use the same key) ++ if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms ++ { ++ ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes ++ ++ // We have an r752+ style ecm with stripped namespace, thus a valid [tsid][onid] combo to use as provider ++ if ((ens & 0xE000FFFF) == 0xA0000000 && BissGetKey(b2i(4, ecm + ecmLen - 8), dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ ++ if ((ens & 0xE0000000) == 0xA0000000) // Strip [tsid] [onid] [namespace] on r752+ ecms ++ { ++ ecmLen -= 8; ++ ecmDataLen -= 8; ++ } ++ } ++ ++ // Try using ecmpid if it seems to be faulty (should be 0x1FFF always for BISS) ++ if (ecmpid != 0x1FFF && ecmpid != 0) ++ { ++ if (BissGetKey((srvid << 16) | ecmpid, dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ } ++ ++ // Try to get the pid from oscam's fake ecm (only search [pid1] [pid2] ... [pidx] to be compatible with emu r748-) ++ if (ecmLen >= 7 && ecmLen <= ecmDataLen) // Use >= for radio channels with just one (audio) pid ++ { ++ // Reverse search order: last pid in list first ++ // Better identifies channels where they share identical video pid but have variable counts of audio pids ++ for (i = ecmLen - 2; i >= 5; i -= 2) ++ { ++ pid = b2i(2, ecm + i); ++ ++ if (BissGetKey((srvid << 16) | pid, dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ } ++ } ++ ++ // Try using the standard BISS ecm pid ++ if (ecmpid == 0x1FFF || ecmpid == 0) ++ { ++ if (BissGetKey((srvid << 16) | 0x1FFF, dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ } ++ ++ // Default BISS key for events with many feeds sharing same key ++ if (ecmpid != 0 && BissGetKey(0xA11FEED5, dw, rdr->emu_datecodedenabled, 2)) // Limit to local ecms, block netwotk ecms ++ { ++ memcpy(dw + 8, dw, 8); ++ cs_hexdump(0, dw, 8, tmpBuffer1, sizeof(tmpBuffer1)); ++ cs_log("No specific match found. Using 'All Feeds' key: %s", tmpBuffer1); ++ return 0; ++ } ++ ++ // Print example key lines for available hash search methods, if no key is found ++ if (strncmp(tmpBuffer2, "0", 2)) cs_log("Example key based on namespace hash: %s", tmpBuffer2); ++ if (strncmp(tmpBuffer3, "0", 2)) cs_log("Example key based on universal hash: %s", tmpBuffer3); ++ ++ // Check if universal hash is common and warn user ++ if (BissIsCommonHash(hash)) cs_log("Feed has commonly used pids, universal hash clashes in SoftCam.Key are likely!"); ++ ++ return 2; ++} ++ ++// PowerVu Emu ++static uint8_t PowervuCrc8Calc(uint8_t *data, int len) ++{ ++ int i; ++ uint8_t crc = 0x00; ++ uint8_t crcTable[256] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, ++ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, ++ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, ++ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, ++ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, ++ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, ++ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, ++ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, ++ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, ++ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, ++ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, ++ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, ++ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, ++ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, ++ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, ++ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; ++ ++ for(i = 0; i < len; i++) ++ { ++ crc = crcTable[data[i] ^ crc]; ++ } ++ ++ return crc; ++} ++ ++static void PowervuPadData(uint8_t *data, int len, uint8_t *dataPadded) ++{ ++ int i; ++ uint8_t pad[] = {0x01, 0x02, 0x22, 0x04, 0x20, 0x2A, 0x1F, 0x03, 0x04, 0x06, 0x02, 0x0C, 0x2B, 0x2B, 0x01, 0x7B}; ++ ++ for(i = 0; i < len; i++) ++ { ++ dataPadded[i] = data[i]; ++ } ++ ++ dataPadded[len] = 0x01; ++ ++ for(i = len + 1; i < 0x2F; i++) ++ { ++ dataPadded[i] = 0x00; ++ } ++ ++ dataPadded[0x2F] = len; ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ dataPadded[0x30 + i] = pad[i]; ++ } ++} ++ ++static void PowervuHashMode01CustomMD5(uint8_t *data, uint8_t *hash) ++{ ++ int i, j, s; ++ uint32_t a, b, c, d, f = 0, g; ++ ++ uint32_t T[] = {0x783E16F6, 0xC267AC13, 0xA2B17F12, 0x6B8A31A4, 0xF910654D, 0xB702DBCB, 0x266CEF60, 0x5145E47C, ++ 0xB92E00D6, 0xE80A4A64, 0x8A07FA77, 0xBA7D89A9, 0xEBED8022, 0x653AAF2B, 0xF118B03B, 0x6CC16544, ++ 0x96EB6583, 0xF4E27E35, 0x1ABB119E, 0x068D3EF2, 0xDAEAA8A5, 0x3C312A3D, 0x59538388, 0xA100772F, ++ 0xAB0165CE, 0x979959E7, 0x5DD8F53D, 0x189662BA, 0xFD021A9C, 0x6BC2D338, 0x1EFF667E, 0x40C66888, ++ 0x6E9F07FF, 0x0CEF442F, 0x82D20190, 0x4E8CAEAC, 0x0F7CB305, 0x2E73FBE7, 0x1CE884A2, 0x7A60BD52, ++ 0xC348B30D, 0x081CE3AA, 0xA12220E7, 0x38C7EC79, 0xCBD8DD3A, 0x62B4FBA5, 0xAD2A63DB, 0xE4D0852E, ++ 0x53DE980F, 0x9C8DDA59, 0xA6B4CEDE, 0xB48A7692, 0x0E2C46A4, 0xEB9367CB, 0x165D72EE, 0x75532B45, ++ 0xB9CA8E97, 0x08C8837B, 0x966F917B, 0x527515B4, 0xF27A5E5D, 0xB71E6267, 0x7603D7E6, 0x9837DD69}; // CUSTOM T ++ ++ uint8_t r[] = {0x06, 0x0A, 0x0F, 0x15, 0x05, 0x09, 0x0E, 0x14, 0x04, 0x0B, 0x10, 0x17, 0x07, 0x0C, 0x11, 0x16}; // STANDARD REORDERED ++ ++ uint8_t tIdxInit[] = {0, 1, 5, 0}; // STANDARD ++ uint8_t tIdxIncr[] = {1, 5, 3, 7}; // STANDARD ++ ++ uint32_t h[] = {0xEAD81D2E, 0xCE4DC6E9, 0xF9B5C301, 0x10325476}; // CUSTOM h0, h1, h2 STANDARD h3 ++ uint32_t dataLongs[0x10]; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ dataLongs[i] = (data[4 * i + 0] << 0) + (data[4 * i + 1] << 8) + (data[4 * i + 2] << 16) + (data[4 * i + 3] << 24); ++ } ++ ++ a = h[0]; ++ b = h[1]; ++ c = h[2]; ++ d = h[3]; ++ ++ for (i = 0; i < 4; i++) ++ { ++ g = tIdxInit[i]; ++ ++ for (j = 0; j < 16; j++) ++ { ++ if (i == 0) ++ { ++ f = (b & c) | (~b & d); ++ } ++ else if (i == 1) ++ { ++ f = (b & d) | (~d & c); ++ } ++ else if (i == 2) ++ { ++ f = (b ^ c ^ d); ++ } ++ else if (i == 3) ++ { ++ f = (~d | b) ^ c; ++ } ++ ++ f = dataLongs[g] + a + T[16 * i + j] + f; ++ ++ s = r[4 * i + (j & 3)]; ++ f = (f << s) | (f >> (32 - s)); ++ ++ a = d; ++ d = c; ++ c = b; ++ b += f; ++ ++ g = (g + tIdxIncr[i]) & 0xF; ++ } ++ } ++ ++ h[0] += a; ++ h[1] += b; ++ h[2] += c; ++ h[3] += d; ++ ++ for (i = 0; i < 4; i++) ++ { ++ hash[4 * i + 0] = h[i] >> 0; ++ hash[4 * i + 1] = h[i] >> 8; ++ hash[4 * i + 2] = h[i] >> 16; ++ hash[4 * i + 3] = h[i] >> 24; ++ } ++} ++ ++static void PowervuHashMode02(uint8_t *data, uint8_t *hash) ++{ ++ int i; ++ uint32_t a, b, c, d, e, f = 0, tmp; ++ uint32_t h[] = {0x81887F3A, 0x36CCA480, 0x99056FB1, 0x79705BAE}; ++ uint32_t dataLongs[0x50]; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); ++ } ++ ++ for (i = 0; i < 0x40; i++) ++ { ++ dataLongs[0x10 + i] = dataLongs[0x10 + i - 2]; ++ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 7]; ++ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 13]; ++ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 16]; ++ } ++ ++ a = dataLongs[0]; ++ b = dataLongs[1]; ++ c = dataLongs[2]; ++ d = dataLongs[3]; ++ e = dataLongs[4]; ++ ++ for (i = 0; i < 0x50; i++) ++ { ++ if (i < 0x15) f = (b & c) | (~b & d); ++ else if (i < 0x28) f = (b ^ c ^ d); ++ else if (i < 0x3D) f = (b & c) | (c & d) | (b & d); ++ else if (i < 0x50) f = (b ^ c ^ d); ++ ++ tmp = a; ++ a = e + f + (a << 5) + (a >> 27) + h[i / 0x14] + dataLongs[i]; ++ e = d; ++ d = c; ++ c = (b << 30) + (b >> 2); ++ b = tmp; ++ } ++ ++ dataLongs[0] += a; ++ dataLongs[1] += b; ++ dataLongs[2] += c; ++ dataLongs[3] += d; ++ ++ for (i = 0; i < 4; i++) ++ { ++ hash[4 * i + 0] = dataLongs[i] >> 24; ++ hash[4 * i + 1] = dataLongs[i] >> 16; ++ hash[4 * i + 2] = dataLongs[i] >> 8; ++ hash[4 * i + 3] = dataLongs[i] >> 0; ++ } ++} ++ ++static void PowervuHashMode03(uint8_t *data, uint8_t *hash) ++{ ++ int i, j, k, s, s2, tmp; ++ uint32_t a, b, c, d, f = 0, g; ++ uint32_t a2, b2, c2, d2, f2 = 0, g2; ++ ++ uint32_t T[] = { 0xC88F3F2E, 0x967506BA, 0xDA877A7B, 0x0DECCDFE }; ++ uint32_t T2[] = { 0x01F42668, 0x39C7CDA5, 0xD490E2FE, 0x9965235D }; ++ ++ uint8_t r[] = { 0x0B, 0x0E, 0x0F, 0x0C, 0x05, 0x08, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0F, 0x06, 0x07, 0x09, 0x08, ++ 0x07, 0x06, 0x08, 0x0D, 0x0B, 0x09, 0x07, 0x0F, 0x07, 0x0C, 0x0F, 0x09, 0x0B, 0x07, 0x0D, 0x0C }; ++ ++ uint8_t tIdxIncr[] = { 0x07, 0x04, 0x0D, 0x01, 0x0A, 0x06, 0x0F, 0x03, 0x0C, 0x00, 0x09, 0x05, 0x02, 0x0E, 0x0B, 0x08, ++ 0x05, 0x0D, 0x02, 0x00, 0x04, 0x09, 0x03, 0x08, 0x01, 0x0A, 0x07, 0x0B, 0x06, 0x0F, 0x0C, 0x0E }; ++ ++ uint32_t h[] = { 0xC8616857, 0x9D3F5B8E, 0x4D7B8F76, 0x97BC8D80 }; ++ ++ uint32_t dataLongs[0x50]; ++ uint32_t result[4]; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); ++ } ++ ++ a = h[0]; ++ b = h[1]; ++ c = h[2]; ++ d = h[3]; ++ ++ a2 = h[3]; ++ b2 = h[2]; ++ c2 = h[1]; ++ d2 = h[0]; ++ ++ for (i = 0; i < 4; i++) ++ { ++ for (j = 0; j < 16; j++) ++ { ++ tmp = j; ++ ++ for (k = 0; k < i; k++) ++ { ++ tmp = tIdxIncr[tmp]; ++ } ++ ++ g = 0x0F - tmp; ++ g2 = tmp; ++ ++ if (i == 0) f = (b & d) | (~d & c); ++ else if (i == 1) f = (~c | b) ^ d; ++ else if (i == 2) f = (~b & d) | (b & c); ++ else if (i == 3) f = (b ^ c ^ d); ++ ++ if (i == 0) f2 = (b2 ^ c2 ^ d2); ++ else if (i == 1) f2 = (~b2 & d2) | (b2 & c2); ++ else if (i == 2) f2 = (~c2 | b2) ^ d2; ++ else if (i == 3) f2 = (b2 & d2) | (~d2 & c2); ++ ++ f = dataLongs[g] + a + T[i] + f; ++ s = r[0x0F + (((i & 1) ^ 1) << 4) - j]; ++ f = (f << s) | (f >> (32 - s)); ++ ++ f2 = dataLongs[g2] + a2 + T2[i] + f2; ++ s2 = r[((i & 1) << 4) + j]; ++ f2 = (f2 << s2) | (f2 >> (32 - s2)); ++ ++ a = d; ++ d = (c << 10) | (c >> 22); ++ c = b; ++ b = f; ++ ++ a2 = d2; ++ d2 = (c2 << 10) | (c2 >> 22); ++ c2 = b2; ++ b2 = f2; ++ } ++ } ++ ++ result[0] = h[3] + b + a2; ++ result[1] = h[2] + c + b2; ++ result[2] = h[1] + d + c2; ++ result[3] = h[0] + a + d2; ++ ++ for (i = 0; i < 4; i++) ++ { ++ hash[4 * i + 0] = result[i] >> 0; ++ hash[4 * i + 1] = result[i] >> 8; ++ hash[4 * i + 2] = result[i] >> 16; ++ hash[4 * i + 3] = result[i] >> 24; ++ } ++} ++ ++uint8_t table04[] = { 0x02, 0x03, 0x07, 0x0B, 0x0D, 0x08, 0x00, 0x01, 0x2B, 0x2D, 0x28, 0x20, 0x21, 0x0A, 0x0C, 0x0E, ++ 0x22, 0x36, 0x23, 0x27, 0x29, 0x24, 0x25, 0x26, 0x2A, 0x3C, 0x3E, 0x3F, 0x0F, 0x2C, 0x2E, 0x2F, ++ 0x12, 0x13, 0x17, 0x1B, 0x1C, 0x18, 0x10, 0x11, 0x19, 0x14, 0x15, 0x16, 0x1A, 0x09, 0x04, 0x05, ++ 0x32, 0x33, 0x37, 0x3B, 0x06, 0x1C, 0x1E, 0x1F, 0x3D, 0x38, 0x30, 0x31, 0x39, 0x34, 0x35, 0x3A }; ++ ++uint8_t table05[] = { 0x08, 0x09, 0x0A, 0x03, 0x04, 0x3F, 0x27, 0x28, 0x29, 0x2A, 0x05, 0x0B, 0x1B, 0x1C, 0x1C, 0x1E, ++ 0x20, 0x0C, 0x0D, 0x22, 0x23, 0x24, 0x00, 0x01, 0x02, 0x06, 0x07, 0x25, 0x26, 0x0E, 0x0F, 0x21, ++ 0x10, 0x11, 0x12, 0x2E, 0x2F, 0x13, 0x14, 0x15, 0x2B, 0x2C, 0x2D, 0x16, 0x17, 0x18, 0x19, 0x1A, ++ 0x30, 0x31, 0x37, 0x3B, 0x3C, 0x3D, 0x3E, 0x1F, 0x38, 0x39, 0x32, 0x33, 0x34, 0x35, 0x36, 0x3A }; ++ ++uint8_t table06[] = { 0x00, 0x01, 0x02, 0x06, 0x07, 0x08, 0x03, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x04, 0x05, 0x09, 0x0D, ++ 0x20, 0x21, 0x22, 0x26, 0x27, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x10, 0x11, 0x12, 0x16, 0x17, 0x28, ++ 0x18, 0x13, 0x14, 0x15, 0x19, 0x1C, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x23, 0x24, 0x25, 0x29, 0x2D, ++ 0x30, 0x31, 0x32, 0x36, 0x37, 0x38, 0x33, 0x34, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x35, 0x39, 0x3D }; ++ ++uint8_t table07[] = { 0x10, 0x11, 0x12, 0x17, 0x1C, 0x1E, 0x0E, 0x38, 0x39, 0x3A, 0x13, 0x14, 0x29, 0x2A, 0x16, 0x1F, ++ 0x00, 0x01, 0x02, 0x3C, 0x3D, 0x3E, 0x3F, 0x07, 0x08, 0x09, 0x03, 0x04, 0x05, 0x06, 0x3B, 0x0A, ++ 0x20, 0x21, 0x22, 0x19, 0x1A, 0x1B, 0x1C, 0x0B, 0x0C, 0x15, 0x23, 0x24, 0x25, 0x26, 0x18, 0x0F, ++ 0x30, 0x31, 0x2B, 0x33, 0x34, 0x35, 0x36, 0x37, 0x27, 0x28, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, 0x0D }; ++ ++uint8_t table08[] = { 0x10, 0x11, 0x1E, 0x17, 0x18, 0x19, 0x12, 0x13, 0x14, 0x1C, 0x1C, 0x15, 0x0D, 0x05, 0x06, 0x0A, ++ 0x00, 0x01, 0x0E, 0x07, 0x08, 0x09, 0x02, 0x2D, 0x25, 0x26, 0x2A, 0x2B, 0x2F, 0x03, 0x04, 0x0C, ++ 0x20, 0x21, 0x2E, 0x27, 0x28, 0x29, 0x30, 0x31, 0x3E, 0x37, 0x38, 0x39, 0x22, 0x23, 0x24, 0x2C, ++ 0x32, 0x33, 0x34, 0x3C, 0x3D, 0x35, 0x36, 0x3A, 0x3B, 0x0B, 0x0F, 0x16, 0x1A, 0x1B, 0x1F, 0x3F }; ++ ++uint8_t table09[] = { 0x20, 0x21, 0x24, 0x22, 0x23, 0x2A, 0x2B, 0x33, 0x35, 0x38, 0x39, 0x36, 0x2D, 0x2C, 0x2E, 0x2F, ++ 0x00, 0x01, 0x04, 0x02, 0x25, 0x28, 0x08, 0x09, 0x06, 0x07, 0x0A, 0x0B, 0x0D, 0x0C, 0x0E, 0x0F, ++ 0x10, 0x11, 0x14, 0x12, 0x13, 0x15, 0x19, 0x16, 0x29, 0x26, 0x03, 0x17, 0x1A, 0x1C, 0x1C, 0x1E, ++ 0x30, 0x31, 0x34, 0x32, 0x37, 0x3A, 0x3B, 0x3D, 0x3C, 0x3E, 0x3F, 0x1B, 0x05, 0x18, 0x27, 0x1F }; ++ ++uint8_t table0A[] = { 0x00, 0x04, 0x05, 0x0B, 0x0C, 0x06, 0x09, 0x0A, 0x0E, 0x0D, 0x0F, 0x25, 0x15, 0x1B, 0x1C, 0x16, ++ 0x10, 0x11, 0x01, 0x02, 0x03, 0x07, 0x08, 0x12, 0x13, 0x17, 0x18, 0x14, 0x23, 0x27, 0x28, 0x24, ++ 0x30, 0x31, 0x32, 0x33, 0x37, 0x38, 0x34, 0x35, 0x3B, 0x3C, 0x20, 0x21, 0x22, 0x2B, 0x2C, 0x26, ++ 0x36, 0x39, 0x3A, 0x3E, 0x3D, 0x19, 0x1A, 0x1E, 0x1C, 0x1F, 0x3F, 0x29, 0x2A, 0x2E, 0x2D, 0x2F }; ++ ++static void PowervuHashModes04to0ATables(uint8_t *data, uint8_t *hash, uint8_t *table) ++{ ++ int i; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ hash[i] = table[i]; ++ hash[i] ^= data[table[i]]; ++ hash[i] ^= table[0x10 + i]; ++ hash[i] ^= data[table[0x10 + i]]; ++ hash[i] ^= table[0x20 + i]; ++ hash[i] ^= data[table[0x20 + i]]; ++ hash[i] ^= table[0x30 + i]; ++ hash[i] ^= data[table[0x30 + i]]; ++ } ++} ++ ++static void PowervuCreateHash(uint8_t *data, int len, uint8_t *hash, int mode) ++{ ++ uint8_t dataPadded[0x40]; ++ ++ PowervuPadData(data, len, dataPadded); ++ ++ switch(mode) ++ { ++ case 1: ++ PowervuHashMode01CustomMD5(dataPadded, hash); ++ break; ++ ++ case 2: ++ PowervuHashMode02(dataPadded, hash); ++ break; ++ ++ case 3: ++ PowervuHashMode03(dataPadded, hash); ++ break; ++ ++ case 4: ++ PowervuHashModes04to0ATables(dataPadded, hash, table04); ++ break; ++ ++ case 5: ++ PowervuHashModes04to0ATables(dataPadded, hash, table05); ++ break; ++ ++ case 6: ++ PowervuHashModes04to0ATables(dataPadded, hash, table06); ++ break; ++ ++ case 7: ++ PowervuHashModes04to0ATables(dataPadded, hash, table07); ++ break; ++ ++ case 8: ++ PowervuHashModes04to0ATables(dataPadded, hash, table08); ++ break; ++ ++ case 9: ++ PowervuHashModes04to0ATables(dataPadded, hash, table09); ++ break; ++ ++ case 10: ++ PowervuHashModes04to0ATables(dataPadded, hash, table0A); ++ break; ++ ++ default: ++ cs_log("A new hash mode [%d] is in use.", mode); ++ break; ++ } ++} ++ ++static void PowervuCreateDataEcmEmm(uint8_t *emmEcm, uint8_t *pos, int lenHeader, int len, uint8_t *data) ++{ ++ int i; ++ ++ for(i = 0; i < len; i++) ++ { ++ data[i] = emmEcm[lenHeader + pos[i]]; ++ } ++} ++ ++static uint8_t PowervuCreateDataCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, uint8_t *seedEcmCw, uint8_t *data) ++{ ++ int i; ++ ++ for(i = 0; i < lenSeed; i++) ++ { ++ data[i] = seed[i]; ++ } ++ ++ for(i = 0; i < 7; i++) ++ { ++ data[lenSeed + i] = baseCw[i]; ++ } ++ ++ data[lenSeed + 7] = val; ++ ++ for(i = 0; i < 16; i++) ++ { ++ data[lenSeed + 7 + 1 + i] = seedEcmCw[i]; ++ } ++ ++ return lenSeed + 7 + 1 + 0x10; ++} ++ ++static uint8_t PowervuUnmaskEcm(uint8_t *ecm, uint8_t *seedEcmCw) ++{ ++ int i, l; ++ ++ uint8_t sourcePos[] = {0x04, 0x05, 0x06, 0x07, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x17, 0x1C, 0x1D, 0x1F, 0x23, ++ 0x24, 0x25, 0x26, 0x27, 0x29, 0x2C, 0x2D, 0x2E}; ++ uint8_t destPos[] = {0x08, 0x09, 0x11, 0x18, 0x19, 0x1A, 0x1B, 0x1E, 0x20, 0x21, 0x22, 0x28, 0x2A, 0x2B, 0x2F, 0x30}; ++ uint8_t seedCwPos[] = {0x07, 0x0A, 0x04, 0x0D, 0x05, 0x0E, 0x06, 0x0B, 0x10, 0x0C, 0x0F}; ++ ++ uint8_t data[0x18]; ++ uint8_t mask[0x10]; ++ uint8_t hashModeEcm; ++ uint8_t hashModeCw; ++ uint32_t crc; ++ ++ // Create seed for CW decryption ++ memset(seedEcmCw, 0, 0x10); ++ ++ int extraBytesLen = ecm[9]; ++ int startOffset = extraBytesLen + 0x0A; ++ ++ for (i = 0; i < 0x0B; i++) ++ { ++ seedEcmCw[i] = ecm[startOffset + seedCwPos[i]]; ++ } ++ ++ // Read hash mode CW ++ hashModeCw = ecm[28 + extraBytesLen] ^ PowervuCrc8Calc(seedEcmCw, 0x10); ++ ++ // Create mask for ECM decryption ++ PowervuCreateDataEcmEmm(ecm, sourcePos, startOffset, 0x18, data); ++ ++ hashModeEcm = ecm[8] ^ PowervuCrc8Calc(data, 0x18); ++ ++ PowervuCreateHash(data, 0x18, mask, hashModeEcm); ++ ++ // Fix header ++ ecm[3] &= 0x0F; ++ ecm[3] |= 0x30; ++ ecm[8] = 0x00; ++ ecm[28 + extraBytesLen] = 0x00; ++ ++ // Unmask body ++ for (i = 0; i < 0x10; i++) ++ { ++ ecm[startOffset + destPos[i]] ^= mask[i & 0x0F]; ++ } ++ ++ // Fix CRC (optional) ++ l = (((ecm[1] << 8) + ecm[2]) & 0xFFF) + 3 - 4; ++ ++ crc = fletcher_crc32(ecm, l); ++ ++ ecm[l + 0] = crc >> 24; ++ ecm[l + 1] = crc >> 16; ++ ecm[l + 2] = crc >> 8; ++ ecm[l + 3] = crc >> 0; ++ ++ return hashModeCw; ++} ++ ++static void PowervuCreateCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, ++ uint8_t *seedEcmCw, uint8_t *cw, int modeDesCsa, int hashMode) ++{ ++ uint8_t tableFixParity[] = {0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E, ++ 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, ++ 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, ++ 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E, ++ 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, ++ 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, ++ 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E, ++ 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, ++ 0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, ++ 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E, ++ 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, ++ 0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, ++ 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, ++ 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, ++ 0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, ++ 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE}; ++ ++ uint8_t data[0x1C]; ++ uint8_t hash[0x10]; ++ uint8_t lenData; ++ int i; ++ ++ lenData = PowervuCreateDataCw(seed, lenSeed, baseCw, val, seedEcmCw, data); ++ PowervuCreateHash(data, lenData, hash, hashMode); ++ ++ for(i = 0; i < 8; i++) ++ { ++ cw[i] = hash[i]; ++ } ++ ++ if(modeDesCsa == 0) // DES - Fix Parity Bits ++ { ++ for(i = 0; i < 8; i++) ++ { ++ cw[i] = tableFixParity[cw[i]]; ++ } ++ } ++ else if(modeDesCsa == 1) // CSA - Fix Checksums ++ { ++ cw[3] = cw[0] + cw[1] + cw[2]; ++ cw[7] = cw[4] + cw[5] + cw[6]; ++ } ++} ++ ++static int8_t GetPowervuKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('P', ident, 0xFFFF0000, keyStr, buf, keyLength, isCriticalKey, keyRef, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int8_t GetPowervuEmmKey(uint8_t *buf, uint32_t ident, char *keyName, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef, uint32_t *getProvider) ++{ ++ if(FindKey('P', ident, 0xFFFFFFFF, keyName, buf, keyLength, isCriticalKey, keyRef, 0, getProvider)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static const uint8_t PowerVu_A0_S_1[16] = {0x33, 0xA4, 0x44, 0x3C, 0xCA, 0x2E, 0x75, 0x7B, 0xBC, 0xE6, 0xE5, 0x35, 0xA0, 0x55, 0xC9, 0xA2}; ++static const uint8_t PowerVu_A0_S_2[16] = {0x5A, 0xB0, 0x2C, 0xBC, 0xDA, 0x32, 0xE6, 0x92, 0x40, 0x53, 0x6E, 0xF9, 0x69, 0x11, 0x1E, 0xFB}; ++static const uint8_t PowerVu_A0_S_3[16] = {0x4E, 0x18, 0x9B, 0x19, 0x79, 0xFB, 0x01, 0xFA, 0xE3, 0xE1, 0x28, 0x3D, 0x32, 0xE4, 0x92, 0xEA}; ++static const uint8_t PowerVu_A0_S_4[16] = {0x05, 0x6F, 0x37, 0x66, 0x35, 0xE1, 0x58, 0xD0, 0xB4, 0x6A, 0x97, 0xAE, 0xD8, 0x91, 0x27, 0x56}; ++static const uint8_t PowerVu_A0_S_5[16] = {0x7B, 0x26, 0xAD, 0x34, 0x3D, 0x77, 0x39, 0x51, 0xE0, 0xE0, 0x48, 0x8C, 0x39, 0xF5, 0xE8, 0x47}; ++static const uint8_t PowerVu_A0_S_6[16] = {0x74, 0xFA, 0x4D, 0x79, 0x42, 0x39, 0xD1, 0xA4, 0x99, 0xA3, 0x97, 0x07, 0xDF, 0x14, 0x3A, 0xC4}; ++static const uint8_t PowerVu_A0_S_7[16] = {0xC6, 0x1E, 0x3C, 0x24, 0x11, 0x08, 0x5D, 0x6A, 0xEB, 0x97, 0xB9, 0x25, 0xA7, 0xFA, 0xE9, 0x1A}; ++static const uint8_t PowerVu_A0_S_8[16] = {0x9A, 0xAD, 0x72, 0xD7, 0x7C, 0x68, 0x3B, 0x55, 0x1D, 0x4A, 0xA2, 0xB0, 0x38, 0xB9, 0x56, 0xD0}; ++static const uint8_t PowerVu_A0_S_9[32] = {0x61, 0xDA, 0x5F, 0xB7, 0xEB, 0xC6, 0x3F, 0x6C, 0x09, 0xF3, 0x64, 0x38, 0x33, 0x08, 0xAA, 0x15, ++ 0xCC, 0xEF, 0x22, 0x64, 0x01, 0x2C, 0x12, 0xDE, 0xF4, 0x6E, 0x3C, 0xCD, 0x1A, 0x64, 0x63, 0x7C ++ }; ++ ++static const uint8_t PowerVu_00_S_1[16] = {0x97, 0x13, 0xEB, 0x6B, 0x04, 0x5E, 0x60, 0x3A, 0xD9, 0xCC, 0x91, 0xC2, 0x5A, 0xFD, 0xBA, 0x0C}; ++static const uint8_t PowerVu_00_S_2[16] = {0x61, 0x3C, 0x03, 0xB0, 0xB5, 0x6F, 0xF8, 0x01, 0xED, 0xE0, 0xE5, 0xF3, 0x78, 0x0F, 0x0A, 0x73}; ++static const uint8_t PowerVu_00_S_3[16] = {0xFD, 0xDF, 0xD2, 0x97, 0x06, 0x14, 0x91, 0xB5, 0x36, 0xAD, 0xBC, 0xE1, 0xB3, 0x00, 0x66, 0x41}; ++static const uint8_t PowerVu_00_S_4[16] = {0x8B, 0xD9, 0x18, 0x0A, 0xED, 0xEE, 0x61, 0x34, 0x1A, 0x79, 0x80, 0x8C, 0x1E, 0x7F, 0xC5, 0x9F}; ++static const uint8_t PowerVu_00_S_5[16] = {0xB0, 0xA1, 0xF2, 0xB8, 0xEA, 0x72, 0xDD, 0xD3, 0x30, 0x65, 0x2B, 0x1E, 0xE9, 0xE1, 0x45, 0x29}; ++static const uint8_t PowerVu_00_S_6[16] = {0x5D, 0xCA, 0x53, 0x75, 0xB2, 0x24, 0xCE, 0xAF, 0x21, 0x54, 0x9E, 0xBE, 0x02, 0xA9, 0x4C, 0x5D}; ++static const uint8_t PowerVu_00_S_7[16] = {0x42, 0x66, 0x72, 0x83, 0x1B, 0x2D, 0x22, 0xC9, 0xF8, 0x4D, 0xBA, 0xCD, 0xBB, 0x20, 0xBD, 0x6B}; ++static const uint8_t PowerVu_00_S_8[16] = {0xC4, 0x0C, 0x6B, 0xD3, 0x6D, 0x94, 0x7E, 0x53, 0xCE, 0x96, 0xAC, 0x40, 0x2C, 0x7A, 0xD3, 0xA9}; ++static const uint8_t PowerVu_00_S_9[32] = {0x31, 0x82, 0x4F, 0x9B, 0xCB, 0x6F, 0x9D, 0xB7, 0xAE, 0x68, 0x0B, 0xA0, 0x93, 0x15, 0x32, 0xE2, ++ 0xED, 0xE9, 0x47, 0x29, 0xC2, 0xA8, 0x92, 0xEF, 0xBA, 0x27, 0x22, 0x57, 0x76, 0x54, 0xC0, 0x59, ++ }; ++ ++static uint8_t PowervuSbox(uint8_t *input, uint8_t mode) ++{ ++ uint8_t s_index, bit, last_index, last_bit; ++ uint8_t const *Sbox1, *Sbox2, *Sbox3, *Sbox4, *Sbox5, *Sbox6, *Sbox7, *Sbox8, *Sbox9; ++ ++ if(mode) ++ { ++ Sbox1 = PowerVu_A0_S_1; ++ Sbox2 = PowerVu_A0_S_2; ++ Sbox3 = PowerVu_A0_S_3; ++ Sbox4 = PowerVu_A0_S_4; ++ Sbox5 = PowerVu_A0_S_5; ++ Sbox6 = PowerVu_A0_S_6; ++ Sbox7 = PowerVu_A0_S_7; ++ Sbox8 = PowerVu_A0_S_8; ++ Sbox9 = PowerVu_A0_S_9; ++ } ++ else ++ { ++ Sbox1 = PowerVu_00_S_1; ++ Sbox2 = PowerVu_00_S_2; ++ Sbox3 = PowerVu_00_S_3; ++ Sbox4 = PowerVu_00_S_4; ++ Sbox5 = PowerVu_00_S_5; ++ Sbox6 = PowerVu_00_S_6; ++ Sbox7 = PowerVu_00_S_7; ++ Sbox8 = PowerVu_00_S_8; ++ Sbox9 = PowerVu_00_S_9; ++ } ++ ++ bit = (GetBit(input[2],0)<<2) | (GetBit(input[3],4)<<1) | (GetBit(input[5],3)); ++ s_index = (GetBit(input[0],0)<<3) | (GetBit(input[2],6)<<2) | (GetBit(input[2],4)<<1) | (GetBit(input[5],7)); ++ last_bit = GetBit(Sbox1[s_index],7-bit); ++ ++ bit = (GetBit(input[5],0)<<2) | (GetBit(input[4],0)<<1) | (GetBit(input[6],2)); ++ s_index = (GetBit(input[2],1)<<3) | (GetBit(input[2],2)<<2) | (GetBit(input[5],5)<<1) | (GetBit(input[5],1)); ++ last_bit = last_bit | (GetBit(Sbox2[s_index],7-bit)<<1); ++ ++ bit = (GetBit(input[6],0)<<2) | (GetBit(input[1],7)<<1) | (GetBit(input[6],7)); ++ s_index = (GetBit(input[1],3)<<3) | (GetBit(input[3],7)<<2) | (GetBit(input[1],5)<<1) | (GetBit(input[5],2)); ++ last_bit = last_bit | (GetBit(Sbox3[s_index], 7-bit)<<2); ++ ++ bit = (GetBit(input[1],0)<<2) | (GetBit(input[2],7)<<1) | (GetBit(input[2],5)); ++ s_index = (GetBit(input[6],3)<<3) | (GetBit(input[6],4)<<2) | (GetBit(input[6],6)<<1) | (GetBit(input[3],5)); ++ last_index = GetBit(Sbox4[s_index], 7-bit); ++ ++ bit = (GetBit(input[3],3)<<2) | (GetBit(input[4],6)<<1) | (GetBit(input[3],2)); ++ s_index = (GetBit(input[3],1)<<3) | (GetBit(input[4],5)<<2) | (GetBit(input[3],0)<<1) | (GetBit(input[4],7)); ++ last_index = last_index | (GetBit(Sbox5[s_index], 7-bit)<<1); ++ ++ bit = (GetBit(input[5],4)<<2) | (GetBit(input[4],4)<<1) | (GetBit(input[1],2)); ++ s_index = (GetBit(input[2],3)<<3) | (GetBit(input[6],5)<<2) | (GetBit(input[1],4)<<1) | (GetBit(input[4],1)); ++ last_index = last_index | (GetBit(Sbox6[s_index], 7-bit)<<2); ++ ++ bit = (GetBit(input[0],6)<<2) | (GetBit(input[0],7)<<1) | (GetBit(input[0],4)); ++ s_index = (GetBit(input[0],5)<<3) | (GetBit(input[0],3)<<2) | (GetBit(input[0],1)<<1) | (GetBit(input[0],2)); ++ last_index = last_index | (GetBit(Sbox7[s_index], 7-bit)<<3); ++ ++ bit = (GetBit(input[4],2)<<2) | (GetBit(input[4],3)<<1) | (GetBit(input[1],1)); ++ s_index = (GetBit(input[1],6)<<3) | (GetBit(input[6],1)<<2) | (GetBit(input[5],6)<<1) | (GetBit(input[3],6)); ++ last_index = last_index | (GetBit(Sbox8[s_index], 7-bit)<<4); ++ ++ return (GetBit(Sbox9[last_index&0x1f],7-last_bit)&1) ? 1: 0; ++} ++ ++static void PowervuDecrypt(uint8_t *data, uint32_t length, uint8_t *key, uint8_t sbox) ++{ ++ uint32_t i; ++ int32_t j, k; ++ uint8_t curByte, tmpBit; ++ ++ for(i = 0; i < length; i++) ++ { ++ curByte = data[i]; ++ ++ for(j = 7; j >= 0; j--) ++ { ++ data[i] = SetBit(data[i], j, (GetBit(curByte, j)^PowervuSbox(key, sbox))^GetBit(key[0], 7)); ++ ++ tmpBit = GetBit(data[i], j)^(GetBit(key[6], 0)); ++ if (tmpBit) ++ { ++ key[3] ^= 0x10; ++ } ++ ++ for (k = 6; k > 0; k--) ++ { ++ key[k] = (key[k]>>1) | (key[k-1]<<7); ++ } ++ key[0] = (key[0]>>1); ++ ++ key[0] = SetBit(key[0], 7, tmpBit); ++ } ++ } ++} ++ ++#define PVU_CW_VID 0 // VIDeo ++#define PVU_CW_HSD 1 // High Speed Data ++#define PVU_CW_A1 2 // Audio 1 ++#define PVU_CW_A2 3 // Audio 2 ++#define PVU_CW_A3 4 // Audio 3 ++#define PVU_CW_A4 5 // Audio 4 ++#define PVU_CW_UTL 6 // UTiLity ++#define PVU_CW_VBI 7 // Vertical Blanking Interval ++ ++#define PVU_CONVCW_VID_ECM 0x80 // VIDeo ++#define PVU_CONVCW_HSD_ECM 0x40 // High Speed Data ++#define PVU_CONVCW_A1_ECM 0x20 // Audio 1 ++#define PVU_CONVCW_A2_ECM 0x10 // Audio 2 ++#define PVU_CONVCW_A3_ECM 0x08 // Audio 3 ++#define PVU_CONVCW_A4_ECM 0x04 // Audio 4 ++#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity ++#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval ++ ++static uint8_t PowervuGetConvcwIndex(uint8_t ecmTag) ++{ ++ switch(ecmTag) ++ { ++ case PVU_CONVCW_VID_ECM: ++ return PVU_CW_VID; ++ ++ case PVU_CONVCW_HSD_ECM: ++ return PVU_CW_HSD; ++ ++ case PVU_CONVCW_A1_ECM: ++ return PVU_CW_A1; ++ ++ case PVU_CONVCW_A2_ECM: ++ return PVU_CW_A2; ++ ++ case PVU_CONVCW_A3_ECM: ++ return PVU_CW_A3; ++ ++ case PVU_CONVCW_A4_ECM: ++ return PVU_CW_A4; ++ ++ case PVU_CONVCW_UTL_ECM: ++ return PVU_CW_UTL; ++ ++ case PVU_CONVCW_VBI_ECM: ++ return PVU_CW_VBI; ++ ++ default: ++ return PVU_CW_VBI; ++ } ++} ++ ++static uint16_t PowervuGetSeedIV(uint8_t seedType, uint8_t *ecm) ++{ ++ switch(seedType) ++ { ++ case PVU_CW_VID: ++ return ((ecm[0x10] & 0x1F) <<3) | 0; ++ case PVU_CW_HSD: ++ return ((ecm[0x12] & 0x1F) <<3) | 2; ++ case PVU_CW_A1: ++ return ((ecm[0x11] & 0x3F) <<3) | 1; ++ case PVU_CW_A2: ++ return ((ecm[0x13] & 0x3F) <<3) | 1; ++ case PVU_CW_A3: ++ return ((ecm[0x19] & 0x3F) <<3) | 1; ++ case PVU_CW_A4: ++ return ((ecm[0x1A] & 0x3F) <<3) | 1;; ++ case PVU_CW_UTL: ++ return ((ecm[0x14] & 0x0F) <<3) | 4; ++ case PVU_CW_VBI: ++ return (((ecm[0x15] & 0xF8)>>3)<<3) | 5; ++ default: ++ return 0; ++ } ++} ++ ++static uint8_t PowervuExpandSeed(uint8_t seedType, uint8_t *seed) ++{ ++ uint8_t seedLength = 0, i; ++ ++ switch(seedType) ++ { ++ case PVU_CW_VID: ++ case PVU_CW_HSD: ++ seedLength = 4; ++ break; ++ case PVU_CW_A1: ++ case PVU_CW_A2: ++ case PVU_CW_A3: ++ case PVU_CW_A4: ++ seedLength = 3; ++ break; ++ case PVU_CW_UTL: ++ case PVU_CW_VBI: ++ seedLength = 2; ++ break; ++ default: ++ return seedLength; ++ } ++ ++ for(i=seedLength; i<7; i++) ++ { ++ seed[i] = seed[i%seedLength]; ++ } ++ ++ return seedLength; ++} ++ ++static void PowervuCalculateSeed(uint8_t seedType, uint8_t *ecm, uint8_t *seedBase, uint8_t *key, uint8_t *seed, uint8_t sbox) ++{ ++ uint16_t tmpSeed; ++ ++ tmpSeed = PowervuGetSeedIV(seedType, ecm+23); ++ seed[0] = (tmpSeed >> 2) & 0xFF; ++ seed[1] = ((tmpSeed & 0x3) << 6) | (seedBase[0] >> 2); ++ seed[2] = ( seedBase[0] << 6) | (seedBase[1] >> 2); ++ seed[3] = ( seedBase[1] << 6) | (seedBase[2] >> 2); ++ seed[4] = ( seedBase[2] << 6) | (seedBase[3] >> 2); ++ seed[5] = ( seedBase[3] << 6); ++ ++ PowervuDecrypt(seed, 6, key, sbox); ++ ++ seed[0] = (seed[1] << 2) | (seed[2] >> 6); ++ seed[1] = (seed[2] << 2) | (seed[3] >> 6); ++ seed[2] = (seed[3] << 2) | (seed[4] >> 6); ++ seed[3] = (seed[4] << 2) | (seed[5] >> 6); ++} ++ ++static void PowervuCalculateCw(uint8_t seedType, uint8_t *seed, uint8_t csaUsed, uint8_t *convolvedCw, ++ uint8_t *cw, uint8_t *baseCw, uint8_t *seedEcmCw, uint8_t hashModeCw, ++ uint8_t needsUnmasking, uint8_t xorMode) ++{ ++ int32_t k; ++ uint8_t seedLength, val = 0; ++ ++ seedLength = PowervuExpandSeed(seedType, seed); ++ ++ if(csaUsed) ++ { ++ if(!needsUnmasking || (hashModeCw == 0)) ++ { ++ for(k = 0; k < 7; k++) ++ { ++ seed[k] ^= baseCw[k]; ++ } ++ ++ cw[0] = seed[0] ^ convolvedCw[0]; ++ cw[1] = seed[1] ^ convolvedCw[1]; ++ cw[2] = seed[2] ^ convolvedCw[2]; ++ cw[3] = seed[3] ^ convolvedCw[3]; ++ cw[4] = seed[3] ^ convolvedCw[4]; ++ cw[5] = seed[4] ^ convolvedCw[5]; ++ cw[6] = seed[5] ^ convolvedCw[6]; ++ cw[7] = seed[6] ^ convolvedCw[7]; ++ } ++ } ++ else ++ { ++ if(xorMode == 0) ++ { ++ for(k = 0; k < 7; k++) ++ { ++ cw[k] = seed[k] ^ baseCw[k]; ++ } ++ } ++ ++ if(xorMode == 1) ++ { ++ for(k = 0; k < 3; k++) ++ { ++ cw[k] = seed[k] ^ baseCw[k]; ++ } ++ ++ for(k = 3; k < 7; k++) ++ { ++ cw[k] = baseCw[k]; ++ } ++ } ++ ++ ExpandDesKey(cw); ++ } ++ ++ if(needsUnmasking && (hashModeCw > 0)) ++ { ++ switch(seedType) ++ { ++ case PVU_CW_VID: ++ val = 0; ++ break; ++ ++ case PVU_CW_A1: ++ case PVU_CW_A2: ++ case PVU_CW_A3: ++ case PVU_CW_A4: ++ val = 1; ++ break; ++ ++ case PVU_CW_HSD: ++ val = 2; ++ break; ++ ++ case PVU_CW_UTL: ++ val = 4; ++ break; ++ ++ case PVU_CW_VBI: ++ val = 5; ++ break; ++ } ++ PowervuCreateCw(seed, seedLength, baseCw, val, seedEcmCw, cw, csaUsed, hashModeCw); ++ } ++} ++ ++#ifdef WITH_EMU ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex) ++#else ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata) ++#endif ++{ ++ int8_t ret = 1; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ uint32_t ecmCrc32; ++ uint8_t nanoCmd, nanoChecksum, keyType, fixedKey, oddKey, bid, csaUsed; ++ uint16_t nanoLen; ++ uint32_t channelId, ecmSrvid, keyIndex; ++ uint32_t i, j, k; ++ uint8_t convolvedCw[8][8]; ++ uint8_t ecmKey[7], tmpEcmKey[7], seedBase[4], baseCw[7], seed[8][8], cw[8][8]; ++ uint8_t decrypt_ok; ++ uint8_t ecmPart1[14], ecmPart2[27]; ++ uint8_t sbox; ++ uint32_t keyRef1, keyRef2; ++ uint8_t calculateAllCws; ++ uint8_t seedEcmCw[0x10]; ++ uint8_t hashModeCw = 0, needsUnmasking, xorMode; ++#ifdef WITH_EMU ++ uint8_t *dwp; ++ emu_stream_cw_item *cw_item; ++ int8_t update_global_key = 0; ++ int8_t update_global_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++ ++ memset(update_global_keys, 0, sizeof(update_global_keys)); ++#endif ++ ++ if(ecmLen < 7) ++ { ++ return 1; ++ } ++ ++ needsUnmasking = (ecm[3] & 0xF0) == 0x50; ++ ++ if(needsUnmasking) ++ { ++ hashModeCw = PowervuUnmaskEcm(ecm, seedEcmCw); ++ } ++ ++ ecmCrc32 = b2i(4, ecm+ecmLen-4); ++ ++ if(fletcher_crc32(ecm, ecmLen-4) != ecmCrc32) ++ { ++ return 8; ++ } ++ ecmLen -= 4; ++ ++ for(i = 0; i < 8; i++) { ++ memset(convolvedCw[i], 0, 8); ++ } ++ ++ for(i = 3; i+3 < ecmLen; ) { ++ nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); ++ i += 2; ++ if(nanoLen > 0) ++ { ++ nanoLen--; ++ } ++ nanoCmd = ecm[i++]; ++ if(i+nanoLen > ecmLen) { ++ return 1; ++ } ++ ++ switch (nanoCmd) { ++ case 0x27: ++ if(nanoLen < 15) ++ { ++ break; ++ } ++ ++ nanoChecksum = 0; ++ for(j = 4; j < 15; j++) ++ { ++ nanoChecksum += ecm[i+j]; ++ } ++ ++ if(nanoChecksum != 0) ++ { ++ break; ++ } ++ ++ keyType = PowervuGetConvcwIndex(ecm[i+4]); ++ memcpy(convolvedCw[keyType], &ecm[i+6], 8); ++ break; ++ ++ default: ++ break; ++ } ++ i += nanoLen; ++ } ++ ++ for(i = 3; i+3 < ecmLen; ) { ++ nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); ++ i += 2; ++ if(nanoLen > 0) ++ { ++ nanoLen--; ++ } ++ nanoCmd = ecm[i++]; ++ if(i+nanoLen > ecmLen) { ++ return 1; ++ } ++ ++ switch (nanoCmd) { ++ case 0x20: ++ if(nanoLen < 54) ++ { ++ break; ++ } ++ ++ i += ecm[i + 3]; // Extra Data Length ++ ++ csaUsed = GetBit(ecm[i+7], 7); ++ fixedKey = !GetBit(ecm[i+6], 5); ++ oddKey = GetBit(ecm[i+6], 4); ++ xorMode = GetBit(ecm[i+6], 0); ++ bid = (GetBit(ecm[i+7], 1) << 1) | GetBit(ecm[i+7], 0); ++ sbox = GetBit(ecm[i+6], 3); ++ ++ keyIndex = (fixedKey << 3) | (bid << 2) | oddKey; ++ channelId = b2i(2, ecm+i+23); ++ ecmSrvid = (channelId >> 4) | ((channelId & 0xF) << 12); ++ ++ decrypt_ok = 0; ++ ++ memcpy(ecmPart1, ecm+i+8, 14); ++ memcpy(ecmPart2, ecm+i+27, 27); ++ ++ keyRef1 = 0; ++ keyRef2 = 0; ++ ++ do ++ { ++ if(!GetPowervuKey(ecmKey, ecmSrvid, '0', keyIndex, 7, 0, keyRef1++)) ++ { ++ if(!GetPowervuKey(ecmKey, channelId, '0', keyIndex, 7, 0, keyRef2++)) ++ { ++ cs_log("Key not found: P %04X 0%X", ecmSrvid, keyIndex); ++ return 2; ++ } ++ } ++ ++ PowervuDecrypt(ecm+i+8, 14, ecmKey, sbox); ++ if((ecm[i+6] != ecm[i+6+7]) || (ecm[i+6+8] != ecm[i+6+15])) ++ { ++ memcpy(ecm+i+8, ecmPart1, 14); ++ continue; ++ } ++ ++ memcpy(tmpEcmKey, ecmKey, 7); ++ ++ PowervuDecrypt(ecm+i+27, 27, ecmKey, sbox); ++ if((ecm[i+23] != ecm[i+23+29]) || (ecm[i+23+1] != ecm[i+23+30])) ++ { ++ memcpy(ecm+i+8, ecmPart1, 14); ++ memcpy(ecm+i+27, ecmPart2, 27); ++ continue; ++ } ++ ++ decrypt_ok = 1; ++ } ++ while(!decrypt_ok); ++ ++ memcpy(seedBase, ecm+i+6+2, 4); ++ ++#ifdef WITH_EMU ++ if(cdata == NULL) ++ { ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) ++ { ++ if(!stream_server_has_ecm[j] && emu_stream_cur_srvid[j] == srvid) ++ { ++ update_global_key = 1; ++ update_global_keys[j] = 1; ++ } ++ } ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); ++ } ++ ++ if(cdata != NULL || update_global_key || cw_ex != NULL) ++#else ++ if(cdata != NULL) ++#endif ++ { ++ // Calculate all seeds ++ for(j = 0; j < 8; j++) ++ { ++ memcpy(ecmKey, tmpEcmKey, 7); ++ PowervuCalculateSeed(j, ecm+i, seedBase, ecmKey, seed[j], sbox); ++ } ++ } ++ else ++ { ++ // Calculate only video seed ++ memcpy(ecmKey, tmpEcmKey, 7); ++ PowervuCalculateSeed(PVU_CW_VID, ecm+i, seedBase, ecmKey, seed[PVU_CW_VID], sbox); ++ } ++ ++ memcpy(baseCw, ecm+i+6+8, 7); ++ ++#ifdef WITH_EMU ++ calculateAllCws = cdata != NULL || update_global_key || cw_ex != NULL; ++#else ++ calculateAllCws = cdata != NULL; ++#endif ++ if(calculateAllCws) ++ { ++ // Calculate all cws ++ for(j = 0; j < 8; j++) ++ { ++ PowervuCalculateCw(j, seed[j], csaUsed, convolvedCw[j], cw[j], baseCw, ++ seedEcmCw, hashModeCw, needsUnmasking, xorMode); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) { ++ cw[j][k + 3] = ((cw[j][k] + cw[j][k + 1] + cw[j][k + 2]) & 0xff); ++ } ++ } ++ } ++ ++#ifdef WITH_EMU ++ if(update_global_key) ++ { ++ for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) ++ { ++ if(update_global_keys[j]) ++ { ++ cw_item = (emu_stream_cw_item*)malloc(sizeof(emu_stream_cw_item)); ++ if(cw_item != NULL) ++ { ++ cw_item->csa_used = csaUsed; ++ cw_item->is_even = ecm[0] == 0x80 ? 1 : 0; ++ cs_ftime(&cw_item->write_time); ++ add_ms_to_timeb(&cw_item->write_time, cfg.emu_stream_ecm_delay); ++ memcpy(cw_item->cw, cw, sizeof(cw)); ++ ll_append(ll_emu_stream_delayed_keys[j], cw_item); ++ } ++ } ++ } ++ } ++ ++ if(cdata != NULL) ++ { ++#endif ++ for(j = 0; j < 8; j++) ++ { ++ if(csaUsed) ++ { ++ if(cdata->pvu_csa_ks[j] == NULL) ++ { cdata->pvu_csa_ks[j] = get_key_struct(); } ++ ++ if(ecm[0] == 0x80) ++ { set_even_control_word(cdata->pvu_csa_ks[j], cw[j]); } ++ else ++ { set_odd_control_word(cdata->pvu_csa_ks[j], cw[j]); } ++ ++ cdata->pvu_csa_used = 1; ++ } ++ else ++ { ++ if(ecm[0] == 0x80) ++ { des_set_key(cw[j], cdata->pvu_des_ks[j][0]); } ++ else ++ { des_set_key(cw[j], cdata->pvu_des_ks[j][1]); } ++ ++ cdata->pvu_csa_used = 0; ++ } ++ } ++#ifdef WITH_EMU ++ } ++ ++ if(cw_ex != NULL) ++ { ++ cw_ex->mode = CW_MODE_MULTIPLE_CW; ++ ++ if(csaUsed) ++ { ++ cw_ex->algo = CW_ALGO_CSA; ++ cw_ex->algo_mode = CW_ALGO_MODE_ECB; ++ } ++ else ++ { ++ cw_ex->algo = CW_ALGO_DES; ++ cw_ex->algo_mode = CW_ALGO_MODE_ECB; ++ } ++ ++ for(j = 0; j < 4; j++) ++ { ++ dwp = cw_ex->audio[j]; ++ ++ memset(dwp, 0, 16); ++ ++ if(ecm[0] == 0x80) ++ { ++ memcpy(dwp, cw[PVU_CW_A1+j], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ else ++ { ++ memcpy(&dwp[8], cw[PVU_CW_A1+j], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 8; k < 16; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ } ++ ++ dwp = cw_ex->data; ++ ++ memset(dwp, 0, 16); ++ ++ if(ecm[0] == 0x80) ++ { ++ memcpy(dwp, cw[PVU_CW_HSD], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ else ++ { ++ memcpy(&dwp[8], cw[PVU_CW_HSD], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 8; k < 16; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ } ++#endif ++ } ++ else ++ { ++ // Calculate only video cw ++ PowervuCalculateCw(PVU_CW_VID, seed[PVU_CW_VID], csaUsed, convolvedCw[PVU_CW_VID], cw[PVU_CW_VID], baseCw, ++ seedEcmCw, hashModeCw, needsUnmasking, xorMode); ++ } ++ ++ memset(dw, 0, 16); ++ ++ if(ecm[0] == 0x80) ++ { ++ memcpy(dw, cw[PVU_CW_VID], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) ++ { ++ dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); ++ } ++ } ++ } ++ else ++ { ++ memcpy(&dw[8], cw[PVU_CW_VID], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 8; k < 16; k += 4) ++ { ++ dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); ++ } ++ } ++ } ++ ++ return 0; ++ ++ default: ++ break; ++ } ++ i += nanoLen; ++ } ++ ++ return ret; ++} ++ ++ ++// Drecrypt EMU ++static void DREover(const uint8_t *ECMdata, uint8_t *dw) ++{ ++ uint8_t key[8]; ++ uint32_t key_schedule[32]; ++ ++ if (ECMdata[2] >= (43 + 4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B) ++ { ++ if (!FindKey('D', ECMdata[42] & 0x0F, 0, "OVER", key, 8, 1, 0, 0, NULL)) ++ { ++ return; ++ } ++ ++ des_set_key(key, key_schedule); ++ ++ des(dw, key_schedule, 0); // even dw post-process ++ des(dw + 8, key_schedule, 0); // odd dw post-process ++ } ++} ++ ++static uint32_t DreGostDec(uint32_t inData) ++{ ++ static uint8_t Sbox[128] = ++ { ++ 0x0E,0x04,0x0D,0x01,0x02,0x0F,0x0B,0x08,0x03,0x0A,0x06,0x0C,0x05,0x09,0x00,0x07, ++ 0x0F,0x01,0x08,0x0E,0x06,0x0B,0x03,0x04,0x09,0x07,0x02,0x0D,0x0C,0x00,0x05,0x0A, ++ 0x0A,0x00,0x09,0x0E,0x06,0x03,0x0F,0x05,0x01,0x0D,0x0C,0x07,0x0B,0x04,0x02,0x08, ++ 0x07,0x0D,0x0E,0x03,0x00,0x06,0x09,0x0A,0x01,0x02,0x08,0x05,0x0B,0x0C,0x04,0x0F, ++ 0x02,0x0C,0x04,0x01,0x07,0x0A,0x0B,0x06,0x08,0x05,0x03,0x0F,0x0D,0x00,0x0E,0x09, ++ 0x0C,0x01,0x0A,0x0F,0x09,0x02,0x06,0x08,0x00,0x0D,0x03,0x04,0x0E,0x07,0x05,0x0B, ++ 0x04,0x0B,0x02,0x0E,0x0F,0x00,0x08,0x0D,0x03,0x0C,0x09,0x07,0x05,0x0A,0x06,0x01, ++ 0x0D,0x02,0x08,0x04,0x06,0x0F,0x0B,0x01,0x0A,0x09,0x03,0x0E,0x05,0x00,0x0C,0x07 ++ }; ++ uint8_t i, j; ++ ++ for(i = 0; i < 8; i++) ++ { ++ j = (inData >> 28) & 0x0F; ++ inData = (inData << 4) | (Sbox[i * 16 + j] & 0x0F); ++ } ++ ++ inData = (inData << 11) | (inData >> 21); ++ ++ return (inData); ++} ++ ++static void DrecryptDecrypt(uint8_t *Data, uint8_t *Key) // DRE GOST 28147-89 CORE ++{ ++ int i, j; ++ uint32_t L_part = 0, R_part = 0, temp = 0; ++ ++ for(i = 0; i < 4; i++) L_part = (L_part << 8) | (Data[i] & 0xFF), R_part = (R_part << 8) | (Data[i + 4] & 0xFF); ++ ++ for(i = 0; i < 4; i++) ++ { ++ temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); ++ R_part ^= DreGostDec(temp + L_part); ++ temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); ++ L_part ^= DreGostDec(temp + R_part); ++ } ++ ++ for(j = 0; j < 3; j++) ++ { ++ for(i = 3; i >= 0; i--) ++ { ++ temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); ++ R_part ^= DreGostDec(temp + L_part); ++ temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); ++ L_part ^= DreGostDec(temp + R_part); ++ } ++ } ++ ++ for(i = 0; i < 4; i++) Data[i] = (R_part >> i*8) & 0xFF, Data[i+4] = (L_part >> i*8) & 0xFF; ++} ++ ++static void DrecryptPostCw(uint8_t* ccw) ++{ ++ uint32_t i, j; ++ uint8_t tmp[4]; ++ ++ for(i = 0; i < 4; i++) ++ { ++ for(j = 0; j < 4; j++) ++ { ++ tmp[j] = ccw[3 - j]; ++ } ++ ++ for(j = 0; j < 4; j++) ++ { ++ ccw[j] = tmp[j]; ++ } ++ ++ ccw += 4; ++ } ++} ++ ++static void DrecryptSwap(uint8_t* ccw) ++{ ++ uint32_t tmp1, tmp2; ++ ++ memcpy(&tmp1, ccw, 4); ++ memcpy(&tmp2, ccw + 4, 4); ++ ++ memcpy(ccw, ccw + 8, 8); ++ ++ memcpy(ccw + 8 , &tmp1, 4); ++ memcpy(ccw + 8 + 4, &tmp2, 4); ++} ++ ++static int8_t Drecrypt2ECM(uint32_t provId, uint8_t *ecm, uint8_t *dw) ++{ ++ uint8_t ecmDataLen, ccw[16], key[32]; ++ uint16_t ecmLen, overcryptId; ++ char keyName[EMU_MAX_CHAR_KEYNAME]; ++ ++ ecmLen = GetEcmLen(ecm); ++ ++ if (ecmLen < 3) ++ { ++ return 1; // Not supported ++ } ++ ++ ecmDataLen = ecm[2]; ++ ++ if (ecmLen < ecmDataLen + 3) ++ { ++ return 4; // Corrupt data ++ } ++ ++ switch (provId & 0xFF) ++ { ++ case 0x11: ++ { ++ if (ecm[3] == 0x56) ++ { ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); ++ ++ if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) ++ { ++ return 2; ++ } ++ } ++ else ++ { ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[3]); ++ ++ if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) ++ { ++ return 2; ++ } ++ } ++ ++ break; ++ } ++ ++ case 0x14: ++ { ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); ++ ++ if (!FindKey('D', 0x4AE114, 0, keyName, key, 32, 1, 0, 0, NULL)) ++ { ++ return 2; ++ } ++ ++ break; ++ } ++ ++ default: ++ return 1; ++ } ++ ++ memcpy(ccw, ecm + 13, 16); ++ ++ DrecryptPostCw(key); ++ DrecryptPostCw(key + 16); ++ ++ DrecryptDecrypt(ccw, key); ++ DrecryptDecrypt(ccw + 8, key); ++ ++ if (ecm[2] >= 46 && ecm[43] == 1 && provId == 0x11) ++ { ++ DrecryptSwap(ccw); ++ overcryptId = b2i(2, &ecm[44]); ++ ++ Drecrypt2OverCW(overcryptId, ccw); ++ ++ if (isValidDCW(ccw)) ++ { ++ memcpy(dw, ccw, 16); ++ return 0; ++ } ++ ++ return 9; // ICG error ++ } ++ ++ DREover(ecm, ccw); ++ ++ if (isValidDCW(ccw)) ++ { ++ DrecryptSwap(ccw); ++ memcpy(dw, ccw, 16); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++// Tandberg EMU ++static uint16_t TandbergChecksum(uint8_t *data, uint8_t length) ++{ ++ // ECM and EMM checksum calculation ++ // 1. Combine data in 2 byte groups ++ // 2. Add them together ++ // 3. Multiply result by itself (power of 7) ++ // 4. XOR with fixed value 0x17E3 ++ ++ uint8_t i; ++ uint16_t checksum = 0; ++ ++ for(i = 0; i < length; i += 2) ++ { ++ checksum += (data[i] << 8) | data[i + 1]; ++ } ++ ++ checksum = checksum * checksum * checksum * checksum * checksum * checksum * checksum; ++ checksum ^= 0x17E3; ++ ++ return checksum; ++} ++ ++static int8_t GetTandbergKey(uint32_t keyIndex, char *keyName, uint8_t *key, uint32_t keyLength) ++{ ++ // keyIndex: ecm keys --> entitlementId ++ // emm keys --> aeskeyIndex ++ // aes keys --> keyIndex ++ ++ // keyName: ecm keys --> "01" ++ // emm keys --> "MK" or "MK01" ++ // aes keys --> "AES" ++ ++ return FindKey('T', keyIndex, 0, keyName, key, keyLength, 1, 0, 0, NULL); ++} ++ ++static int8_t TandbergECM(uint8_t *ecm, uint8_t *dw) ++{ ++ uint8_t nanoType, nanoLength; ++ uint8_t* nanoData; ++ uint32_t pos = 3; ++ uint32_t entitlementId; ++ uint32_t ks[32]; ++ uint8_t ecmKey[8]; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 5) ++ { ++ return 1; ++ } ++ ++ do ++ { ++ nanoType = ecm[pos]; ++ nanoLength = ecm[pos+1]; ++ ++ if(pos + 2 + nanoLength > ecmLen) ++ { ++ break; ++ } ++ ++ nanoData = ecm + pos + 2; ++ ++ // ECM validation ++ uint16_t payloadChecksum = (nanoData[nanoLength - 2] << 8) | nanoData[nanoLength - 1]; ++ uint16_t calculatedChecksum = TandbergChecksum(nanoData, nanoLength - 2); ++ ++ if(calculatedChecksum != payloadChecksum) ++ { ++ cs_log("ECM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); ++ return 8; ++ } ++ // End of ECM validation ++ ++ switch(nanoType) ++ { ++ case 0xEC: // Director v6 (September 2017) ++ { ++ if(nanoLength != 0x28) ++ { ++ cs_log("WARNING: nanoType EC length (%d) != %d", nanoLength, 0x28); ++ break; ++ } ++ ++ entitlementId = b2i(4, nanoData); ++ ++ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) ++ { ++ return 2; ++ } ++ ++ cs_log("Active entitlement %.4X", entitlementId); ++ ++ // Step 1 - Decrypt DES CBC with ecmKey and iv = { 0 } (equal to nanoED) ++ uint8_t encryptedData[32] = { 0 }; ++ memcpy(encryptedData, nanoData + 6, 32); ++ ++ uint8_t iv[8] = { 0 }; ++ des_cbc_decrypt(encryptedData, iv, ecmKey, 32); ++ ++ uint8_t nanoMode = nanoData[5]; ++ ++ if ((nanoMode & 0x20) == 0) // Old algo ++ { ++ // Step 2 - Create CW (equal to nano ED) ++ dw[0] = encryptedData[0x05]; ++ dw[1] = encryptedData[0x19]; ++ dw[2] = encryptedData[0x1D]; ++ ++ dw[4] = encryptedData[0x0B]; ++ dw[5] = encryptedData[0x12]; ++ dw[6] = encryptedData[0x1A]; ++ ++ dw[8] = encryptedData[0x16]; ++ dw[9] = encryptedData[0x03]; ++ dw[10] = encryptedData[0x11]; ++ ++ dw[12] = encryptedData[0x18]; ++ dw[13] = encryptedData[0x10]; ++ dw[14] = encryptedData[0x0E]; ++ ++ return 0; ++ } ++ else // New algo (overencryption with AES) ++ { ++ // Step 2 - Prepare data for AES (it is like the creation of CW in nanoED but swapped each 8 bytes) ++ uint8_t dataEC[16] = { 0 }; ++ ++ dataEC[0] = encryptedData[0x02]; ++ dataEC[1] = encryptedData[0x0E]; ++ dataEC[2] = encryptedData[0x10]; ++ dataEC[3] = encryptedData[0x18]; ++ dataEC[4] = encryptedData[0x09]; ++ dataEC[5] = encryptedData[0x11]; ++ dataEC[6] = encryptedData[0x03]; ++ dataEC[7] = encryptedData[0x16]; ++ ++ dataEC[8] = encryptedData[0x13]; ++ dataEC[9] = encryptedData[0x1A]; ++ dataEC[10] = encryptedData[0x12]; ++ dataEC[11] = encryptedData[0x0B]; ++ dataEC[12] = encryptedData[0x04]; ++ dataEC[13] = encryptedData[0x1D]; ++ dataEC[14] = encryptedData[0x19]; ++ dataEC[15] = encryptedData[0x05]; ++ ++ // Step 3 - Decrypt AES CBC with new aesKey and iv 2EBD816A5E749A708AE45ADDD84333DE ++ uint8_t aesKeyIndex = nanoMode & 0x1F; // 32 possible AES keys ++ uint8_t aesKey[16] = { 0 }; ++ ++ if(!GetTandbergKey(aesKeyIndex, "AES", aesKey, 16)) ++ { ++ return 2; ++ } ++ ++ struct aes_keys aes; ++ aes_set_key(&aes, (char *)aesKey); ++ ++ uint8_t ivAes[16] = { 0x2E, 0xBD, 0x81, 0x6A, 0x5E, 0x74, 0x9A, 0x70, 0x8A, 0xE4, 0x5A, 0xDD, 0xD8, 0x43, 0x33, 0xDE }; ++ aes_cbc_decrypt(&aes, dataEC, 16, ivAes); ++ ++ // Step 4 - Create CW (a simple swap) ++ uint8_t offset; ++ for (offset = 0; offset < 16; offset++) ++ { ++ dw[offset] = dataEC[15 - offset]; ++ } ++ ++ return 0; ++ } ++ } ++ ++ case 0xED: // ECM_TAG_CW_DESCRIPTOR ++ { ++ if(nanoLength != 0x26) ++ { ++ cs_log("WARNING: nanoType ED length (%d) != %d", nanoLength, 0x26); ++ break; ++ } ++ ++ entitlementId = b2i(4, nanoData); ++ ++ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) ++ { ++ return 2; ++ } ++ ++ cs_log("Active entitlement %.4X", entitlementId); ++ ++ uint8_t encryptedData[32] = { 0 }; ++ memcpy(encryptedData, nanoData + 4, 32); ++ ++ uint8_t iv[8] = { 0 }; ++ des_cbc_decrypt(encryptedData, iv, ecmKey, 32); ++ ++ dw[0] = encryptedData[0x05]; ++ dw[1] = encryptedData[0x19]; ++ dw[2] = encryptedData[0x1D]; ++ dw[4] = encryptedData[0x0B]; ++ dw[5] = encryptedData[0x12]; ++ dw[6] = encryptedData[0x1A]; ++ dw[8] = encryptedData[0x16]; ++ dw[9] = encryptedData[0x03]; ++ dw[10] = encryptedData[0x11]; ++ dw[12] = encryptedData[0x18]; ++ dw[13] = encryptedData[0x10]; ++ dw[14] = encryptedData[0x0E]; ++ ++ return 0; ++ } ++ ++ case 0xEE: // ECM_TAG_CW_DESCRIPTOR ++ { ++ if(nanoLength != 0x16) ++ { ++ cs_log("WARNING: nanoType EE length (%d) != %d", nanoLength, 0x16); ++ break; ++ } ++ ++ entitlementId = b2i(4, nanoData); ++ ++ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) ++ { ++ return 2; ++ } ++ ++ cs_log("Active entitlement %.4X", entitlementId); ++ ++ memcpy(dw, nanoData + 4 + 8, 8); // even ++ memcpy(dw + 8, nanoData + 4, 8); // odd ++ ++ des_set_key(ecmKey, ks); ++ ++ des(dw, ks, 0); ++ des(dw + 8, ks, 0); ++ ++ return 0; ++ } ++ ++ default: ++ cs_log("WARNING: nanoType %.2X not supported", nanoType); ++ break; ++ } ++ ++ pos += 2 + nanoLength; ++ ++ } while (pos < ecmLen); ++ ++ return 1; ++} ++ ++const char* GetProcessECMErrorReason(int8_t result) ++{ ++ switch(result) { ++ case 0: ++ return "No error"; ++ case 1: ++ return "ECM not supported"; ++ case 2: ++ return "Key not found"; ++ case 3: ++ return "Nano80 problem"; ++ case 4: ++ return "Corrupt data"; ++ case 5: ++ return "CW not found"; ++ case 6: ++ return "CW checksum error"; ++ case 7: ++ return "Out of memory"; ++ case 8: ++ return "ECM checksum error"; ++ case 9: ++ return "ICG error"; ++ default: ++ return "Unknown"; ++ } ++} ++ ++/* Error codes ++0 OK ++1 ECM not supported ++2 Key not found ++3 Nano80 problem ++4 Corrupt data ++5 CW not found ++6 CW checksum error ++7 Out of memory ++8 ECM checksum error ++9 ICG error ++*/ ++#ifdef WITH_EMU ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, ++ uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex) ++#else ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, ++ uint8_t *dw, uint16_t srvid, uint16_t ecmpid) ++#endif ++{ ++ int8_t result = 1, i; ++ uint8_t ecmCopy[EMU_MAX_ECM_LEN]; ++ uint16_t ecmLen = 0; ++ ++ if(ecmDataLen < 3) { ++ // accept requests without ecm only for biss ++ if((caid>>8) != 0x26 && caid != 0xFFFF) { ++ return 1; ++ } ++ } ++ else { ++ ecmLen = GetEcmLen(ecm); ++ } ++ ++ if(ecmLen > ecmDataLen) { ++ return 1; ++ } ++ ++ if(ecmLen > EMU_MAX_ECM_LEN) { ++ return 1; ++ } ++ memcpy(ecmCopy, ecm, ecmLen); ++ ++ if((caid >> 8) == 0x0D) { ++ result = CryptoworksECM(caid, ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x09) { ++ result = SoftNDSECM(caid, ecmCopy, dw); ++ } ++ else if(caid == 0x0500) { ++ result = ViaccessECM(ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x18) { ++ result = Nagra2ECM(ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x06) { ++ result = Irdeto2ECM(caid, ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x26 || caid == 0xFFFF) { ++ result = BissECM(rdr, ecm, ecmDataLen, dw, srvid, ecmpid); ++ } ++ else if((caid >> 8) == 0x0E) { ++#ifdef WITH_EMU ++ result = PowervuECM(ecmCopy, dw, srvid, NULL, cw_ex); ++#else ++ result = PowervuECM(ecmCopy, dw, NULL); ++#endif ++ } ++ else if(caid == 0x4AE1) { ++ result = Drecrypt2ECM(provider, ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x10) { ++ result = TandbergECM(ecmCopy, dw); ++ } ++ ++ // fix dcw checksum ++ if(result == 0 && !((caid >> 8) == 0x0E)) { ++ for(i = 0; i < 16; i += 4) { ++ dw[i + 3] = ((dw[i] + dw[i + 1] + dw[i + 2]) & 0xff); ++ } ++ } ++ ++ if(result != 0) { ++ cs_log("ECM failed: %s", GetProcessECMErrorReason(result)); ++ } ++ ++ return result; ++} ++ ++// Viaccess EMM EMU ++static int8_t ViaccessEMM(uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint8_t nanoCmd = 0, subNanoCmd = 0, *tmp; ++ uint16_t i = 0, j = 0, k = 0, emmLen = GetEcmLen(emm); ++ uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17]; ++ uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D; ++ uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0; ++ uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0; ++ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; ++ struct aes_keys aes; ++ ++ memset(keyD0, 0, 2); ++ memset(ecmKeyIndex, 0, sizeof(uint32_t)*6); ++ ++ for(i=3; i+2 emmLen) { ++ return 1; ++ } ++ ++ switch(nanoCmd) { ++ case 0x90: { ++ if(nanoLen < 3) { ++ break; ++ } ++ ui1 = emm[i+2]; ++ ui2 = emm[i+1]; ++ ui3 = emm[i]; ++ provider = (ui1 | (ui2 << 8) | (ui3 << 16)); ++ if(provider == 0x00D00040) { ++ ecmProvider = 0x030B00; ++ } ++ else { ++ return 1; ++ } ++ break; ++ } ++ case 0xD2: { ++ if(nanoLen < 2) { ++ break; ++ } ++ emmKeyIndex = emm[i+1]; ++ break; ++ } ++ case 0x41: { ++ if(nanoLen < 1) { ++ break; ++ } ++ if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { ++ return 2; ++ } ++ memset(provName, 0, 17); ++ memset(emmXorKey, 0, 16); ++ k = nanoLen < 16 ? nanoLen : 16; ++ memcpy(provName, &emm[i], k); ++ aes_set_key(&aes, (char*)emmKey); ++ aes_decrypt(&aes, emmXorKey, 16); ++ for(j=0; j<16; j++) { ++ provName[j] ^= emmXorKey[j]; ++ } ++ provName[k] = 0; ++ ++ if(strcmp((char*)provName, "TNTSAT") != 0 && strcmp((char*)provName, "TNTSATPRO") != 0 ++ &&strcmp((char*)provName, "CSAT V") != 0) { ++ return 1; ++ } ++ break; ++ } ++ case 0xBA: { ++ if(nanoLen < 2) { ++ break; ++ } ++ GetViaKey(keyD0, ecmProvider, 'D', 0, 2, 0); ++ ui1 = (emm[i] << 8) | emm[i+1]; ++ if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00)) { ++ keyD0[0] = emm[i]; ++ keyD0[1] = emm[i+1]; ++ haveNewD0 = 1; ++ break; ++ } ++ return 0; ++ } ++ case 0xBC: { ++ break; ++ } ++ case 0x43: { ++ if(nanoLen < 16) { ++ break; ++ } ++ memcpy(emmXorKey, &emm[i], 16); ++ haveEmmXorKey = 1; ++ break; ++ } ++ case 0x44: { ++ if(nanoLen < 3) { ++ break; ++ } ++ if (!haveEmmXorKey) { ++ memset(emmXorKey, 0, 16); ++ } ++ tmp = (uint8_t*)malloc(((nanoLen/16)+1)*16*sizeof(uint8_t)); ++ if(tmp == NULL) { ++ return 7; ++ } ++ memcpy(tmp, &emm[i], nanoLen); ++ aes_set_key(&aes, (char*)emmKey); ++ for(j=0; j 5) { ++ break; ++ } ++ for(j=i; j+2 i+nanoLen) { ++ break; ++ } ++ switch(subNanoCmd) { ++ case 0xD2: { ++ if(nanoLen < 2) { ++ break; ++ } ++ aesMode = emm[j]; ++ emmKeyIndex = emm[j+1]; ++ break; ++ } ++ case 0x01: { ++ if(nanoLen < 17) { ++ break; ++ } ++ ecmKeyIndex[ecmKeyCount] = emm[j]; ++ memcpy(&ecmKeys[ecmKeyCount], &emm[j+1], 16); ++ if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { ++ break; ++ } ++ ++ if(aesMode == 0x0F || aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); ++ hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]); ++ } ++ else if(aesMode == 0x13 || aesMode == 0x15) { ++ hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]); ++ } ++ aes_set_key(&aes, (char*)emmKey); ++ aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16); ++ if(aesMode == 0x0F || aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); ++ } ++ else if(aesMode == 0x13 || aesMode == 0x15) { ++ hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]); ++ } ++ ++ ecmKeyCount++; ++ break; ++ } ++ default: ++ break; ++ } ++ j += subNanoLen; ++ } ++ break; ++ } ++ case 0xF0: { ++ if(nanoLen != 4) { ++ break; ++ } ++ ui1 = ((emm[i+2] << 8) | (emm[i+1] << 16) | (emm[i] << 24) | emm[i+3]); ++ if(fletcher_crc32(emm + 3, emmLen - 11) != ui1) { ++ return 4; ++ } ++ ++ if(haveNewD0) { ++ ++ SetKey('V', ecmProvider, "D0", keyD0, 2, 1, NULL, NULL); ++ ++ for(j=0; j>2); ++ SetKey('I', ident, keyName, &emm[i+3], 16, 1, NULL, NULL); ++ ++ (*keysAdded)++; ++ cs_hexdump(0, &emm[i+3], 16, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); ++ } ++ } ++ i+=l; ++ } ++ ++ if(*keysAdded > 0) { ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++static int8_t Irdeto2DoEMMTypePMK(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, ++ uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) ++{ ++ uint32_t end, i, l, j; ++ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; ++ ++ Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length); ++ ++ i = 13; ++ end = startOffset + (length-8 < 0 ? 0 : length-8); ++ ++ while(i 0) { ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++static const uint8_t fausto_xor[16] = { 0x22, 0x58, 0xBD, 0x85, 0x2E, 0x8E, 0x52, 0x80, 0xA3, 0x79, 0x98, 0x69, 0x68, 0xE2, 0xD8, 0x4D }; ++ ++static int8_t Irdeto2EMM(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded) ++{ ++ uint8_t length, okeySeed[16], keySeed[16], keyIV[16], keyPMK[16], startOffset, emmType; ++ uint32_t ident; ++ uint32_t keySeedRef, keyIVRef, keyPMK0Ref, keyPMK1Ref, keyPMK0ERef, keyPMK1ERef; ++ uint8_t emmCopy[EMU_MAX_EMM_LEN], *emm = oemm; ++ uint16_t emmLen = GetEcmLen(emm); ++ ++ if(emmLen < 11) { ++ return 1; ++ } ++ ++ if(emm[3] == 0xC3 || emm[3] == 0xCB) { ++ emmType = 2; ++ startOffset = 11; ++ } ++ else { ++ emmType = 1; ++ startOffset = 10; ++ } ++ ++ ident = emm[startOffset-2] | caid << 8; ++ length = emm[startOffset-1]; ++ ++ ++ if(emmLen < length+startOffset) { ++ return 1; ++ } ++ ++ keySeedRef = 0; ++ while(GetIrdetoKey(okeySeed, ident, 'M', emmType == 1 ? 0 : 0xA, 1, &keySeedRef)) { ++ keyIVRef = 0; ++ while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) { ++ ++ keyPMK0Ref = 0; ++ keyPMK1Ref = 0; ++ keyPMK0ERef = 0; ++ keyPMK1ERef = 0; ++ ++ while(GetIrdetoKey(keyPMK, ident, 'M', emmType == 1 ? 3 : 0xB, 1, &keyPMK0Ref)) { ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(emmType == 1) { ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ else { ++ if(Irdeto2DoEMMTypePMK(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ } ++ ++ if(emmType == 1) { ++ while(GetIrdetoKey(keyPMK, ident, 'M', 4, 1, &keyPMK1Ref)) { ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ ++ while(GetIrdetoKey(keyPMK, ident, 'M', 5, 1, &keyPMK0ERef)) { ++ xxor(keyPMK, 16, keyPMK, fausto_xor); ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ ++ while(GetIrdetoKey(keyPMK, ident, 'M', 6, 1, &keyPMK1ERef)) { ++ xxor(keyPMK, 16, keyPMK, fausto_xor); ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ } ++ ++ if(keyPMK0Ref == 0 && keyPMK1Ref == 0 && keyPMK0ERef == 0 && keyPMK1ERef == 0) { ++ return 2; ++ } ++ } ++ if(keyIVRef == 0) { ++ return 2; ++ } ++ } ++ if(keySeedRef == 0) { ++ return 2; ++ } ++ ++ return 1; ++} ++ ++int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t *hexserial) ++{ ++ uint32_t i, len; ++ KeyDataContainer *KeyDB; ++ KeyData *tmpKeyData; ++ ++ KeyDB = GetKeyContainer('I'); ++ if(KeyDB == NULL) { ++ return 0; ++ } ++ ++ for(i=0; ikeyCount; i++) { ++ ++ if(KeyDB->EmuKeys[i].provider>>8 != caid) { ++ continue; ++ } ++ if(strcmp(KeyDB->EmuKeys[i].keyName, "MC")) { ++ continue; ++ } ++ ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ ++ len = tmpKeyData->keyLength; ++ if(len > 3) ++ { len = 3; } ++ ++ memcpy(hexserial+(3-len), tmpKeyData->key, len); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++// PowerVu EMM EMU ++static void PowervuUnmaskEmm(uint8_t *emm) ++{ ++ int i, l; ++ ++ uint8_t sourcePos[] = {0x03, 0x0C, 0x0D, 0x11, 0x15, 0x18, 0x1D, 0x1F, 0x25, 0x2A, 0x32, 0x35, 0x3A, 0x3B, 0x3E, ++ 0x42, 0x47, 0x48, 0x53, 0x58, 0x5C, 0x61, 0x66, 0x69, 0x71, 0x72, 0x78, 0x7B, 0x81, 0x84}; ++ ++ uint8_t destPos[] = {0x02, 0x08, 0x0B, 0x0E, 0x13, 0x16, 0x1E, 0x23, 0x28, 0x2B, 0x2F, 0x33, 0x38, 0x3C, 0x40, ++ 0x44, 0x4A, 0x4D, 0x54, 0x57, 0x5A, 0x63, 0x68, 0x6A, 0x70, 0x75, 0x76, 0x7D, 0x82, 0x85}; ++ ++ uint8_t data[0x1E]; ++ uint8_t hashModeEmm; ++ uint8_t mask[0x10]; ++ uint32_t crc; ++ ++ // Create Mask for ECM decryption ++ PowervuCreateDataEcmEmm(emm, sourcePos, 0x13, 0x1E, data); ++ ++ hashModeEmm = emm[8] ^ PowervuCrc8Calc(data, 0x1E); ++ ++ PowervuCreateHash(data, 0x1E, mask, hashModeEmm); ++ ++ // Fix Header ++ emm[3] &= 0x0F; ++ emm[3] |= 0x10; ++ emm[8] = 0x00; ++ ++ // Unmask Body ++ for(i = 0; i < 0x1E; i++) ++ { ++ emm[0x13 + destPos[i]] ^= mask[i & 0x0F]; ++ } ++ ++ // Fix CRC (optional) ++ l = (((emm[1] << 8) + emm[2]) & 0xFFF) + 3 - 4; ++ crc = fletcher_crc32(emm, l); ++ ++ emm[l + 0] = crc >> 24; ++ emm[l + 1] = crc >> 16; ++ emm[l + 2] = crc >> 8; ++ emm[l + 3] = crc >> 0; ++} ++ ++static int8_t PowervuEMM(uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint8_t emmInfo, emmType, decryptOk = 0; ++ uint16_t emmLen = GetEcmLen(emm); ++ uint32_t i, uniqueAddress, groupId, keyRef = 0; ++ //uint32_t emmCrc32; ++ uint8_t emmKey[7], tmpEmmKey[7], tmp[26]; ++ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[16]; ++ char uaInfo[4+8+1]; ++ ++ if(emmLen < 50) ++ { ++ return 1; ++ } ++ ++ // Check if unmasking is needed ++ if((emm[3] & 0xF0) == 0x50) ++ { ++ PowervuUnmaskEmm(emm); ++ } ++ ++ // looks like checksum does not work for all EMMs ++ //emmCrc32 = b2i(4, emm+emmLen-4); ++ // ++ //if(fletcher_crc32(emm, emmLen-4) != emmCrc32) ++ //{ ++ // return 8; ++ //} ++ emmLen -= 4; ++ ++ uniqueAddress = b2i(4, emm+12); ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.8X", uniqueAddress); ++ ++ do ++ { ++ if(!GetPowervuEmmKey(emmKey, 0, keyName, 7, 0, keyRef++, &groupId)) ++ { ++ cs_log_dbg(D_EMM, "EMM error: AU key for UA %s is missing", keyName); ++ return 2; ++ } ++ ++ for(i=19; i+27<=emmLen; i+=27) { ++ emmInfo = emm[i]; ++ ++ if(!GetBit(emmInfo, 7)) ++ { ++ continue; ++ } ++ ++ //keyNb = emm[i] & 0x0F; ++ ++ memcpy(tmp, emm+i+1, 26); ++ memcpy(tmpEmmKey, emmKey, 7); ++ PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 0); ++ ++ if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) ++ { ++ memcpy(emm+i+1, tmp, 26); ++ memcpy(tmpEmmKey, emmKey, 7); ++ PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 1); ++ ++ if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) ++ { ++ memcpy(emm+i+1, tmp, 26); ++ memcpy(tmpEmmKey, emmKey, 7); ++ continue; ++ } ++ } ++ ++ decryptOk = 1; ++ ++ emmType = emm[i+2] & 0x7F; ++ if(emmType > 1) ++ { ++ continue; ++ } ++ ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", emmType); ++ snprintf(uaInfo, sizeof(uaInfo), "UA: %08X", uniqueAddress); ++ ++ if(emm[i+3] == 0 && emm[i+4] == 0) ++ { ++ cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: P %.4X**** %s %s -> REJECTED (looks invalid) UA: %.8X", groupId, keyName, keyValue, uniqueAddress); ++ continue; ++ } ++ ++ UpdateKeysByProviderMask('P', groupId<<16, 0x0000FFFF, keyName, &emm[i+3], 7, uaInfo); ++ ++ (*keysAdded)++; ++ cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: P %.4X**** %s %s ; UA: %.8X", groupId, keyName, keyValue, uniqueAddress); ++ } ++ ++ } while(!decryptOk); ++ ++ return 0; ++} ++ ++int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count) ++{ ++ //srvid == 0xFFFF -> get all ++ ++ uint32_t i, j; ++ uint32_t groupid; ++ int32_t len, k; ++ KeyDataContainer *KeyDB; ++ uint8_t tmp[4]; ++ int8_t alreadyAdded; ++ ++ KeyDB = GetKeyContainer('P'); ++ if(KeyDB == NULL) ++ { return 0; } ++ ++ (*count) = 0; ++ ++ for(i=0; ikeyCount && (*count)EmuKeys[i].provider <= 0x0000FFFF) // skip au keys ++ { continue; } ++ ++ if(srvid != 0xFFFF && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != srvid) ++ { continue; } ++ ++ groupid = KeyDB->EmuKeys[i].provider>>16; ++ ++ for(j=0; jkeyCount && (*count)EmuKeys[j].provider != groupid) // search au key with groupip ++ { continue; } ++ ++ len = strlen(KeyDB->EmuKeys[j].keyName); ++ ++ if(len < 3) ++ { continue;} ++ ++ if(len > 8) ++ { len = 8; } ++ ++ memset(tmp, 0, 4); ++ CharToBin(tmp+(4-(len/2)), KeyDB->EmuKeys[j].keyName, len); ++ ++ for(k=0, alreadyAdded=0; k<*count; k++) ++ { ++ if(!memcmp(hexserials[k], tmp, 4)) ++ { ++ alreadyAdded = 1; ++ break; ++ } ++ } ++ ++ if(!alreadyAdded) ++ { ++ memcpy(hexserials[*count], tmp, 4); ++ (*count)++; ++ } ++ } ++ ++ } ++ ++ return 1; ++} ++ ++// Drecrypt EMM EMU ++static int8_t DrecryptGetEmmKey(uint8_t *buf, uint32_t keyIdent, uint16_t keyName, uint8_t isCriticalKey) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "MK%04X", keyName); ++ return FindKey('D', keyIdent, 0, keyStr, buf, 32, isCriticalKey, 0, 0, NULL); ++} ++ ++static void DrecryptWriteEebin(const char *path, const char *name) ++{ ++ char tmp[256]; ++ FILE *file = NULL; ++ uint8_t i, buffer[64][32]; ++ uint32_t prvid; ++ ++ // Set path ++ if (path != NULL) ++ { ++ snprintf(tmp, 256, "%s%s", path, name); ++ } ++ else // No path set, use SoftCam.Keys's path ++ { ++ snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); ++ } ++ ++ if ((file = fopen(tmp, "wb")) != NULL) ++ { ++ cs_log("Writing key file: %s", tmp); ++ } ++ else ++ { ++ cs_log("Error writing key file: %s", tmp); ++ return; ++ } ++ ++ // Load keys from db to buffer ++ prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; ++ ++ for (i = 0; i < 32; i++) // Load "3B" type keys ++ { ++ snprintf(tmp, 5, "3B%02X", i); ++ if (!FindKey('D', prvid, 0, tmp, buffer[i], 32, 0, 0, 0, NULL)) ++ { ++ memset(buffer[i], 0xFF, 32); ++ } ++ } ++ ++ for (i = 0; i < 32; i++) // Load "56" type keys ++ { ++ snprintf(tmp, 5, "56%02X", i); ++ if (!FindKey('D', prvid, 0, tmp, buffer[32 + i], 32, 0, 0, 0, NULL)) ++ { ++ memset(buffer[32 + i], 0xFF, 32); ++ } ++ } ++ ++ // Write buffer to ee.bin file ++ fwrite(buffer, 1, sizeof(buffer), file); ++ fclose(file); ++} ++ ++static int8_t DrecryptProcessEMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint16_t emmLen, emmDataLen; ++ uint32_t i, keyIdent; ++ uint16_t keyName; ++ uint8_t emmKey[32]; ++ uint8_t *curECMkey3B = NULL, *curECMkey56 = NULL; ++ uint8_t keynum =0, keyidx = 0, keyclass = 0, key1offset, key2offset; ++ char newKeyName[EMU_MAX_CHAR_KEYNAME], curKeyName[EMU_MAX_CHAR_KEYNAME], keyValue[100]; ++ ++ emmDataLen = GetEcmLen(emm); ++ emmLen = ((emm[1] & 0xF) << 8) | emm[2]; ++ ++ if (emmDataLen < emmLen + 3) ++ { ++ return 4; // Corrupt data ++ } ++ ++ if (emm[0] == 0x91) ++ { ++ Drecrypt2OverEMM(emm); ++ return 0; ++ } ++ else if (emm[0] == 0x82) ++ { ++ ReasmEMM82(emm); ++ return 0; ++ } ++ else if (emm[0] != 0x86) ++ { ++ return 1; // Not supported ++ } ++ ++ // Emm type 0x86 only ++ switch (emm[4]) ++ { ++ case 0x02: ++ keynum = 0x2C; ++ keyidx = 0x30; ++ keyclass = 0x26; ++ key1offset = 0x35; ++ key2offset = 0x6D; ++ break; ++ ++ case 0x4D: ++ keynum = 0x61; ++ keyidx = 0x60; ++ keyclass = 0x05; ++ key1offset = 0x62; ++ key2offset = 0x8B; ++ break; ++ ++ default: ++ return 1; // Not supported ++ } ++ ++ switch (provId & 0xFF) ++ { ++ case 0x11: ++ { ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); ++ FindKey('D', 0x4AE111, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); ++ ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); ++ FindKey('D', 0x4AE111, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); ++ ++ break; ++ } ++ ++ case 0x14: ++ { ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); ++ FindKey('D', 0x4AE114, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); ++ ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); ++ FindKey('D', 0x4AE114, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); ++ ++ break; ++ } ++ ++ default: ++ return 9; // Wrong provider ++ } ++ ++ keyIdent = (0x4AE1 << 8) | provId; ++ keyName = (emm[3] << 8) | emm[keynum]; ++ ++ if (!DrecryptGetEmmKey(emmKey, keyIdent, keyName, 1)) ++ { ++ return 2; ++ } ++ ++ // Key #1 ++ for (i = 0; i < 4; i++) ++ { ++ DrecryptDecrypt(&emm[key1offset + (i * 8)], emmKey); ++ } ++ ++ // Key #2 ++ for (i = 0; i < 4; i++) ++ { ++ DrecryptDecrypt(&emm[key2offset + (i * 8)], emmKey); ++ } ++ ++ // Key #1 ++ keyName = emm[keyidx] << 8 | emm[keyclass]; ++ snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); ++ ++ if (memcmp(&emm[key1offset], emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, 32) != 0) ++ { ++ memcpy(emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, &emm[key1offset], 32); ++ SetKey('D', keyIdent, newKeyName, &emm[key1offset], 32, 0, NULL, NULL); ++ (*keysAdded)++; ++ ++ cs_hexdump(0, &emm[key1offset], 32, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); ++ } ++ else ++ { ++ cs_log("Key %.6X %s already exists", keyIdent, newKeyName); ++ } ++ ++ // Key #2 ++ keyName = (emm[keyidx] == 0x56 ? 0x3B00 : 0x5600) | emm[keyclass]; ++ snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); ++ ++ if (memcmp(&emm[key2offset], emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, 32) != 0) ++ { ++ memcpy(emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, &emm[key2offset], 32); ++ SetKey('D', keyIdent, newKeyName, &emm[key2offset], 32, 0, NULL, NULL); ++ (*keysAdded)++; ++ ++ cs_hexdump(0, &emm[key2offset], 32, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); ++ } ++ else ++ { ++ cs_log("Key %.6X %s already exists", keyIdent, newKeyName); ++ } ++ ++ if (*keysAdded > 0) // Write new ecm keys to ee.bin file ++ { ++ switch (provId & 0xFF) ++ { ++ case 0x11: ++ DrecryptWriteEebin(rdr->extee36, "ee36.bin"); ++ break; ++ ++ case 0x14: ++ DrecryptWriteEebin(rdr->extee56, "ee56.bin"); ++ break; ++ ++ default: ++ cs_log("Provider %02X doesn't have a matching ee.bin file", provId & 0xFF); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static int8_t Drecrypt2EMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) ++{ ++ int8_t result = DrecryptProcessEMM(rdr, provId, emm, keysAdded); ++ ++ if (result == 2) ++ { ++ uint8_t keynum = 0, emmkey; ++ uint32_t i; ++ KeyDataContainer *KeyDB = GetKeyContainer('D'); ++ ++ if (KeyDB == NULL) ++ { ++ return result; ++ } ++ ++ for (i = 0; i < KeyDB->keyCount; i++) ++ { ++ if (KeyDB->EmuKeys[i].provider != ((0x4AE1 << 8) | provId)) ++ { ++ continue; ++ } ++ ++ if (strlen(KeyDB->EmuKeys[i].keyName) < 6) ++ { ++ continue; ++ } ++ ++ if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) ++ { ++ continue; ++ } ++ ++ CharToBin(&keynum, KeyDB->EmuKeys[i].keyName + 4, 2); ++ emmkey = (emm[4] == 0x4D) ? emm[0x61] : emm[0x2C]; ++ ++ if (keynum == emmkey) ++ { ++ if (provId == 0x11) ++ { ++ CharToBin(&rdr->dre36_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); ++ } ++ else ++ { ++ CharToBin(&rdr->dre56_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); ++ } ++ ++ break; ++ } ++ } ++ } ++ ++ return result; ++} ++ ++int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t *count) ++{ ++ uint32_t i; ++ KeyDataContainer *KeyDB = GetKeyContainer('D'); ++ ++ if (KeyDB == NULL) ++ { ++ return 0; ++ } ++ ++ (*count) = 0; ++ ++ for (i = 0; i < KeyDB->keyCount && (*count) < length; i++) ++ { ++ ++ if (KeyDB->EmuKeys[i].provider != ((caid << 8) | provid)) ++ { ++ continue; ++ } ++ ++ if (strlen(KeyDB->EmuKeys[i].keyName) < 6) ++ { ++ continue; ++ } ++ ++ if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) ++ { ++ continue; ++ } ++ ++ CharToBin(&hexserials[(*count)], KeyDB->EmuKeys[i].keyName + 2, 2); ++ ++ (*count)++; ++ } ++ ++ return 1; ++} ++ ++// Tandberg EMM EMU ++static uint8_t MixTable[] = ++{ ++ 0x12,0x78,0x4B,0x19,0x13,0x80,0x2F,0x84, ++ 0x86,0x4C,0x09,0x53,0x15,0x79,0x6B,0x49, ++ 0x10,0x4D,0x33,0x43,0x18,0x37,0x83,0x38, ++ 0x82,0x1B,0x6E,0x24,0x2A,0x85,0x3C,0x3D, ++ 0x5A,0x58,0x55,0x5D,0x20,0x41,0x65,0x51, ++ 0x0C,0x45,0x63,0x7F,0x0F,0x46,0x21,0x7C, ++ 0x2C,0x61,0x7E,0x0A,0x42,0x57,0x35,0x16, ++ 0x87,0x3B,0x4F,0x40,0x34,0x22,0x26,0x74, ++ 0x32,0x69,0x44,0x7A,0x6A,0x6D,0x0D,0x56, ++ 0x23,0x2B,0x5C,0x72,0x76,0x36,0x28,0x25, ++ 0x2E,0x52,0x5B,0x6C,0x7D,0x30,0x0B,0x5E, ++ 0x47,0x1F,0x7B,0x31,0x3E,0x11,0x77,0x1E, ++ 0x60,0x75,0x54,0x27,0x50,0x17,0x70,0x59, ++ 0x1A,0x2D,0x4A,0x67,0x3A,0x5F,0x68,0x08, ++ 0x4E,0x3F,0x29,0x6F,0x81,0x71,0x39,0x64, ++ 0x48,0x66,0x73,0x14,0x0E,0x1D,0x62,0x1C ++}; ++ ++void TandbergRotateBytes(unsigned char *in, int n) ++{ ++ if(n > 1) ++ { ++ unsigned char *e = in + n - 1; ++ do ++ { ++ unsigned char temp = *in; ++ *in++ = *e; ++ *e-- = temp; ++ } ++ while (in < e); ++ } ++} ++ ++static void TandbergECMKeyDecrypt(uint8_t* emmKey, uint8_t* tagData, uint8_t* ecmKey) ++{ ++ TandbergRotateBytes(emmKey, 8); ++ uint8_t iv[8] = { 0 }; ++ uint8_t* payLoad = tagData + 4 + 5; ++ des_cbc_decrypt(payLoad, iv, emmKey, 16); ++ ++ ecmKey[0] = payLoad[0x0F]; ++ ecmKey[1] = payLoad[0x01]; ++ ecmKey[2] = payLoad[0x0B]; ++ ecmKey[3] = payLoad[0x03]; ++ ecmKey[4] = payLoad[0x0E]; ++ ecmKey[5] = payLoad[0x04]; ++ ecmKey[6] = payLoad[0x0A]; ++ ecmKey[7] = payLoad[0x08]; ++} ++ ++static int8_t TandbergParseEMMNanoTags(uint8_t* data, uint32_t length, uint8_t keyIndex, uint32_t *keysAdded) ++{ ++ uint8_t tagType, tagLength, blockIndex; ++ uint32_t pos = 0, entitlementId; ++ int32_t i, k; ++ uint32_t ks[32]; ++ uint8_t* tagData; ++ uint8_t emmKey[8]; ++ char keyValue[17]; ++ uint8_t tagDataDecrypted[0x10][8]; ++ ++ if(length < 2) ++ { ++ return 1; ++ } ++ ++ while(pos < length) ++ { ++ tagType = data[pos]; ++ tagLength = data[pos+1]; ++ ++ if(pos + 2 + tagLength > length) ++ { ++ return 1; ++ } ++ ++ tagData = data + pos + 2; ++ ++ switch(tagType) ++ { ++ case 0xE4: // EMM_TAG_SECURITY_TABLE_DESCRIPTOR (ram emm keys) ++ { ++ uint8_t tagMode = data[pos + 2]; ++ ++ switch(tagMode) ++ { ++ case 0x01: // keySet 01 (MK01) ++ { ++ if(tagLength != 0x8A) ++ { ++ cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x8A); ++ break; ++ } ++ ++ if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) ++ { ++ break; ++ } ++ ++ uint8_t iv[8] = { 0 }; ++ uint8_t* tagPayload = tagData + 2; ++ des_cbc_decrypt(tagPayload, iv, emmKey, 136); ++ ++ for (k = 0; k < 0x10; k++) // loop 0x10 keys ++ { ++ for (i = 0; i < 8; i++) // loop 8 bytes of key ++ { ++ tagDataDecrypted[k][i] = tagPayload[MixTable[8*k + i]]; ++ } ++ } ++ ++ blockIndex = tagData[1] & 0x03; ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ SetKey('T', (blockIndex << 4) + i, "MK01", tagDataDecrypted[i], 8, 0, NULL, NULL); ++ } ++ } ++ break; ++ ++ case 0xFF: // keySet FF (MK) ++ { ++ if(tagLength != 0x82) ++ { ++ cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x82); ++ break; ++ } ++ ++ blockIndex = tagData[1] & 0x03; ++ ++ if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) ++ { ++ break; ++ } ++ ++ des_set_key(emmKey, ks); ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ des(tagData + 2 + (i*8), ks, 0); ++ } ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ SetKey('T', (blockIndex << 4) + i, "MK", tagData + 2 + (i*8), 8, 0, NULL, NULL); ++ } ++ } ++ break; ++ ++ default: ++ cs_log("WARNING: nanoTag E4 mode %.2X not supported", tagMode); ++ break; ++ } ++ break; ++ } ++ ++ case 0xE1: // EMM_TAG_EVENT_ENTITLEMENT_DESCRIPTOR (ecm keys) ++ { ++ uint8_t tagMode = data[pos + 2 + 4]; ++ ++ switch(tagMode) ++ { ++ case 0x00: // ecm keys from mode FF ++ { ++ if(tagLength != 0x12) ++ { ++ cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x12); ++ break; ++ } ++ ++ entitlementId = b2i(4, tagData); ++ ++ if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) ++ { ++ break; ++ } ++ ++ des_set_key(emmKey, ks); ++ des(tagData + 4 + 5, ks, 0); ++ ++ if((tagData + 4 + 5 + 7) != 0x00) // check if key looks valid (last byte 0x00) ++ { ++ break; ++ } ++ ++ if(UpdateKey('T', entitlementId, "01", tagData + 4 + 5, 8, 1, NULL)) ++ { ++ (*keysAdded)++; ++ cs_hexdump(0, tagData + 4 + 5, 8, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); ++ } ++ } ++ break; ++ ++ case 0x01: // ecm keys from mode 01 ++ { ++ if(tagLength != 0x1A) ++ { ++ cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x1A); ++ break; ++ } ++ ++ entitlementId = b2i(4, tagData); ++ ++ if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) ++ { ++ break; ++ } ++ ++ uint8_t ecmKey[8] = { 0 }; ++ TandbergECMKeyDecrypt(emmKey, tagData, ecmKey); ++ ++ if(ecmKey[7] != 0x00) // check if key looks valid (last byte 0x00) ++ { ++ break; ++ } ++ ++ if(UpdateKey('T', entitlementId, "01", ecmKey, 8, 1, NULL)) ++ { ++ (*keysAdded)++; ++ cs_hexdump(0, ecmKey, 8, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); ++ } ++ } ++ break; ++ ++ default: ++ cs_log("WARNING: nanoTag E1 mode %.2X not supported", tagMode); ++ break; ++ } ++ break; ++ } ++ ++ default: ++ cs_log("WARNING: nanoTag %.2X not supported", tagType); ++ break; ++ } ++ ++ pos += 2 + tagLength; ++ } ++ ++ return 0; ++} ++ ++static int8_t TandbergParseEMMNanoData(uint8_t* data, uint32_t* nanoLength, uint32_t maxLength, uint8_t keyIndex, uint32_t *keysAdded) ++{ ++ uint32_t pos = 0; ++ uint16_t sectionLength; ++ int8_t ret = 0; ++ ++ if(maxLength < 2) ++ { ++ (*nanoLength) = 0; ++ return 1; ++ } ++ ++ sectionLength = ((data[pos]<<8) | data[pos+1]) & 0x0FFF; ++ ++ if(pos + 2 + sectionLength > maxLength) ++ { ++ (*nanoLength) = pos; ++ return 1; ++ } ++ ++ ret = TandbergParseEMMNanoTags(data + pos + 2, sectionLength, keyIndex, keysAdded); ++ ++ pos += 2 + sectionLength; ++ ++ (*nanoLength) = pos; ++ return ret; ++} ++ ++static int8_t TandbergEMM(uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint8_t keyIndex, ret = 0; ++ uint16_t emmLen = GetEcmLen(emm); ++ uint32_t pos = 3; ++ uint32_t permissionDataType; ++ uint32_t nanoLength = 0; ++ ++ while (pos < emmLen && !ret) ++ { ++ permissionDataType = emm[pos]; ++ ++ switch(permissionDataType) ++ { ++ case 0x00: ++ { ++ break; ++ } ++ ++ case 0x01: ++ { ++ pos += 0x0A; ++ break; ++ } ++ ++ case 0x02: ++ { ++ pos += 0x26; ++ break; ++ } ++ ++ default: ++ cs_log("ERROR: unknown permissionDataType %.2X (pos: %d)", permissionDataType, pos); ++ return 1; ++ } ++ ++ if(pos+6 >= emmLen) ++ { ++ break; ++ } ++ ++ keyIndex = emm[pos+1]; ++ ++ // EMM validation ++ // Copy payload checksum bytes and then set them to zero, ++ // so they do not affect the calculated checksum. ++ uint16_t payloadChecksum = (emm[pos + 2] << 8) | emm[pos + 3]; ++ memset(emm + pos + 2, 0, 2); ++ uint16_t calculatedChecksum = TandbergChecksum(emm + 3, emmLen - 3); ++ ++ if(calculatedChecksum != payloadChecksum) ++ { ++ cs_log("EMM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); ++ return 8; ++ } ++ // End of EMM validation ++ ++ pos += 0x04; ++ ret = TandbergParseEMMNanoData(emm + pos, &nanoLength, emmLen - pos, keyIndex, keysAdded); ++ pos += nanoLength; ++ } ++ ++ return ret; ++} ++ ++const char* GetProcessEMMErrorReason(int8_t result) ++{ ++ switch(result) { ++ case 0: ++ return "No error"; ++ case 1: ++ return "EMM not supported"; ++ case 2: ++ return "Key not found"; ++ case 3: ++ return "Nano80 problem"; ++ case 4: ++ return "Corrupt data"; ++ case 5: ++ return "Unknown"; ++ case 6: ++ return "Checksum error"; ++ case 7: ++ return "Out of memory"; ++ case 8: ++ return "EMM checksum error"; ++ case 9: ++ return "Wrong provider"; ++ default: ++ return "Unknown"; ++ } ++} ++ ++int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded) ++{ ++ int8_t result = 1; ++ uint8_t emmCopy[EMU_MAX_EMM_LEN]; ++ uint16_t emmLen = GetEcmLen(emm); ++ ++ if(emmLen > EMU_MAX_EMM_LEN) { ++ return 1; ++ } ++ memcpy(emmCopy, emm, emmLen); ++ *keysAdded = 0; ++ ++ if(caid==0x0500) { ++ result = ViaccessEMM(emmCopy, keysAdded); ++ } ++ else if((caid>>8)==0x06) { ++ result = Irdeto2EMM(caid, emmCopy, keysAdded); ++ } ++ else if((caid>>8)==0x0E) { ++ result = PowervuEMM(emmCopy, keysAdded); ++ } ++ else if(caid==0x4AE1) { ++ result = Drecrypt2EMM(rdr, provider, emmCopy, keysAdded); ++ } ++ else if((caid>>8)==0x10) { ++ result = TandbergEMM(emmCopy, keysAdded); ++ } ++ ++ if(result != 0) { ++ cs_log_dbg(D_EMM,"EMM failed: %s", GetProcessEMMErrorReason(result)); ++ } ++ ++ return result; ++} +diff -ruNp trunk.patches/module-emulator-osemu.h trunk/module-emulator-osemu.h +--- trunk.patches/module-emulator-osemu.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator-osemu.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,127 @@ ++#include "globals.h" ++#include "module-emulator-stream.h" ++ ++#ifndef EMULATOR_H_ ++#define EMULATOR_H_ ++ ++#define EMU_MAX_CHAR_KEYNAME 12 ++#define EMU_KEY_FILENAME "SoftCam.Key" ++#define EMU_KEY_FILENAME_MAX_LEN 31 ++#define EMU_MAX_ECM_LEN MAX_ECM_SIZE ++#define EMU_MAX_EMM_LEN MAX_EMM_SIZE ++ ++typedef struct KeyData KeyData; ++ ++struct KeyData ++{ ++ char identifier; ++ uint32_t provider; ++ char keyName[EMU_MAX_CHAR_KEYNAME]; ++ uint8_t *key; ++ uint32_t keyLength; ++ KeyData *nextKey; ++}; ++ ++typedef struct ++{ ++ KeyData *EmuKeys; ++ uint32_t keyCount; ++ uint32_t keyMax; ++} KeyDataContainer; ++ ++extern KeyDataContainer CwKeys; ++extern KeyDataContainer ViKeys; ++extern KeyDataContainer NagraKeys; ++extern KeyDataContainer IrdetoKeys; ++extern KeyDataContainer NDSKeys; ++extern KeyDataContainer BissKeys; ++extern KeyDataContainer PowervuKeys; ++extern KeyDataContainer DreKeys; ++extern KeyDataContainer TandbergKeys; ++extern uint8_t viasat_const[]; ++ ++uint32_t GetOSemuVersion(void); ++ ++void set_emu_keyfile_path(const char *path); ++void clear_emu_keydata(void); ++uint8_t read_emu_keyfile(struct s_reader *rdr, const char *path); ++ ++#if !defined(__APPLE__) && !defined(__ANDROID__) ++void read_emu_keymemory(struct s_reader *rdr); ++#endif ++ ++void read_emu_eebin(const char *path, const char *name); ++void read_emu_deskey(uint8_t *dreOverKey, uint8_t len); ++ ++int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen); ++ ++/* Error codes ++0 OK ++1 ECM not supported ++2 Key not found ++3 Nano80 problem ++4 Corrupt data ++5 CW not found ++6 CW checksum error ++7 Out of memory ++8 ECM checksum error ++9 ICG error ++*/ ++#ifdef WITH_EMU ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, ++ const uint8_t *ecm, uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex); ++#else ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, ++ const uint8_t *ecm, uint8_t *dw, uint16_t srvid, uint16_t ecmpid); ++#endif ++ ++const char* GetProcessECMErrorReason(int8_t result); ++ ++/* Error codes ++0 OK ++1 EMM not supported ++2 Key not found ++3 Nano80 problem ++4 Corrupt data ++5 ++6 Checksum error ++7 Out of memory ++*/ ++int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded); ++ ++const char* GetProcessEMMErrorReason(int8_t result); ++ ++// hexserial must be of type "uint8_t hexserial[3]" ++// returns 0 on error, 1 on success ++int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t* hexserial); ++ ++// hexserials must be of type "uint8_t hexserials[length][4]" ++// if srvid == 0xFFFF all serials are returned (no srvid filtering) ++// returns 0 on error, 1 on success ++int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count); ++ ++// hexserials must be of type "uint8_t hexserials[length]" ++// returns 0 on error, 1 on success ++int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t* count); ++ ++#define PVU_CW_VID 0 // VIDeo ++#define PVU_CW_HSD 1 // High Speed Data ++#define PVU_CW_A1 2 // Audio 1 ++#define PVU_CW_A2 3 // Audio 2 ++#define PVU_CW_A3 4 // Audio 3 ++#define PVU_CW_A4 5 // Audio 4 ++#define PVU_CW_UTL 6 // UTiLity ++#define PVU_CW_VBI 7 // Vertical Blanking Interval ++ ++#ifdef WITH_EMU ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex); ++#else ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata); ++#endif ++ ++#ifdef WITH_EMU ++int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, ++ uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider); ++#endif ++ ++#endif +diff -ruNp trunk.patches/module-emulator-stream.c trunk/module-emulator-stream.c +--- trunk.patches/module-emulator-stream.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator-stream.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,1105 @@ ++#define MODULE_LOG_PREFIX "emu" ++ ++#include "globals.h" ++#include "cscrypt/des.h" ++ ++#ifdef WITH_EMU ++#include "oscam-string.h" ++#include "oscam-config.h" ++#include "oscam-time.h" ++#include "oscam-net.h" ++ ++extern int32_t exit_oscam; ++#endif ++ ++#include "ffdecsa/ffdecsa.h" ++#include "module-emulator-osemu.h" ++#include "module-emulator-stream.h" ++ ++typedef struct ++{ ++ int32_t connfd; ++ int32_t connid; ++} emu_stream_client_conn_data; ++ ++int8_t stream_server_thread_init = 0; ++char emu_stream_source_host[256] = {"127.0.0.1"}; ++int32_t emu_stream_source_port = 8001; ++char *emu_stream_source_auth = NULL; ++int32_t emu_stream_relay_port = 17999; ++int8_t emu_stream_emm_enabled = 0; ++uint32_t cluster_size = 50; ++ ++static uint8_t emu_stream_server_mutex_init = 0; ++static pthread_mutex_t emu_stream_server_mutex; ++static int32_t glistenfd, gconncount = 0, gconnfd[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++ ++#ifdef WITH_EMU ++pthread_mutex_t emu_fixed_key_srvid_mutex; ++uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++ ++pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++#endif ++ ++static void SearchTsPackets(uint8_t *buf, uint32_t bufLength, uint16_t *packetSize, uint16_t *startOffset) ++{ ++ uint32_t i; ++ ++ (*packetSize) = 0; ++ (*startOffset) = 0; ++ ++ for(i=0; i free_data_length ? free_data_length : (len-offset); ++ ++ memcpy(data+(*data_pos), buf+offset, copySize); ++ (*data_pos) += copySize; ++ ++ found_start = 0; ++ for(i=0; i < *data_pos; i++) ++ { ++ if((data[i] & table_mask) == table_id) ++ { ++ if(i != 0) ++ { ++ if((*data_pos)-i > i) ++ { memmove(data, &data[i], (*data_pos)-i); } ++ else ++ { memcpy(data, &data[i], (*data_pos)-i); } ++ ++ *data_pos -= i; ++ } ++ found_start = 1; ++ break; ++ } ++ } ++ if(!found_start) ++ { *flag = 0; return; } ++ ++ *flag = 2; ++ ++ if(*data_pos < 3) ++ { return; } ++ ++ section_length = SCT_LEN(data); ++ ++ if(section_length > data_length || section_length < min_table_length) ++ { *flag = 0; return; } ++ ++ if((*data_pos) < section_length) ++ { return; } ++ ++ func(cdata); ++ ++ found_start = 0; ++ for(i=section_length; i < *data_pos; i++) ++ { ++ if((data[i] & table_mask) == table_id) ++ { ++ if((*data_pos)-i > i) ++ { memmove(data, &data[i], (*data_pos)-i); } ++ else ++ { memcpy(data, &data[i], (*data_pos)-i); } ++ ++ *data_pos -= i; ++ found_start = 1; ++ break; ++ } ++ } ++ if(!found_start) ++ { *data_pos = 0; } ++ ++ *flag = 1; ++} ++ ++static void ParsePATData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->pat_data; ++ uint16_t section_length = SCT_LEN(data); ++ uint16_t srvid; ++ int32_t i; ++ ++ for(i=8; i+7srvid == srvid) ++ { ++ cdata->pmt_pid = b2i(2, data+i+2) & 0x1FFF; ++ cs_log_dbg(D_READER, "Stream %i found pmt pid: 0x%04X (%i)",cdata->connid, cdata->pmt_pid, cdata->pmt_pid); ++ break; ++ } ++ } ++} ++ ++static void ParsePMTData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->pmt_data; ++ ++ uint16_t section_length = SCT_LEN(data); ++ int32_t i; ++ uint16_t program_info_length = 0, es_info_length = 0; ++ uint8_t descriptor_tag = 0, descriptor_length = 0; ++ uint8_t stream_type; ++ uint16_t stream_pid, caid; ++ ++ cdata->pcr_pid = b2i(2, data+8) &0x1FFF; ++ if(cdata->pcr_pid != 0x1FFF) ++ { ++ cs_log_dbg(D_READER, "Stream %i found pcr pid: 0x%04X (%i)",cdata->connid, cdata->pcr_pid, cdata->pcr_pid); ++ } ++ ++ program_info_length = b2i(2, data+10) &0xFFF; ++ ++ if(12+program_info_length >= section_length) ++ { return; } ++ ++ for(i=12; i+1 < 12+program_info_length; i+=descriptor_length+2) ++ { ++ descriptor_tag = data[i]; ++ descriptor_length = data[i+1]; ++ ++ if(descriptor_length < 1) ++ { break; } ++ ++ if(i+1+descriptor_length >= 12+program_info_length) ++ { break; } ++ ++ if(descriptor_tag == 0x09 && descriptor_length >= 4) ++ { ++ caid = b2i(2, data+i+2); ++ ++ if(caid>>8 == 0x0E) ++ { ++ cdata->ecm_pid = b2i(2, data+i+4) &0x1FFF; ++ cs_log_dbg(D_READER, "Stream %i found ecm pid: 0x%04X (%i)", cdata->connid, cdata->ecm_pid, cdata->ecm_pid); ++ break; ++ } ++ } ++ } ++ ++ for(i=12+program_info_length; i+4video_pid = stream_pid; ++ cs_log_dbg(D_READER, "Stream %i found video pid: 0x%04X (%i)",cdata->connid, stream_pid, stream_pid); ++ } ++ ++ else if(stream_type == 0x03 || stream_type == 0x04 || stream_type == 0x05 || stream_type == 0x06 || ++ stream_type == 0x0F || stream_type == 0x11 || (stream_type >= 0x81 && stream_type <= 0x87) || stream_type == 0x8A) ++ { ++ if(cdata->audio_pid_count >= EMU_STREAM_MAX_AUDIO_SUB_TRACKS) ++ { continue; } ++ ++ cdata->audio_pids[cdata->audio_pid_count] = stream_pid; ++ cdata->audio_pid_count++; ++ cs_log_dbg(D_READER, "Stream %i found audio pid: 0x%04X (%i)", cdata->connid, stream_pid, stream_pid); ++ } ++ } ++} ++ ++static void ParseCATData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->cat_data; ++ uint32_t i; ++ ++ for(i = 8; i < (b2i(2, data + 1)&0xFFF) - 1; i += data[i + 1] + 2) ++ { ++ if(data[i] != 0x09) { continue; } ++ ++ uint16_t caid = b2i(2, data + i + 2); ++ uint16_t emm_pid = b2i(2, data + i +4)&0x1FFF; ++ ++ if(caid>>8 == 0x0E) ++ { ++ cdata->emm_pid = emm_pid; ++ cs_log_dbg(D_READER, "Stream %i found audio pid: 0x%04X (%i)", cdata->connid, emm_pid, emm_pid); ++ break; ++ } ++ } ++} ++ ++static void ParseEMMData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->emm_data; ++ uint32_t keysAdded = 0; ++ ++ ProcessEMM(NULL, 0x0E00, 0, data, &keysAdded); ++ ++ if(keysAdded) ++ { ++ cs_log("Stream %i found %i keys", cdata->connid, keysAdded); ++ } ++} ++ ++static void ParseECMData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->ecm_data; ++ uint16_t section_length = SCT_LEN(data); ++ uint8_t dcw[16]; ++ ++ if(section_length < 0xb) ++ { return; } ++ ++ if(data[0xb] > cdata->ecm_nb || (cdata->ecm_nb == 255 && data[0xb] == 0) ++ || ((cdata->ecm_nb - data[0xb]) > 5)) ++ { ++ cdata->ecm_nb = data[0xb]; ++#ifdef WITH_EMU ++ PowervuECM(data, dcw, cdata->srvid, &cdata->key, NULL); ++#else ++ PowervuECM(data, dcw, &cdata->key); ++#endif ++ } ++} ++ ++static void ParseTSPackets(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize) ++{ ++ uint32_t i, j, k; ++ uint32_t tsHeader; ++ uint16_t pid, offset; ++ uint8_t scramblingControl, payloadStart, oddeven; ++ int8_t oddKeyUsed; ++ uint32_t *deskey; ++ uint8_t *pdata; ++ uint8_t *packetClusterA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS][64]; // separate cluster arrays for video and each audio track ++ uint8_t *packetClusterV[256]; ++ void *csakeyA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; ++ void *csakeyV = 0; ++ emu_stream_client_key_data *keydata; ++ uint32_t scrambled_packets = 0; ++ uint32_t scrambled_packetsA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; ++ packetClusterV[0] = NULL; ++ uint32_t cs =0; // video cluster start ++ uint32_t ce =1; // video cluster end ++ uint32_t csa[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; // cluster index for audio tracks ++ ++ for(i=0; i> 8; ++ scramblingControl = tsHeader & 0xc0; ++ payloadStart = (tsHeader & 0x400000) >> 22; ++ ++ if(tsHeader & 0x20) ++ { offset = 4 + stream_buf[i+4] + 1; } ++ else ++ { offset = 4; } ++ ++ if(packetSize-offset < 1) ++ { continue; } ++ ++ if(pid == 1) ++ { ++ // set to null pid ++ stream_buf[i+1] |= 0x1f; ++ stream_buf[i+2] = 0xff; ++ ++ if(emu_stream_emm_enabled && !data->emm_pid) ++ { ++ ParseTSData(0x01, 0xFF, 8, &data->have_cat_data, data->cat_data, sizeof(data->cat_data), &data->cat_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParseCATData, data); ++ continue; ++ } ++ } ++ ++ if(emu_stream_emm_enabled && data->emm_pid && pid == data->emm_pid) ++ { ++ // set to null pid ++ stream_buf[i+1] |= 0x1f; ++ stream_buf[i+2] = 0xff; ++ ++ ParseTSData(0x80, 0xF0, 3, &data->have_emm_data, data->emm_data, sizeof(data->emm_data), &data->emm_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParseEMMData, data); ++ continue; ++ } ++ ++ if(pid == 0 && !data->pmt_pid) ++ { ++ ParseTSData(0x00, 0xFF, 16, &data->have_pat_data, data->pat_data, sizeof(data->pat_data), &data->pat_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParsePATData, data); ++ continue; ++ } ++ ++ if(!data->ecm_pid && pid == data->pmt_pid) ++ { ++ ParseTSData(0x02, 0xFF, 21, &data->have_pmt_data, data->pmt_data, sizeof(data->pmt_data), &data->pmt_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParsePMTData, data); ++ continue; ++ } ++ ++ if(data->ecm_pid && pid == data->ecm_pid) ++ { ++#ifdef WITH_EMU ++ stream_server_has_ecm[data->connid] = 1; ++#endif ++ ++ // set to null pid ++ stream_buf[i+1] |= 0x1f; ++ stream_buf[i+2] = 0xff; ++ ++ 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); ++ continue; ++ } ++ ++ if(scramblingControl == 0) ++ { continue; } ++ ++ if(!(stream_buf[i+3] & 0x10)) ++ { ++ stream_buf[i+3] &= 0x3F; ++ continue; ++ } ++ ++ oddKeyUsed = scramblingControl == 0xC0 ? 1 : 0; ++ ++#ifdef WITH_EMU ++ if(!stream_server_has_ecm[data->connid]) ++ { ++ keydata = &emu_fixed_key_data[data->connid]; ++ SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]); ++ data->key.pvu_csa_used = keydata->pvu_csa_used; ++ } ++ else ++ { ++#endif ++ keydata = &data->key; ++#ifdef WITH_EMU ++ } ++#endif ++ ++ if(keydata->pvu_csa_used) ++ { ++ oddeven = scramblingControl; // for detecting odd/even switch ++ ++ if(pid == data->video_pid) // start with video pid, since it is most dominant ++ { ++ csakeyV = keydata->pvu_csa_ks[PVU_CW_VID]; ++ ++ if(csakeyV !=NULL) ++ { ++ cs=0; ++ ce=1; ++ packetClusterV[cs] = stream_buf+i; // set first cluster start ++ packetClusterV[ce] = stream_buf+i+packetSize-1; ++ scrambled_packets=1; ++ ++ for(j = i+packetSize; j < bufLength; j += packetSize) // Now iterate through the rest of the packets and create clusters for batch decryption ++ { ++ tsHeader = b2i(4, stream_buf+j); ++ pid = (tsHeader & 0x1fff00) >> 8; ++ if(pid == data->video_pid) ++ { ++ if(oddeven != (tsHeader & 0xc0)) // changed key so stop adding clusters ++ { ++ break; ++ } ++ if(cs > ce) // First video packet for each cluster ++ { ++ packetClusterV[cs] = stream_buf+j; ++ ce = cs+1; ++ } ++ ++ scrambled_packets++; ++ } ++ else ++ { ++ if(cs < ce) // First non-video packet - need to set end of video cluster ++ { ++ packetClusterV[ce] = stream_buf+j-1; ++ cs = ce+1; ++ } ++ ++ if((tsHeader & 0xc0) == 0) { ++ continue; ++ } ++ ++ if(oddeven != (tsHeader & 0xc0)) // changed key so stop adding clusters ++ { ++ j = bufLength; // to break out of outer loop also ++ break; ++ } ++ ++ for(k = 0; k < data->audio_pid_count; k++) // Check for audio tracks and create single packet clusters ++ { ++ if(pid == data->audio_pids[k]) ++ { ++ packetClusterA[k][csa[k]] = stream_buf+j; ++ csa[k]++; ++ packetClusterA[k][csa[k]] = stream_buf+j+packetSize-1; ++ csa[k]++; ++ scrambled_packetsA[k]++; ++ } ++ } ++ } ++ } ++ ++ if( cs > ce ) // last packet was not a video packet, so set null for end of all clusters ++ { packetClusterV[cs] = NULL; } ++ else ++ { ++ if(scrambled_packets > 1) // last packet was a video packet, so set end of cluster to end of last packet ++ { ++ packetClusterV[ce] = stream_buf+j-1; ++ } ++ packetClusterV[ce+1] = NULL; // add null to end of cluster list ++ } ++ ++ while( j >= cluster_size ) ++ { j = decrypt_packets(csakeyV, packetClusterV); } ++ ++ for(k = 0; k < data->audio_pid_count; k++) ++ { ++ if(scrambled_packetsA[k]) // if audio track has scrambled packets, set null to mark end and decrypt ++ { ++ csakeyA[k] = keydata->pvu_csa_ks[PVU_CW_A1+k]; ++ packetClusterA[k][csa[k]] = NULL; ++ decrypt_packets(csakeyA[k], packetClusterA[k]); ++ csa[k]=0; ++ scrambled_packetsA[k] = 0; ++ } ++ } ++ } ++ } ++ else ++ { ++ for(j = 0; j < data->audio_pid_count; j++) ++ if(pid == data->audio_pids[j]) ++ { csakeyA[0] = keydata->pvu_csa_ks[PVU_CW_A1+j]; } ++ ++ if(csakeyA[0] != NULL) ++ { ++ packetClusterA[0][0] = stream_buf+i; ++ packetClusterA[0][1] = stream_buf+i+packetSize -1; ++ packetClusterA[0][2] = NULL; ++ decrypt_packets(csakeyA[0], packetClusterA[0]); ++ } ++ } ++ } ++ else ++ { ++ deskey = NULL; ++ ++ if(pid == data->video_pid) ++ { deskey = keydata->pvu_des_ks[PVU_CW_VID][oddKeyUsed]; } ++ else ++ { ++ for(j = 0; j < data->audio_pid_count; j++) ++ if(pid == data->audio_pids[j]) ++ { deskey = keydata->pvu_des_ks[PVU_CW_A1+j][oddKeyUsed]; } ++ } ++ ++ if(deskey == NULL) ++ { ++ deskey = keydata->pvu_des_ks[PVU_CW_HSD][oddKeyUsed]; ++ } ++ ++ for(j = offset; j+7 < 188; j += 8) ++ { ++ pdata = stream_buf+i+j; ++ des(pdata, deskey, 0); ++ } ++ ++ stream_buf[i+3] &= 0x3F; ++ } ++ ++#ifdef WITH_EMU ++ if(!stream_server_has_ecm[data->connid]) ++ { ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]); ++ } ++#endif ++ } ++} ++ ++static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path) ++{ ++ struct sockaddr_in cservaddr; ++ IN_ADDR_T in_addr; ++ ++ int32_t streamfd = socket(AF_INET, SOCK_STREAM, 0); ++ if(streamfd == -1) ++ { 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); ++ SIN_GET_ADDR(cservaddr) = in_addr; ++ cservaddr.sin_port = htons(emu_stream_source_port); ++ ++ if(connect(streamfd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1) ++ { return -1; } ++ if(emu_stream_source_auth) ++ { ++ snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n" ++ "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n" ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" ++ "Accept-Language: en-US\n" ++ "Authorization: Basic %s\n" ++ "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port, emu_stream_source_auth); ++ } ++ else ++ { ++ snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n" ++ "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n" ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" ++ "Accept-Language: en-US\n" ++ "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port); ++ } ++ ++ if(send(streamfd, http_buf, strlen(http_buf), 0) == -1) ++ { return -1; } ++ ++ return streamfd; ++} ++ ++static void stream_client_disconnect(emu_stream_client_conn_data *conndata) ++{ ++ int32_t i; ++ ++#ifdef WITH_EMU ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ emu_stream_cur_srvid[conndata->connid] = NO_SRVID_VALUE; ++ stream_server_has_ecm[conndata->connid] = 0; ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); ++#endif ++ ++ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); ++ for(i=0; iconnfd) ++ { ++ gconnfd[i] = -1; ++ gconncount--; ++ } ++ } ++ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); ++ ++ shutdown(conndata->connfd, 2); ++ close(conndata->connfd); ++ ++ cs_log("Stream client %i disconnected",conndata->connid); ++ ++ NULLFREE(conndata); ++} ++ ++static void *stream_client_handler(void *arg) ++{ ++#define EMU_DVB_MAX_TS_PACKETS 278 ++#define EMU_DVB_BUFFER_SIZE_CSA 188*EMU_DVB_MAX_TS_PACKETS ++#define EMU_DVB_BUFFER_WAIT_CSA 188*(EMU_DVB_MAX_TS_PACKETS-128) ++#define EMU_DVB_BUFFER_SIZE_DES 188*32 ++#define EMU_DVB_BUFFER_WAIT_DES 188*29 ++#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA ++ ++ emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg; ++ char *http_buf, stream_path[255], stream_path_copy[255]; ++ int32_t streamfd; ++ int32_t clientStatus, streamStatus; ++ uint8_t *stream_buf; ++ uint16_t packetCount = 0, packetSize = 0, startOffset = 0; ++ uint32_t remainingDataPos, remainingDataLength; ++ int32_t cur_dvb_buffer_size, cur_dvb_buffer_wait; ++ int32_t bytesRead = 0; ++ emu_stream_client_data *data; ++ int8_t streamConnectErrorCount = 0; ++ int8_t streamDataErrorCount = 0; ++ int32_t i, srvidtmp; ++ char *saveptr, *token; ++ char http_version[4]; ++ int32_t http_status_code = 0; ++ ++ cs_log("Stream client %i connected", conndata->connid); ++ ++ if(!cs_malloc(&http_buf, 1024)) ++ { ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ if(!cs_malloc(&stream_buf, EMU_DVB_BUFFER_SIZE)) ++ { ++ NULLFREE(http_buf); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ if(!cs_malloc(&data, sizeof(emu_stream_client_data))) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ clientStatus = recv(conndata->connfd, http_buf, 1024, 0); ++ if(clientStatus < 1) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ NULLFREE(data); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ http_buf[1023] = '\0'; ++ if(sscanf(http_buf, "GET %254s ", stream_path) < 1) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ NULLFREE(data); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ cs_strncpy(stream_path_copy, stream_path, sizeof(stream_path)); ++ ++ token = strtok_r(stream_path_copy, ":", &saveptr); ++ ++ for(i=0; token != NULL && i<3; i++) ++ { ++ token = strtok_r(NULL, ":", &saveptr); ++ if(token == NULL) ++ { break; } ++ } ++ if(token != NULL) ++ { ++ if(sscanf(token, "%x", &srvidtmp) < 1) ++ { ++ token = NULL; ++ } ++ else ++ { ++ data->srvid = srvidtmp & 0xFFFF; ++ } ++ } ++ ++ if(token == NULL) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ NULLFREE(data); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++#ifdef WITH_EMU ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ emu_stream_cur_srvid[conndata->connid] = data->srvid; ++ stream_server_has_ecm[conndata->connid] = 0; ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); ++#endif ++ ++ cs_log("Stream client %i request %s", conndata->connid, stream_path); ++ ++ snprintf(http_buf, 1024, "HTTP/1.0 200 OK\nConnection: Close\nContent-Type: video/mpeg\nServer: stream_enigma2\n\n"); ++ clientStatus = send(conndata->connfd, http_buf, strlen(http_buf), 0); ++ ++ data->connid = conndata->connid; ++ ++ while(!exit_oscam && clientStatus != -1 && streamConnectErrorCount < 3 && streamDataErrorCount < 15) ++ { ++ streamfd = connect_to_stream(http_buf, 1024, stream_path); ++ if(streamfd == -1) ++ { ++ cs_log("WARNING: stream client %i cannot connect to stream source", conndata->connid); ++ streamConnectErrorCount++; ++ cs_sleepms(500); ++ continue; ++ } ++ ++ streamStatus = 0; ++ bytesRead = 0; ++ ++ while(!exit_oscam && clientStatus != -1 && streamStatus != -1 && streamConnectErrorCount < 3 && streamDataErrorCount < 15) ++ { ++ if(data->key.pvu_csa_used) ++ { ++ cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_CSA; ++ cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_CSA; ++ } ++ 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 ++ { ++ cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid); ++ streamConnectErrorCount++; ++ cs_sleepms(100); ++ break; ++ } ++ ++ if(streamStatus < 0) // error ++ { ++ if ((errno == EWOULDBLOCK) | (errno == EAGAIN)) { ++ cs_log("WARNING: stream client %i no data from stream source", conndata->connid); ++ streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close ++ cs_sleepms(100); ++ continue; ++ } ++ ++ 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 ++ { ++ if(!bytesRead && streamStatus > 13 && ++ sscanf((const char*)stream_buf, "HTTP/%3s %d ", http_version , &http_status_code) == 2 && ++ http_status_code != 200) ++ { ++ cs_log("ERROR: stream client %i got %d response from stream source", conndata->connid, http_status_code); ++ streamConnectErrorCount++; ++ cs_sleepms(100); ++ break; ++ } ++ else ++ { ++ cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid); ++ streamDataErrorCount++; ++ cs_sleepms(100); ++ } ++ } ++ else ++ { ++ streamDataErrorCount = 0; ++ } ++ ++ streamConnectErrorCount = 0; ++ bytesRead += streamStatus; ++ ++ if(bytesRead >= cur_dvb_buffer_wait) ++ { ++ startOffset = 0; ++ if(stream_buf[0] != 0x47 || packetSize == 0) // only search if not starting on ts packet or unknown packet size ++ { ++ SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset); ++ } ++ if(packetSize == 0) ++ { ++ bytesRead = 0; ++ } ++ else ++ { ++ packetCount = ((bytesRead-startOffset) / packetSize); ++ ++ ParseTSPackets(data, stream_buf+startOffset, packetCount*packetSize, packetSize); ++ ++ clientStatus = send(conndata->connfd, stream_buf+startOffset, packetCount*packetSize, 0); ++ ++ remainingDataPos = startOffset+(packetCount*packetSize); ++ remainingDataLength = bytesRead-remainingDataPos; ++ ++ if(remainingDataPos < remainingDataLength) ++ { memmove(stream_buf, stream_buf+remainingDataPos, remainingDataLength); } ++ else ++ { memcpy(stream_buf, stream_buf+remainingDataPos, remainingDataLength); } ++ ++ bytesRead = remainingDataLength; ++ } ++ } ++ } ++ ++ close(streamfd); ++ } ++ ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ for(i=0; i<8; i++) ++ { ++ if(data->key.pvu_csa_ks[i]) ++ { free_key_struct(data->key.pvu_csa_ks[i]); } ++ } ++ NULLFREE(data); ++ ++ stream_client_disconnect(conndata); ++ return NULL; ++} ++ ++void *stream_server(void *UNUSED(a)) ++{ ++ struct sockaddr_in servaddr, cliaddr; ++ socklen_t clilen; ++ int32_t connfd, reuse = 1, i; ++ int8_t connaccepted; ++ emu_stream_client_conn_data *conndata; ++ ++ cluster_size = get_internal_parallelism(); ++ cs_log("INFO: FFDecsa parallel mode = %d", cluster_size); ++ ++ if(!emu_stream_server_mutex_init) ++ { ++ SAFE_MUTEX_INIT(&emu_stream_server_mutex, NULL); ++ emu_stream_server_mutex_init = 1; ++ } ++ ++#ifdef WITH_EMU ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ for(i=0; iconnfd = connfd; ++ conndata->connid = i; ++ ++ break; ++ } ++ } ++ } ++ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); ++ } ++ ++ if(connaccepted) ++ { ++ int on = 1; ++ if(setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) ++ { ++ cs_log("ERROR: stream client %i setsockopt() failed for TCP_NODELAY", conndata->connid); ++ } ++ ++ start_thread("emu stream client", stream_client_handler, (void*)conndata, NULL, 1, 0); ++ } ++ else ++ { ++ shutdown(connfd, 2); ++ close(connfd); ++ cs_log("ERROR: stream server client dropped because of too many connections (%i)", EMU_STREAM_SERVER_MAX_CONNECTIONS); ++ } ++ ++ cs_sleepms(20); ++ } ++ ++ close(glistenfd); ++ ++ return NULL; ++} ++ ++#ifdef WITH_EMU ++void *stream_key_delayer(void *UNUSED(arg)) ++{ ++ int32_t i, j; ++ emu_stream_client_key_data* cdata; ++ LL_ITER it; ++ emu_stream_cw_item *item; ++ struct timeb t_now; ++ ++ while(!exit_oscam) ++ { ++ cs_ftime(&t_now); ++ ++ for(i=0; iwrite_time) < 0) ++ { ++ break; ++ } ++ ++ SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[i]); ++ ++ cdata = &emu_fixed_key_data[i]; ++ ++ for(j=0; j<8; j++) ++ { ++ if(item->csa_used) ++ { ++ if(cdata->pvu_csa_ks[j] == NULL) ++ { cdata->pvu_csa_ks[j] = get_key_struct(); } ++ ++ if(item->is_even) ++ { set_even_control_word(cdata->pvu_csa_ks[j], item->cw[j]); } ++ else ++ { set_odd_control_word(cdata->pvu_csa_ks[j], item->cw[j]); } ++ ++ cdata->pvu_csa_used = 1; ++ } ++ else ++ { ++ if(item->is_even) ++ { des_set_key(item->cw[j], cdata->pvu_des_ks[j][0]); } ++ else ++ { des_set_key(item->cw[j], cdata->pvu_des_ks[j][1]); } ++ ++ cdata->pvu_csa_used = 0; ++ } ++ } ++ ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[i]); ++ ++ ll_iter_remove_data(&it); ++ } ++ } ++ ++ cs_sleepms(25); ++ } ++ ++ return NULL; ++} ++#endif ++ ++void stop_stream_server(void) ++{ ++ int32_t i; ++ ++ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); ++ for(i=0; ityp == R_EMU) ++ { ++ usr_filter = * get_emu_prids_for_caid(aureader, cfg.ncd_ptab.ports[cl->port_idx].ncd->ncd_ftab.filts[0].caid); ++ } ++ else ++#endif + mk_user_au_ftab(aureader, &usr_filter); + } + +@@ -948,6 +955,13 @@ static int8_t newcamd_auth_client(IN_ADD + else + { memset(&mbuf[8], 0, 6); } //mbuf[8] - mbuf[13] + ++#ifdef WITH_EMU ++ if(aureader && aureader->typ == R_EMU && caid_is_dre(pufilt->caid)) ++ { ++ mbuf[10] = aureader->dre36_force_group; ++ } ++#endif ++ + mbuf[14] = pufilt->nprids; + for(j = 0; j < pufilt->nprids; j++) + { +@@ -973,7 +987,7 @@ static int8_t newcamd_auth_client(IN_ADD + int32_t k, found; + uint32_t rprid; + found = 0; +- if(pufilt->caid == aureader->caid) ++ if(pufilt->caid == aureader->caid && aureader->typ != R_EMU) + { + for(k = 0; (k < aureader->nprov); k++) + { +@@ -999,6 +1013,32 @@ static int8_t newcamd_auth_client(IN_ADD + } + } + } ++#ifdef WITH_EMU ++ else if(aureader->typ == R_EMU) ++ { ++ if(caid_is_dre(pufilt->caid)) ++ { ++ found = 1; ++ memset(&mbuf[22 + 11 * j] ,0 ,4); ++ switch((uchar)(pufilt->prids[j])) ++ { ++ case 0x11: ++ mbuf[22 + 11 * j] = aureader->dre36_force_group; ++ break; ++ case 0x14: ++ mbuf[22 + 11 * j] = aureader->dre56_force_group; ++ break; ++ case 0xfe: ++ mbuf[22 + 11 * j] = 0xED; ++ mbuf[25 + 11 * j] = 0x02; ++ break; ++ default: ++ found = 0; ++ } ++ } ++ } ++#endif ++ + if(!found) + { + mbuf[22 + 11 * j] = 0x00; +diff -ruNp trunk.patches/module-newcamd-des.c trunk/module-newcamd-des.c +--- trunk.patches/module-newcamd-des.c 2018-04-03 02:44:10.106269046 +0300 ++++ trunk/module-newcamd-des.c 2018-04-03 03:20:07.662045399 +0300 +@@ -5,10 +5,7 @@ + #define DES_IP 1 + #define DES_IP_1 2 + #define DES_RIGHT 4 +-#define DES_HASH 8 + +-#define DES_ECM_CRYPT 0 +-#define DES_ECM_HASH DES_HASH + #define DES_ECS2_DECRYPT (DES_IP | DES_IP_1 | DES_RIGHT) + #define DES_ECS2_CRYPT (DES_IP | DES_IP_1) + +@@ -356,7 +353,7 @@ static void desRound(unsigned char left[ + swap(data - 4, data); + } + +-static void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]) ++void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]) + { + unsigned char i; + unsigned char left[8]; +diff -ruNp trunk.patches/module-newcamd-des.h trunk/module-newcamd-des.h +--- trunk.patches/module-newcamd-des.h 2018-04-03 02:44:10.214269951 +0300 ++++ trunk/module-newcamd-des.h 2018-04-03 03:20:07.662045399 +0300 +@@ -1,8 +1,15 @@ + #ifndef MODULE_NEWCAMD_DES_H_ + #define MODULE_NEWCAMD_DES_H_ + ++#define DES_HASH 8 ++ ++#define DES_ECM_CRYPT 0 ++#define DES_ECM_HASH DES_HASH ++ + int nc_des_encrypt(unsigned char *buffer, int len, unsigned char *deskey); + int nc_des_decrypt(unsigned char *buffer, int len, unsigned char *deskey); + unsigned char *nc_des_login_key_get(unsigned char *key1, unsigned char *key2, int len, unsigned char *des16); + ++ void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]); ++ + #endif +diff -ruNp trunk.patches/module-stat.c trunk/module-stat.c +--- trunk.patches/module-stat.c 2018-04-03 02:44:09.474263747 +0300 ++++ trunk/module-stat.c 2018-04-03 03:20:07.662045399 +0300 +@@ -903,7 +903,7 @@ void check_lb_auto_betatunnel_mode(ECM_R + + uint16_t get_rdr_caid(struct s_reader *rdr) + { +- if(is_network_reader(rdr)) ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) + { + return 0; //reader caid is not real caid + } +@@ -1301,7 +1301,7 @@ void stat_get_best_reader(ECM_REQUEST *e + for(ea = er->matching_rdr; ea; ea = ea->next) + { + rdr = ea->reader; +- if(is_network_reader(rdr)) //reader caid is not real caid ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) //reader caid is not real caid + { + prv = ea; + continue; // proxy can convert or reject +diff -ruNp trunk.patches/module-webif.c trunk/module-webif.c +--- trunk.patches/module-webif.c 2018-04-03 02:44:08.458255227 +0300 ++++ trunk/module-webif.c 2018-04-03 03:20:07.662045399 +0300 +@@ -101,6 +101,7 @@ static bool use_srvid2 = false; + #define MNU_CFG_LCD 14 + #define MNU_CFG_MONITOR 15 + #define MNU_CFG_WEBIF 16 ++#define MNU_CFG_STREAMRELAY 17 + + /* constants for files.html submenuactivating */ + #define MNU_CFG_FVERSION 0 +@@ -134,8 +135,9 @@ static bool use_srvid2 = false; + #define MNU_GBX_FSTAINF 27 + #define MNU_GBX_FEXPINF 28 + #define MNU_GBX_INFOLOG 29 ++#define MNU_CFG_FSOFTCAMKEY 30 + +-#define MNU_CFG_TOTAL_ITEMS 30 // sum of items above. Use it for "All inactive" in function calls too. ++#define MNU_CFG_TOTAL_ITEMS 31 // sum of config or files items above. Use it for "All inactive" in function calls too. + + static void set_status_info_var(struct templatevars *vars, char *varname, int no_data, char *fmt, double value) { + if (no_data) +@@ -1219,6 +1221,34 @@ static char *send_oscam_config_scam(stru + } + #endif + ++#ifdef WITH_EMU ++#include "module-emulator-stream.h" ++ ++static char *send_oscam_config_streamrelay(struct templatevars *vars, struct uriparams *params) ++{ ++ setActiveSubMenu(vars, MNU_CFG_STREAMRELAY); ++ ++ webif_save_config("streamrelay", vars, params); ++ ++ tpl_printf(vars, TPLADD, "STREAM_SOURCE_HOST", "%s", cfg.emu_stream_source_host); ++ tpl_printf(vars, TPLADD, "STREAM_SOURCE_PORT", "%d", cfg.emu_stream_source_port); ++ if(cfg.emu_stream_source_auth_user) ++ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_USER", "%s", cfg.emu_stream_source_auth_user); } ++ if(cfg.emu_stream_source_auth_password) ++ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_PASSWORD", "%s", cfg.emu_stream_source_auth_password); } ++ tpl_printf(vars, TPLADD, "STREAM_RELAY_PORT", "%d", cfg.emu_stream_relay_port); ++ tpl_printf(vars, TPLADD, "STREAM_ECM_DELAY", "%d", cfg.emu_stream_ecm_delay); ++ ++ tpl_printf(vars, TPLADD, "TMP", "STREAMRELAYENABLEDSELECTED%d", cfg.emu_stream_relay_enabled); ++ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); ++ ++ tpl_printf(vars, TPLADD, "TMP", "STREAMEMMENABLEDSELECTED%d", cfg.emu_stream_emm_enabled); ++ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); ++ ++ return tpl_getTpl(vars, "CONFIGSTREAMRELAY"); ++} ++#endif ++ + #ifdef MODULE_CCCAM + static char *send_oscam_config_cccam(struct templatevars *vars, struct uriparams *params) + { +@@ -1557,6 +1587,10 @@ static char *send_oscam_config_dvbapi(st + tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWAPISELECTED%d", cfg.dvbapi_extended_cw_api); + tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); + ++ //extended_cw_pids (pid limiter) ++ tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWPIDSSELECTED%d", cfg.dvbapi_extended_cw_pids); ++ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); ++ + //write_sdt_prov + if(cfg.dvbapi_write_sdt_prov > 0) + { tpl_addVar(vars, TPLADD, "WRITESDTPROVCHECKED", "checked"); } +@@ -1634,6 +1668,9 @@ static char *send_oscam_config(struct te + #ifdef MODULE_SCAM + else if(!strcmp(part, "scam")) { return send_oscam_config_scam(vars, params); } + #endif ++#ifdef WITH_EMU ++ else if(!strcmp(part, "streamrelay")) { return send_oscam_config_streamrelay(vars, params); } ++#endif + #ifdef MODULE_CCCAM + else if(!strcmp(part, "cccam")) { return send_oscam_config_cccam(vars, params); } + #endif +@@ -2096,7 +2133,7 @@ static char *send_oscam_reader_config(st + chk_reader("services", servicelabels, rdr); + chk_reader("lb_whitelist_services", servicelabelslb, rdr); + +- if(is_network_reader(rdr)) //physical readers make trouble if re-started ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) //physical readers make trouble if re-started + { + restart_cardreader(rdr, 1); + } +@@ -2674,6 +2711,31 @@ static char *send_oscam_reader_config(st + tpl_addVar(vars, TPLADD, "USERSCRIPT", rdr->userscript); + #endif + ++#ifdef WITH_EMU ++ //emu_auproviders ++ value = mk_t_ftab(&rdr->emu_auproviders); ++ tpl_addVar(vars, TPLADD, "EMUAUPROVIDERS", value); ++ free_mk_t(value); ++ ++ // Date-coded BISS keys ++ if(!apicall) ++ { ++ tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "checked" : ""); ++ } ++ else ++ { ++ tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "1" : "0"); ++ } ++ ++ //extee ++ tpl_addVar(vars, TPLADD, "EXTEE36", rdr->extee36); ++ tpl_addVar(vars, TPLADD, "EXTEE56", rdr->extee56); ++ ++ //dre force group ++ tpl_printf(vars, TPLADD, "DRE36FORCEGROUP","%02X", rdr->dre36_force_group); ++ tpl_printf(vars, TPLADD, "DRE56FORCEGROUP","%02X", rdr->dre56_force_group); ++#endif ++ + tpl_addVar(vars, TPLADD, "PROTOCOL", reader_get_type_desc(rdr, 0)); + + // Show only parameters which needed for the reader +@@ -2695,6 +2757,9 @@ static char *send_oscam_reader_config(st + case R_CAMD35 : + tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCAMD35BIT")); + break; ++ case R_EMU : ++ tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGEMUBIT")); ++ break; + case R_CS378X : + tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCS378XBIT")); + break; +@@ -4417,9 +4482,38 @@ static char *send_oscam_entitlement(stru + + tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", "

New Structure:
"); + char tbuffer[83]; ++#ifdef WITH_EMU ++ char keyBuffer[1024]; ++#endif + int jsondelimiter = 0; + while((item = ll_iter_next(&itr))) + { ++#ifdef WITH_EMU ++ if(item->isKey) { ++ tpl_addVar(vars, TPLADD, "ENTSTARTDATE", ""); ++ tpl_addVar(vars, TPLADD, "ENTENDDATE", ""); ++ cs_hexdump(0, item->key, item->keyLength, keyBuffer, sizeof(keyBuffer)); ++ tpl_addVar(vars, TPLADD, "ENTEXPIERED", "e_valid"); ++ tpl_printf(vars, TPLADD, "ENTCAID", "%04X", item->caid); ++ if(item->caid == 0x2600) { ++ tpl_printf(vars, TPLADD, "ENTPROVID", "%08X", item->provid); ++ } ++ else { ++ tpl_printf(vars, TPLADD, "ENTPROVID", "%06X", item->provid); ++ } ++ tpl_addVar(vars, TPLADD, "ENTID", item->name); ++ tpl_addVar(vars, TPLADD, "ENTCLASS", keyBuffer); ++ if(item->isData) { tpl_addVar(vars, TPLADD, "ENTTYPE", "data"); } ++ else { tpl_addVar(vars, TPLADD, "ENTTYPE", "key"); } ++ tpl_addVar(vars, TPLADD, "ENTRESNAME", ""); ++ ++ if((strcmp(getParam(params, "hideexpired"), "1") != 0) || (item->end > now)) ++ { tpl_addVar(vars, TPLAPPEND, "READERENTENTRY", tpl_getTpl(vars, "ENTITLEMENTITEMBIT")); } ++ ++ continue; ++ } ++#endif ++ + localtime_r(&item->start, &start_t); + localtime_r(&item->end, &end_t); + +@@ -4895,6 +4989,9 @@ static char *send_oscam_status(struct te + #else + filtered = (type == cl->typ); + #endif ++#ifdef WITH_EMU ++ if(type == 'e' && cl->typ == 'r' && cl->reader->typ == R_EMU) filtered = 1; ++#endif + } + } + +@@ -6339,6 +6436,9 @@ static char *send_oscam_files(struct tem + { "expired.info", MNU_GBX_FEXPINF, FTYPE_GBOX }, // id 28 + { "info.log", MNU_GBX_INFOLOG, FTYPE_GBOX }, // id 29 + #endif ++#ifdef WITH_EMU ++ { "SoftCam.Key", MNU_CFG_FSOFTCAMKEY,FTYPE_CONFIG }, // id 30 ++#endif + { NULL, 0, 0 }, + }; + +@@ -6809,7 +6909,7 @@ static char *send_oscam_EMM_running(stru + else if(!proxy && rdr->csystem_active) // local active reader + { + csystem = rdr->csystem; +- caid = rdr->caid; ++ if(rdr->typ != R_EMU) caid = rdr->caid; + } + + if(csystem) +@@ -7816,8 +7916,8 @@ static int32_t readRequest(FILE * f, IN_ + memcpy(*result + bufsize, buf2, n); + bufsize += n; + +- //max request size 100kb +- if(bufsize > 102400) ++ //max request size 200kb ++ if(bufsize > 204800) + { + cs_log("error: too much data received from %s", cs_inet_ntoa(in)); + NULLFREE(*result); +diff -ruNp trunk.patches/module-webif-tpl.c trunk/module-webif-tpl.c +--- trunk.patches/module-webif-tpl.c 2018-04-03 02:44:09.754266095 +0300 ++++ trunk/module-webif-tpl.c 2018-04-03 03:20:07.662045399 +0300 +@@ -457,6 +457,7 @@ char *tpl_getUnparsedTpl(const char *nam + check_conf(WITH_SSL, ptr2); + check_conf(WITH_STAPI, ptr2); + check_conf(WITH_STAPI5, ptr2); ++ check_conf(WITH_EMU, ptr2); + } // for + if(ok == 0) + { +diff -ruNp trunk.patches/oscam-aes.c trunk/oscam-aes.c +--- trunk.patches/oscam-aes.c 2018-04-03 02:44:10.106269046 +0300 ++++ trunk/oscam-aes.c 2018-04-03 03:20:07.662045399 +0300 +@@ -37,6 +37,16 @@ void aes_encrypt_idx(struct aes_keys *ae + } + } + ++void aes_cbc_encrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv) ++{ ++ AES_cbc_encrypt(buf, buf, n, &aes->aeskey_encrypt, iv, AES_ENCRYPT); ++} ++ ++void aes_cbc_decrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv) ++{ ++ AES_cbc_encrypt(buf, buf, n, &aes->aeskey_decrypt, iv, AES_DECRYPT); ++} ++ + /* Creates an AES_ENTRY and adds it to the given linked list. */ + void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey) + { +diff -ruNp trunk.patches/oscam-aes.h trunk/oscam-aes.h +--- trunk.patches/oscam-aes.h 2018-04-03 02:44:10.110269080 +0300 ++++ trunk/oscam-aes.h 2018-04-03 03:20:07.662045399 +0300 +@@ -5,6 +5,8 @@ void aes_set_key(struct aes_keys *aes, c + bool aes_set_key_alloc(struct aes_keys **aes, char *key); + void aes_decrypt(struct aes_keys *aes, uchar *buf, int32_t n); + void aes_encrypt_idx(struct aes_keys *aes, uchar *buf, int32_t n); ++void aes_cbc_encrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv); ++void aes_cbc_decrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv); + + void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey); + void parse_aes_entry(AES_ENTRY **list, char *label, char *value); +diff -ruNp trunk.patches/oscam.c trunk/oscam.c +--- trunk.patches/oscam.c 2018-04-03 03:10:28.813703490 +0300 ++++ trunk/oscam.c 2018-04-03 03:20:07.662045399 +0300 +@@ -41,6 +41,11 @@ + #include "reader-common.h" + #include "module-gbox.h" + ++#ifdef WITH_EMU ++ void add_emu_reader(void); ++ void stop_stream_server(void); ++#endif ++ + #ifdef WITH_SSL + #include + #include +@@ -422,6 +427,7 @@ static void write_versionfile(bool use_s + write_conf(CW_CYCLE_CHECK, "CW Cycle Check support"); + write_conf(LCDSUPPORT, "LCD support"); + write_conf(LEDSUPPORT, "LED support"); ++ write_conf(WITH_EMU, "Emulator support"); + switch (cs_getclocktype()) { + case CLOCK_TYPE_UNKNOWN : write_conf(CLOCKFIX, "Clockfix with UNKNOWN clock"); break; + case CLOCK_TYPE_REALTIME : write_conf(CLOCKFIX, "Clockfix with realtime clock"); break; +@@ -1640,6 +1646,9 @@ const struct s_cardreader *cardreaders[] + #ifdef CARDREADER_STINGER + &cardreader_stinger, + #endif ++#ifdef WITH_EMU ++ &cardreader_emu, ++#endif + NULL + }; + +@@ -1811,6 +1820,9 @@ int32_t main(int32_t argc, char *argv[]) + + init_sidtab(); + init_readerdb(); ++#ifdef WITH_EMU ++ add_emu_reader(); ++#endif + cfg.account = init_userdb(); + init_signal(); + init_provid(); +@@ -1898,6 +1910,9 @@ int32_t main(int32_t argc, char *argv[]) + if(!cfg.gsms_dis) + { stop_sms_sender(); } + #endif ++#ifdef WITH_EMU ++ stop_stream_server(); ++#endif + webif_close(); + azbox_close(); + coolapi_close_all(); +diff -ruNp trunk.patches/oscam-chk.c trunk/oscam-chk.c +--- trunk.patches/oscam-chk.c 2018-04-03 02:44:09.470263713 +0300 ++++ trunk/oscam-chk.c 2018-04-03 03:20:07.662045399 +0300 +@@ -758,7 +758,7 @@ int32_t matching_reader(ECM_REQUEST *er, + return 0; + } + +- if(!is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) ++ if(!(rdr->typ == R_EMU) && !is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) + { + if (!rdr->csystem) + return 0; +@@ -794,7 +794,7 @@ int32_t matching_reader(ECM_REQUEST *er, + } + + //Checking ident: +- if(!chk_rfilter(er, rdr)) ++ if(!(rdr->typ == R_EMU && (er->caid>>8 == 0x26 || er->caid == 0xFFFF)) && !chk_rfilter(er, rdr)) + { + cs_log_dbg(D_TRACE, "r-filter reader %s", rdr->label); + return (0); +@@ -853,7 +853,7 @@ int32_t matching_reader(ECM_REQUEST *er, + } + + //Checking entitlements: +- if(ll_count(rdr->ll_entitlements) > 0) ++ if(ll_count(rdr->ll_entitlements) > 0 && !(rdr->typ == R_EMU)) + { + LL_ITER itr = ll_iter_create(rdr->ll_entitlements); + S_ENTITLEMENT *item; +@@ -1024,7 +1024,7 @@ int32_t chk_caid(uint16_t caid, CAIDTAB + + int32_t chk_caid_rdr(struct s_reader *rdr, uint16_t caid) + { +- if(is_network_reader(rdr)) ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) + { + return 1; //reader caid is not real caid + } +diff -ruNp trunk.patches/oscam-config-global.c trunk/oscam-config-global.c +--- trunk.patches/oscam-config-global.c 2018-04-03 02:44:08.394254690 +0300 ++++ trunk/oscam-config-global.c 2018-04-03 03:20:07.662045399 +0300 +@@ -854,6 +854,30 @@ static const struct config_list scam_opt + #else + static const struct config_list scam_opts[] = { DEF_LAST_OPT }; + #endif ++ ++#ifdef WITH_EMU ++static bool streamrelay_should_save_fn(void *UNUSED(var)) ++{ ++ return 1; ++} ++static const struct config_list streamrelay_opts[] = ++{ ++ DEF_OPT_SAVE_FUNC(streamrelay_should_save_fn), ++ DEF_OPT_STR("stream_source_host" , OFS(emu_stream_source_host), "127.0.0.1"), ++ DEF_OPT_INT32("stream_source_port" , OFS(emu_stream_source_port), 8001), ++ DEF_OPT_STR("stream_source_auth_user" , OFS(emu_stream_source_auth_user), NULL), ++ DEF_OPT_STR("stream_source_auth_password" , OFS(emu_stream_source_auth_password), NULL), ++ DEF_OPT_INT32("stream_relay_port" , OFS(emu_stream_relay_port), 17999), ++ DEF_OPT_UINT32("stream_ecm_delay" , OFS(emu_stream_ecm_delay), 600), ++ DEF_OPT_INT8("stream_relay_enabled" , OFS(emu_stream_relay_enabled), 1), ++ DEF_OPT_INT8("stream_emm_enabled" , OFS(emu_stream_emm_enabled), 1), ++ DEF_LAST_OPT ++}; ++#else ++static const struct config_list streamrelay_opts[] = { DEF_LAST_OPT }; ++#endif ++ ++ + #ifdef MODULE_RADEGAST + static bool radegast_should_save_fn(void *UNUSED(var)) + { +@@ -1262,6 +1286,7 @@ static const struct config_list dvbapi_o + DEF_OPT_INT8("read_sdt" , OFS(dvbapi_read_sdt), 0), + DEF_OPT_INT8("write_sdt_prov", OFS(dvbapi_write_sdt_prov), 0), + DEF_OPT_INT8("extended_cw_api", OFS(dvbapi_extended_cw_api), 0), ++ DEF_OPT_INT8("extended_cw_pids", OFS(dvbapi_extended_cw_pids), 64), // pid limiter + DEF_OPT_FUNC("boxtype" , OFS(dvbapi_boxtype), dvbapi_boxtype_fn), + DEF_OPT_FUNC("services" , OFS(dvbapi_sidtabs.ok), dvbapi_services_fn), + // OBSOLETE OPTIONS +@@ -1315,6 +1340,7 @@ static const struct config_sections osca + { "cccam", cccam_opts }, + { "pandora", pandora_opts }, + { "scam", scam_opts }, ++ { "streamrelay", streamrelay_opts }, + { "dvbapi", dvbapi_opts }, + { "monitor", monitor_opts }, + { "webif", webif_opts }, +diff -ruNp trunk.patches/oscam-config.h trunk/oscam-config.h +--- trunk.patches/oscam-config.h 2018-04-03 02:44:09.470263713 +0300 ++++ trunk/oscam-config.h 2018-04-03 03:20:07.662045399 +0300 +@@ -22,6 +22,7 @@ void free_reader(struct s_reader *rdr + int32_t free_readerdb(void); + int32_t write_server(void); + void reload_readerdb(void); ++void reader_fixups_fn(void *var); + + void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab); + int32_t init_sidtab(void); +@@ -63,7 +64,8 @@ enum ftab_fn + FTAB_FBPCAID = 0x10, + FTAB_LOCALCARDS = 0x20, + FTAB_IGNCHKSMCAID = 0x40, +- FTAB_IGNCRCCEX4USERONLYFOR = 0x80 ++ FTAB_IGNCRCCEX4USERONLYFOR = 0x80, ++ FTAB_EMUAU = 0x100 + }; + + void ftab_fn(const char *token, char *value, void *setting, long ftab_type, FILE *f); +diff -ruNp trunk.patches/oscam-config-reader.c trunk/oscam-config-reader.c +--- trunk.patches/oscam-config-reader.c 2018-04-03 02:44:09.758266128 +0300 ++++ trunk/oscam-config-reader.c 2018-04-03 03:20:07.662045399 +0300 +@@ -109,6 +109,7 @@ static void protocol_fn(const char *toke + { "newcamd525", R_NEWCAMD }, + { "newcamd524", R_NEWCAMD }, + { "drecas", R_DRECAS }, ++ { "emu", R_EMU }, + { NULL , 0 } + }, *p; + int i; +@@ -448,6 +449,9 @@ void ftab_fn(const char *token, char *va + if(ftab_type & FTAB_FBPCAID) { rdr = container_of(setting, struct s_reader, fallback_percaid); } + if(ftab_type & FTAB_LOCALCARDS) { rdr = container_of(setting, struct s_reader, localcards); } + if(ftab_type & FTAB_IGNCHKSMCAID){ rdr = container_of(setting, struct s_reader, disablecrccws_only_for); } ++#ifdef WITH_EMU ++ if(ftab_type & FTAB_EMUAU) { rdr = container_of(setting, struct s_reader, emu_auproviders); } ++#endif + if(rdr) + { rdr->changes_since_shareupdate = 1; } + } +@@ -779,7 +783,7 @@ static void cooldowntime_fn(const char * + } + + +-static void reader_fixups_fn(void *var) ++void reader_fixups_fn(void *var) + { + struct s_reader *rdr = var; + #ifdef WITH_LB +@@ -923,6 +927,14 @@ static const struct config_list reader_o + #ifdef READER_DRECAS + DEF_OPT_STR("stmkeys" , OFS(stmkeys), NULL), + #endif ++#ifdef WITH_EMU ++ DEF_OPT_FUNC_X("emu_auproviders" , OFS(emu_auproviders), ftab_fn, FTAB_READER | FTAB_EMUAU), ++ DEF_OPT_INT8("emu_datecodedenabled" , OFS(emu_datecodedenabled), 0), ++ DEF_OPT_STR("extee36" , OFS(extee36), NULL), ++ DEF_OPT_STR("extee56" , OFS(extee56), NULL), ++ DEF_OPT_HEX("dre36_force_group" , OFS(dre36_force_group), 1), ++ DEF_OPT_HEX("dre56_force_group" , OFS(dre56_force_group), 1), ++#endif + DEF_OPT_INT8("deprecated" , OFS(deprecated), 0), + DEF_OPT_INT8("audisabled" , OFS(audisabled), 0), + DEF_OPT_FUNC("auprovid" , 0, auprovid_fn), +diff -ruNp trunk.patches/oscam-ecm.c trunk/oscam-ecm.c +--- trunk.patches/oscam-ecm.c 2018-04-03 02:44:08.174252846 +0300 ++++ trunk/oscam-ecm.c 2018-04-03 03:20:07.662045399 +0300 +@@ -1585,7 +1585,7 @@ int32_t write_ecm_answer(struct s_reader + + if(reader && cw && rc < E_NOTFOUND) + { +- if(cfg.disablecrccws == 0 && reader->disablecrccws == 0) ++ if(cfg.disablecrccws == 0 && reader->disablecrccws == 0 && ((er->caid >> 8) != 0x0E)) + { + uint8_t selectedForIgnChecksum = chk_if_ignore_checksum(er, cfg.disablecrccws, &cfg.disablecrccws_only_for) + + chk_if_ignore_checksum(er, reader->disablecrccws, &reader->disablecrccws_only_for); +diff -ruNp trunk.patches/oscam-emm.c trunk/oscam-emm.c +--- trunk.patches/oscam-emm.c 2018-04-03 02:44:09.758266128 +0300 ++++ trunk/oscam-emm.c 2018-04-03 03:20:07.662045399 +0300 +@@ -50,7 +50,14 @@ static int8_t do_simple_emm_filter(struc + unsigned int j, filter_count = 0; + + // Call cardsystems emm filter +- csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ if(rdr->typ == R_EMU) ++ { ++ return 1; //valid emm ++ } ++ else ++ { ++ csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ } + + // Only check matching emmtypes: + uint8_t org_emmtype; +@@ -209,6 +216,24 @@ int32_t emm_reader_match(struct s_reader + rdr_log_dbg(reader, D_EMM, "reader auprovid = %06X fixup to %06X (ignoring last digit)", reader->auprovid, prid); + } + ++#ifdef WITH_EMU ++ if(reader->typ == R_EMU) ++ { ++ FILTER* emu_provids = get_emu_prids_for_caid(reader, caid); ++ if(emu_provids != NULL) ++ { ++ for(i = 0; i < emu_provids->nprids; i++) ++ { ++ if(provid == emu_provids->prids[i]) ++ { ++ return 1; ++ } ++ } ++ } ++ return 0; ++ } ++#endif ++ + if(prid == provid) + { + rdr_log_dbg(reader, D_EMM, "reader auprovid = %06X matching with emm provid = %06X -> SEND!", prid, provid); +diff -ruNp trunk.patches/oscam-string.c trunk/oscam-string.c +--- trunk.patches/oscam-string.c 2018-04-03 02:44:09.762266162 +0300 ++++ trunk/oscam-string.c 2018-04-03 03:20:07.662045399 +0300 +@@ -510,6 +510,62 @@ uint32_t crc32(uint32_t crc, const uint8 + return crc ^ 0xffffffffL; + } + ++static uint32_t fletcher_crc_table[256] = { ++ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, ++ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, ++ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, ++ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, ++ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, ++ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, ++ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, ++ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, ++ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, ++ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, ++ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, ++ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, ++ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, ++ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, ++ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, ++ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, ++ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, ++ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, ++ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, ++ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, ++ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, ++ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, ++ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, ++ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, ++ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, ++ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, ++ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, ++ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, ++ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, ++ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, ++ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, ++ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, ++ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, ++ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, ++ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, ++ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, ++ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, ++ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, ++ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, ++ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, ++ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, ++ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, ++ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; ++ ++uint32_t fletcher_crc32(uint8_t *data, uint32_t len) ++{ ++ uint32_t i; ++ uint32_t crc = 0xffffffff; ++ ++ for (i=0; i> 24) ^ *data++) & 0xff]; ++ ++ return crc; ++} ++ + static uint16_t ccitt_crc_table [256] = + { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, +diff -ruNp trunk.patches/oscam-string.h trunk/oscam-string.h +--- trunk.patches/oscam-string.h 2018-04-03 02:44:10.090268912 +0300 ++++ trunk/oscam-string.h 2018-04-03 03:20:07.662045399 +0300 +@@ -37,6 +37,7 @@ void get_random_bytes_init(void); + void get_random_bytes(uint8_t *dst, uint32_t dst_len); + + uint32_t crc32(uint32_t crc, const uint8_t *buf, uint32_t len); ++uint32_t fletcher_crc32(uint8_t *data, uint32_t len); + uint16_t ccitt_crc(uint8_t *data, size_t length, uint16_t seed, uint16_t final); + uint32_t jhash(const char *key, size_t len); + +diff -ruNp trunk.patches/reader-common.c trunk/reader-common.c +--- trunk.patches/reader-common.c 2018-04-03 02:44:09.758266128 +0300 ++++ trunk/reader-common.c 2018-04-03 03:20:07.662045399 +0300 +@@ -15,6 +15,7 @@ + #include "reader-common.h" + //#include "csctapi/atr.h" + #include "csctapi/icc_async.h" ++#include "readers.h" + + extern const struct s_cardsystem *cardsystems[]; + extern char *RDR_CD_TXT[]; +@@ -142,6 +143,19 @@ void cardreader_poll_status(struct s_rea + static int32_t reader_get_cardsystem(struct s_reader *reader, ATR *atr) + { + int32_t i; ++ ++#ifdef WITH_EMU ++ if(reader->typ == R_EMU) ++ { ++ NULLFREE(reader->csystem_data); ++ rdr_log(reader, "found card system %s", reader_emu.desc); ++ reader->csystem = &reader_emu; ++ reader->csystem_active = true; ++ led_status_found_cardsystem(); ++ return (reader->csystem_active); ++ } ++#endif ++ + for(i = 0; cardsystems[i]; i++) + { + NULLFREE(reader->csystem_data); +diff -ruNp trunk.patches/readers.h trunk/readers.h +--- trunk.patches/readers.h 2018-04-03 02:44:09.762266162 +0300 ++++ trunk/readers.h 2018-04-03 03:20:07.662045399 +0300 +@@ -16,5 +16,6 @@ extern const struct s_cardsystem reader_ + extern const struct s_cardsystem reader_bulcrypt; + extern const struct s_cardsystem reader_griffin; + extern const struct s_cardsystem reader_dgcrypt; ++extern const struct s_cardsystem reader_emu; + + #endif +diff -ruNp trunk.patches/webif/config/dvbapi.html trunk/webif/config/dvbapi.html +--- trunk.patches/webif/config/dvbapi.html 2018-04-03 02:44:08.322254087 +0300 ++++ trunk/webif/config/dvbapi.html 2018-04-03 03:20:07.666045429 +0300 +@@ -53,7 +53,7 @@ + + + Write detected prov name to srvid: +- +\ В конце файла нет новой строки ++ ++ ++ Max pids for extended CWs ++ ++ ++ ++ +\ В конце файла нет новой строки +diff -ruNp trunk.patches/webif/config/menu.html trunk/webif/config/menu.html +--- trunk.patches/webif/config/menu.html 2018-04-03 02:44:08.458255227 +0300 ++++ trunk/webif/config/menu.html 2018-04-03 03:20:07.666045429 +0300 +@@ -16,6 +16,7 @@ + ##TPLCONFIGMENUDVBAPI## + ##TPLCONFIGMENULCD## + ##TPLCONFIGMENUMONITOR## ++##TPLCONFIGMENUSTREAMRELAY## +

  • WebIf
  • + + +diff -ruNp trunk.patches/webif/config/menu_streamrelay.html trunk/webif/config/menu_streamrelay.html +--- trunk.patches/webif/config/menu_streamrelay.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/config/menu_streamrelay.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1 @@ ++
  • Stream Relay
  • +diff -ruNp trunk.patches/webif/config/streamrelay.html trunk/webif/config/streamrelay.html +--- trunk.patches/webif/config/streamrelay.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/config/streamrelay.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1,25 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ В конце файла нет новой строки +diff -ruNp trunk.patches/webif/files/menu.html trunk/webif/files/menu.html +--- trunk.patches/webif/files/menu.html 2018-04-03 02:44:08.458255227 +0300 ++++ trunk/webif/files/menu.html 2018-04-03 03:20:07.666045429 +0300 +@@ -10,7 +10,7 @@ +
  • logfile
  • +
  • userfile
  • + ##TPLFILEMENUGBOX## +-
  • other files ++
  • other files + +
  • + +diff -ruNp trunk.patches/webif/files/menu_softcamkey.html trunk/webif/files/menu_softcamkey.html +--- trunk.patches/webif/files/menu_softcamkey.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/files/menu_softcamkey.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1 @@ ++
  • SoftCam.Key
  • +diff -ruNp trunk.patches/webif/pages_index.txt trunk/webif/pages_index.txt +--- trunk.patches/webif/pages_index.txt 2018-04-03 02:44:08.678257072 +0300 ++++ trunk/webif/pages_index.txt 2018-04-03 03:20:07.666045429 +0300 +@@ -80,11 +80,13 @@ CONFIGMENUMONITOR config/men + CONFIGMENUNEWCAMD config/menu_newcamd.html MODULE_NEWCAMD + CONFIGMENURADEGAST config/menu_radegast.html MODULE_RADEGAST + CONFIGMENUSCAM config/menu_scam.html MODULE_SCAM ++CONFIGMENUSTREAMRELAY config/menu_streamrelay.html WITH_EMU + CONFIGMENUSERIAL config/menu_serial.html MODULE_SERIAL + CONFIGMONITOR config/monitor.html MODULE_MONITOR + CONFIGNEWCAMD config/newcamd.html MODULE_NEWCAMD + CONFIGRADEGAST config/radegast.html MODULE_RADEGAST + CONFIGSCAM config/scam.html MODULE_SCAM ++CONFIGSTREAMRELAY config/streamrelay.html WITH_EMU + CONFIGSERIAL config/serial.html MODULE_SERIAL + CONFIGSERIALDEVICEBIT config/serial_devices.html MODULE_SERIAL + CONFIGWEBIF config/webif.html +@@ -118,6 +120,7 @@ FILEMENUDVBAPI files/menu + FILEMENUFAKECWS files/menu_fakecws.html CS_CACHEEX + FILEMENUGBOX files/menu_gbox.html MODULE_GBOX + FILEMENUTWIN files/menu_twin.html MODULE_SERIAL ++FILEMENUSOFTCAMKEY files/menu_softcamkey.html WITH_EMU + + AUTOCONF ghttp/autoconf.html MODULE_GHTTP + PREAUTOCONF ghttp/pre_autoconf.html MODULE_GHTTP +@@ -182,6 +185,7 @@ READERCONFIG readerconf + READEREDITCACHEEXBIT readerconfig/readerconfig_cacheexbit.html CS_CACHEEX + READERCONFIGCAMD35BIT readerconfig/readerconfig_camd35bit.html MODULE_CAMD35 + READERCONFIGCCCAMBIT readerconfig/readerconfig_cccambit.html MODULE_CCCAM ++READERCONFIGEMUBIT readerconfig/readerconfig_emubit.html WITH_EMU + READERCONFIGCS378XBIT readerconfig/readerconfig_cs378xbit.html MODULE_CAMD35_TCP + READERCONFIGGBOXBIT readerconfig/readerconfig_gboxbit.html MODULE_GBOX + READERCONFIGGHTTPBIT readerconfig/readerconfig_ghttpbit.html MODULE_GHTTP +diff -ruNp trunk.patches/webif/readerconfig/readerconfig_emubit.html trunk/webif/readerconfig/readerconfig_emubit.html +--- trunk.patches/webif/readerconfig/readerconfig_emubit.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/readerconfig/readerconfig_emubit.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ ++ diff --git a/package/lean/dvb/tvheadend/Config.in b/package/lean/dvb/tvheadend/Config.in new file mode 100644 index 000000000..5bc1a18bc --- /dev/null +++ b/package/lean/dvb/tvheadend/Config.in @@ -0,0 +1,17 @@ +config TVHEADEND_NDMS_CWC_SUPPORT + bool "NewCamd support" + default y + +config TVHEADEND_NDMS_LINUXDVB_SUPPORT + bool "Linux DVB support" + default y + +config TVHEADEND_NDMS_DVBSCAN_SUPPORT + bool "Fetch DVB-scan data" + depends on TVHEADEND_NDMS_LINUXDVB_SUPPORT + default TVHEADEND_NDMS_LINUXDVB_SUPPORT + +config TVHEADEND_NDMS_AVAHI_SUPPORT + bool "Avahi client support" + select PACKAGE_libavahi-client + default n diff --git a/package/lean/dvb/tvheadend/Makefile b/package/lean/dvb/tvheadend/Makefile new file mode 100644 index 000000000..491f65473 --- /dev/null +++ b/package/lean/dvb/tvheadend/Makefile @@ -0,0 +1,131 @@ +# +# Copyright (C) 2015 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=tvheadend +PKG_VERSION:=4.2.6 +PKG_RELEASE:=1 + +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=c2a6b61d06ecf8c033f2f5be5746c146eb907d26 +# This is stable git version... +# PKG_SOURCE_VERSION:=1a0262f5870e4fabd6b9c70a7bf2ebe420bc956e +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/tvheadend/tvheadend.git +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILES:=LICENSE.md + +PKG_FIXUP:=autoreconf + +PKG_USE_MIPS16:=0 + +SHORT_GIT_VER:=$(shell echo $(PKG_SOURCE_VERSION) | cut -b -7) + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/nls.mk + +define Package/tvheadend + SECTION:=multimedia + CATEGORY:=Multimedia + TITLE:=Tvheadend is a TV streaming server for Linux + DEPENDS:=+libopenssl +librt +zlib +libpcre +libdvbcsa +TVHEADEND_AVAHI_SUPPORT:libavahi-client $(ICONV_DEPENDS) + URL:=https://tvheadend.org + MAINTAINER:=Jan Čermák +endef + +define Package/tvheadend/description + Tvheadend is a TV streaming server and recorder for Linux, FreeBSD and Android + supporting DVB-S, DVB-S2, DVB-C, DVB-T, ATSC, IPTV, SAT>IP and HDHomeRun as input sources. + + Tvheadend offers the HTTP (VLC, MPlayer), HTSP (Kodi, Movian) and SAT>IP streaming. +endef + +define Package/tvheadend/config + menu "Configuration" + depends on PACKAGE_tvheadend + source "$(SOURCE)/Config.in" + endmenu +endef + +ifeq ($(CONFIG_TVHEADEND_CWC_SUPPORT),) + CONFIGURE_ARGS += --disable-cwc +endif + +ifeq ($(CONFIG_TVHEADEND_LINUXDVB_SUPPORT),) + CONFIGURE_ARGS += --disable-linuxdvb +endif + +ifeq ($(CONFIG_TVHEADEND_DVBSCAN_SUPPORT),) + CONFIGURE_ARGS += --disable-dvbscan +endif + +ifeq ($(CONFIG_TVHEADEND_AVAHI_SUPPORT),) + CONFIGURE_ARGS += --disable-avahi +else + CONFIGURE_ARGS += --enable-avahi +endif + +CONFIGURE_ARGS += \ + --arch=$(ARCH) \ + --disable-dbus_1 \ + --disable-libav \ + --enable-bundle \ + --enable-dvben50221 \ + --enable-tvhcsa \ + --enable-dvbcsa \ + --enable-inotify \ + --enable-epoll \ + --enable-trace \ + --nowerror \ + --disable-dvbscan \ + --disable-avahi \ + --disable-hdhomerun_static \ + --disable-pie \ + --disable-imagecache \ + --disable-ffmpeg_static \ + --disable-libx264 \ + --disable-libx264_static \ + --disable-libx265 \ + --disable-libx265_static \ + --disable-libvpx \ + --disable-libvpx_static \ + --disable-libtheora \ + --disable-libtheora_static \ + --disable-libvorbis \ + --disable-libvorbis_static \ + --disable-libfdkaac \ + --disable-libfdkaac_static \ + --disable-nvenc \ + --disable-libmfx_static \ + --disable-timeshift + + +define Build/Prepare + $(call Build/Prepare/Default) + echo 'Tvheadend $(shell echo $(PKG_VERSION)~$(SHORT_GIT_VER)-$(PKG_RELEASE))' \ + > $(PKG_BUILD_DIR)/debian/changelog +endef + +define Package/conffiles +/etc/config/tvheadend +endef + +define Package/tvheadend/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/tvheadend.init $(1)/etc/init.d/tvheadend + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/tvheadend.config $(1)/etc/config/tvheadend + + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/build.linux/tvheadend $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,tvheadend)) diff --git a/package/lean/dvb/tvheadend/files/tvheadend.config b/package/lean/dvb/tvheadend/files/tvheadend.config new file mode 100644 index 000000000..62c139de5 --- /dev/null +++ b/package/lean/dvb/tvheadend/files/tvheadend.config @@ -0,0 +1,13 @@ +#config tvheadend service +# option nosyslog '0' +# option use_temp_epgdb '0' +# option config_path '/etc/tvheadend' + +config tvheadend server + option ipv6 '1' +# option bindaddr '0.0.0.0' +# option http_port '9981' +# option http_root '/tvheadend' +# option htsp_port '9982' +# option htsp_port2 '9983' +# option xspf '0' diff --git a/package/lean/dvb/tvheadend/files/tvheadend.init b/package/lean/dvb/tvheadend/files/tvheadend.init new file mode 100644 index 000000000..07d96a867 --- /dev/null +++ b/package/lean/dvb/tvheadend/files/tvheadend.init @@ -0,0 +1,71 @@ +#!/bin/sh /etc/rc.common + +START=99 +STOP=00 + +USE_PROCD=1 +PROG=/usr/bin/tvheadend + +TEMP_CONFIG=/tmp/tvheadend +PERSISTENT_CONFIG=/etc/tvheadend + +execute_first_run() { + "$PROG" -C "$1" -B -C -A >/dev/null 2>&1 +} + +ensure_config_exists() { + local config_path + + config_load tvheadend + config_get config_path service config_path + + if [ -z "$config_path" ]; then + [ -d "$PERSISTENT_CONFIG" ] || execute_first_run "$PERSISTENT_CONFIG" + else + # if the configuration directory is empty, empty config with grant-all ACL is created + [ -d "$config_path" ] && [ "$(ls -A $config_path)" ] || execute_first_run "$config_path" + fi + + # if use_temp_epgdb is enabled (default), most of the config is put to config_path + # (or /etc/config), except for epgdb.v2, which grows quite large and is write-heavy, + # so it's put into volatile tmpfs + # epgdb.v2 is created and symlinked to main config dir upon each start (if it doesn't exist) + config_get_bool use_temp_epgdb service use_temp_epgdb 1 + if [ "$use_temp_epgdb" == "1" ]; then + TEMP_EPG="${TEMP_CONFIG}/epgdb.v2" + [ ! -f "$TEMP_EPG" ] && mkdir -p "$TEMP_CONFIG" && touch "$TEMP_EPG" && chmod 700 "$TEMP_EPG" + [ -z "$config_path" ] && config_path="$PERSISTENT_CONFIG" + ln -sf "$TEMP_EPG" "${config_path}/epgdb.v2" + fi +} + +load_uci_config() { + config_load tvheadend + config_get config_path service config_path "$PERSISTENT_CONFIG" + [ -n "$config_path" ] && procd_append_param command -c "$config_path" + config_get_bool nosyslog service nosyslog 0 + [ "$nosyslog" -eq 1 ] && procd_append_param command --nosyslog + config_get_bool ipv6 server ipv6 0 + [ "$ipv6" -eq 1 ] && procd_append_param command --ipv6 + config_get bindaddr server bindaddr + [ -n "$bindaddr" ] && procd_append_param command --bindaddr "$bindaddr" + config_get http_port server http_port + [ -n "$http_port" ] && procd_append_param command --http_port "$http_port" + config_get http_root server http_root + [ -n "$http_root" ] && procd_append_param command --http_root "$http_root" + config_get htsp_port server htsp_port + [ -n "$htsp_port" ] && procd_append_param command --htsp_port "$htsp_port" + config_get htsp_port2 server htsp_port2 + [ -n "$htsp_port2" ] && procd_append_param command --htsp_port "$htsp_port2" + config_get xspf server xspf 0 + [ "$xspf" -eq 1 ] && procd_append_param command --xspf +} + +start_service() { + ensure_config_exists + procd_open_instance + procd_set_param file /etc/config/tvheadend + procd_set_param command "$PROG" -B -C + load_uci_config + procd_close_instance +} diff --git a/package/lean/dvb/tvheadend/patches/001-config.patch b/package/lean/dvb/tvheadend/patches/001-config.patch new file mode 100644 index 000000000..becfe11d9 --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/001-config.patch @@ -0,0 +1,12 @@ +diff -ruN tvheadend.orig/Makefile tvheadend/Makefile +--- tvheadend.orig/Makefile 2017-10-18 16:39:58.000000000 +0300 ++++ tvheadend/Makefile 2017-12-13 00:49:51.314127208 +0300 +@@ -52,7 +52,7 @@ + CFLAGS += -Wmissing-prototypes + CFLAGS += -fms-extensions -funsigned-char -fno-strict-aliasing + CFLAGS += -D_FILE_OFFSET_BITS=64 +-CFLAGS += -I${BUILDDIR} -I${ROOTDIR}/src -I${ROOTDIR} ++CFLAGS += -I ./vendor/dvb-api/5.10 -I${BUILDDIR} -I${ROOTDIR}/src -I${ROOTDIR} + ifeq ($(CONFIG_ANDROID),yes) + LDFLAGS += -ldl -lm + else diff --git a/package/lean/dvb/tvheadend/patches/002-add-cflags.patch b/package/lean/dvb/tvheadend/patches/002-add-cflags.patch new file mode 100755 index 000000000..cbd72e0ba --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/002-add-cflags.patch @@ -0,0 +1,33 @@ +commit 511fddc480c11ba55c9078e54884b584430dc41e +Author: Jaroslav Kysela +Date: Fri Jan 19 10:20:17 2018 +0100 + + Makefile: Add CFLAGS for timestamp and bundle objects, fixes #4870 + +diff --git a/Makefile b/Makefile +index f4b7deb..a6629bd 100644 +--- a/Makefile ++++ b/Makefile +@@ -764,11 +764,11 @@ $(BUILDDIR)/timestamp.c: FORCE + @echo 'const char* build_timestamp = "'$(BUILD_DATE)'";' >> $@ + + $(BUILDDIR)/timestamp.o: $(BUILDDIR)/timestamp.c +- $(pCC) -c -o $@ $< ++ $(pCC) $(CFLAGS) -c -o $@ $< + + $(BUILDDIR)/build.o: $(BUILDDIR)/build.c + @mkdir -p $(dir $@) +- $(pCC) -c -o $@ $< ++ $(pCC) $(CFLAGS) -c -o $@ $< + + # Documentation + $(BUILDDIR)/docs-timestamp: $(I18N-DOCS) support/doc/md_to_c.py +@@ -825,7 +825,7 @@ src/tvh_locale_inc.c: $(PO-FILES) + # Bundle files + $(BUILDDIR)/bundle.o: $(BUILDDIR)/bundle.c + @mkdir -p $(dir $@) +- $(pCC) -I${ROOTDIR}/src -c -o $@ $< ++ $(pCC) $(CFLAGS) -I${ROOTDIR}/src -c -o $@ $< + + $(BUILDDIR)/bundle.c: check_dvb_scan make_webui + @mkdir -p $(dir $@) diff --git a/package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch b/package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch new file mode 100644 index 000000000..901c252e0 --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch @@ -0,0 +1,314 @@ +diff -ruNp tvheadend.orig/src/http.c tvheadend/src/http.c +--- tvheadend.orig/src/http.c 2018-02-22 22:16:01.000000000 +0300 ++++ tvheadend/src/http.c 2018-02-26 04:03:51.584188821 +0300 +@@ -1273,10 +1273,6 @@ process_request(http_connection_t *hc, h + hc->hc_session = tvh_strdupa(v); + else + hc->hc_session = NULL; +- if(hc->hc_cseq == 0) { +- http_error(hc, HTTP_STATUS_BAD_REQUEST); +- return -1; +- } + break; + + case HTTP_VERSION_1_0: +@@ -1336,10 +1332,7 @@ process_request(http_connection_t *hc, h + case RTSP_VERSION_1_0: + if (tvhtrace_enabled()) + dump_request(hc); +- if (hc->hc_cseq) +- rval = hc->hc_process(hc, spill); +- else +- http_error(hc, HTTP_STATUS_HTTP_VERSION); ++ rval = hc->hc_process(hc, spill); + break; + + case HTTP_VERSION_1_0: +diff -ruNp tvheadend.orig/src/http.h tvheadend/src/http.h +--- tvheadend.orig/src/http.h 2018-02-22 22:16:01.000000000 +0300 ++++ tvheadend/src/http.h 2018-02-26 03:19:40.457467700 +0300 +@@ -162,6 +162,7 @@ typedef struct http_connection { + + int hc_no_output; + int hc_shutdown; ++ int hc_stream; + uint64_t hc_cseq; + char *hc_session; + +diff -ruNp tvheadend.orig/src/satip/rtsp.c tvheadend/src/satip/rtsp.c +--- tvheadend.orig/src/satip/rtsp.c 2018-02-22 22:16:01.000000000 +0300 ++++ tvheadend/src/satip/rtsp.c 2018-02-26 19:07:59.113158089 +0300 +@@ -92,6 +92,13 @@ static pthread_mutex_t rtsp_lock; + static void rtsp_close_session(session_t *rs); + static void rtsp_free_session(session_t *rs); + ++/* ++ * ++ */ ++static inline int rtsp_is_nat_active(void) ++{ ++ return rtsp_nat_ip[0] != '\0'; ++} + + /* + * +@@ -280,9 +287,10 @@ rtsp_check_urlbase(char *u) + if (strcmp(u, rtsp_ip)) { + if (rtsp_nat_ip == NULL) + return NULL; +- if (rtsp_nat_ip[0] != '*') +- if (rtsp_nat_ip[0] == '\0' || strcmp(u, rtsp_nat_ip)) ++ if (rtsp_is_nat_active()) { ++ if (rtsp_nat_ip[0] != '*' && strcmp(u, rtsp_nat_ip)) + return NULL; ++ } + } + return p ? p + 1 : u + strlen(u); + } +@@ -455,8 +463,7 @@ static void + rtsp_manage_descramble(session_t *rs) + { + idnode_set_t *found; +- mpegts_service_t *s, *snext; +- mpegts_service_t *master = (mpegts_service_t *)rs->subs->ths_raw_service; ++ mpegts_service_t *s, *master, *snext; + slave_subscription_t *sub; + mpegts_apids_t pmt_pids; + size_t si; +@@ -470,6 +477,8 @@ rtsp_manage_descramble(session_t *rs) + if (rs->mux == NULL || rs->subs == NULL) + goto end; + ++ master = (mpegts_service_t *)rs->subs->ths_raw_service; ++ + if (rs->pids.all) { + LIST_FOREACH(s, &rs->mux->mm_services, s_dvb_mux_link) + if (rtsp_validate_service(s, NULL)) +@@ -861,7 +870,7 @@ parse_pids(char *p, mpegts_apids_t *pids + while (1) { + if (x == NULL) + break; +- if (strcmp(x, "all") == 0) { ++ if (strcmp(x, "all") == 0 || strcmp(x, "8192") == 0) { + if (satip_server_conf.satip_restrict_pids_all) { + pids->all = 0; + for (pid = 1; pid <= 2; pid++) /* CAT, TSDT */ +@@ -907,7 +916,22 @@ parse_transport(http_connection_t *hc) + if (a + 1 != b) + return -1; + return a; +- } else if ((strncmp(s, "RTP/AVP/TCP;interleaved=0-1", 27) == 0) && ++ } else if (strncmp(s, "RTP/AVP/UDP;unicast;client_port=", 32) == 0) { ++ for (s += 32, u = s; isdigit(*u); u++); ++ if (*u != '-') ++ return -1; ++ a = atoi(s); ++ for (s = ++u; isdigit(*s); s++); ++ if (*s != '\0' && *s != ';') ++ return -1; ++ b = atoi(u); ++ if (a + 1 != b) ++ return -1; ++ return a; ++ } else if ((strncmp(s, "RTP/AVP/TCP;unicast;interleaved=0-1", 27) == 0) && ++ !satip_server_conf.satip_notcp_mode) { ++ return RTSP_TCP_DATA; ++ } else if ((strncmp(s, "RTP/AVP/TCP;interleaved=0-1", 35) == 0) && + !satip_server_conf.satip_notcp_mode) { + return RTSP_TCP_DATA; + } +@@ -983,12 +1007,14 @@ rtsp_parse_cmd + if (cmd == RTSP_CMD_SETUP) { + if (!rs) { + rs = rtsp_new_session(hc->hc_peer_ipstr, msys, 0, -1); ++ if (rs == NULL) goto end; + if (delsys == DVB_SYS_NONE) goto end; + if (msys == DVB_SYS_NONE) goto end; + if (!(*valid)) goto end; + alloc_stream_id = 1; + } else if (stream != rs->stream) { + rs = rtsp_new_session(hc->hc_peer_ipstr, msys, rs->nsession, stream); ++ if (rs == NULL) goto end; + if (delsys == DVB_SYS_NONE) goto end; + if (msys == DVB_SYS_NONE) goto end; + if (!(*valid)) goto end; +@@ -1017,6 +1043,8 @@ rtsp_parse_cmd + rs->rtp_peer_port = r; + rs->frontend = fe > 0 ? fe : 1; + } else { ++ if (!rs && !stream && cmd == RTSP_CMD_DESCRIBE) ++ rs = rtsp_new_session(hc->hc_peer_ipstr, msys, 0, -1); + if (!rs || stream != rs->stream) { + if (rs) + errcode = HTTP_STATUS_NOT_FOUND; +@@ -1187,6 +1215,12 @@ play: + if (mpegts_pid_dump(&rs->pids, buf + r, sizeof(buf) - r, 0, 0) == 0) + tvh_strlcatf(buf, sizeof(buf), r, ""); + ++ if (cmd == RTSP_CMD_DESCRIBE) { ++ hc->hc_session = rs->session; ++ if (!rs->stream) ++ rs->stream = 1; ++ hc->hc_stream = rs->stream; ++ } + tvhdebug(LS_SATIPS, "%i/%s/%d: %s from %s:%d %s", + rs->frontend, rs->session, rs->stream, + caller, hc->hc_peer_ipstr, ntohs(IP_PORT(*hc->hc_peer)), buf); +@@ -1294,7 +1328,8 @@ rtsp_describe_session(session_t *rs, hts + { + char buf[4096]; + +- htsbuf_qprintf(q, "a=control:stream=%d\r\n", rs->stream); ++ if (rs->stream > 0) ++ htsbuf_qprintf(q, "a=control:stream=%d\r\n", rs->stream); + htsbuf_append_str(q, "a=tool:tvheadend\r\n"); + htsbuf_append_str(q, "m=video 0 RTP/AVP 33\r\n"); + if (strchr(rtsp_ip, ':')) +@@ -1311,6 +1346,20 @@ rtsp_describe_session(session_t *rs, hts + } + } + ++static inline const char * ++rtsp_conn_ip(http_connection_t *hc, char *buf, size_t buflen, int *port) ++{ ++ const char *used_ip = rtsp_ip; ++ int used_port = rtsp_port; ++ ++ if (hc && hc->hc_self) ++ used_ip = tcp_get_str_from_ip(hc->hc_self, buf, buflen); ++ ++ *port = used_port > 0 ? used_port : 554; ++ ++ return used_ip; ++} ++ + /* + * + */ +@@ -1322,9 +1371,10 @@ rtsp_process_describe(http_connection_t + char *u = tvh_strdupa(hc->hc_url); + session_t *rs; + htsbuf_queue_t q; +- char buf[96]; ++ char buf[96], buf1[46]; ++ const char *used_ip = NULL; + int r = HTTP_STATUS_BAD_REQUEST; +- int stream, first = 1, valid; ++ int stream, first = 1, valid, used_port; + + htsbuf_queue_init(&q, 0); + +@@ -1381,10 +1431,15 @@ rtsp_process_describe(http_connection_t + http_arg_init(&args); + if (hc->hc_session) + http_arg_set(&args, "Session", hc->hc_session); +- if (stream > 0) +- snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", rtsp_ip, stream); ++ used_ip = rtsp_conn_ip(hc, buf1, sizeof(buf1), &used_port); ++ if ((stream > 0) && (used_port != 554)) ++ snprintf(buf, sizeof(buf), "rtsp://%s:%d/stream=%i", used_ip, used_port, stream); ++ else if ((stream > 0) && (used_port == 554)) ++ snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", used_ip, stream); ++ else if (used_port != 554) ++ snprintf(buf, sizeof(buf), "rtsp://%s:%d", used_ip, used_port); + else +- snprintf(buf, sizeof(buf), "rtsp://%s", rtsp_ip); ++ snprintf(buf, sizeof(buf), "rtsp://%s", used_ip); + http_arg_set(&args, "Content-Base", buf); + http_send_begin(hc); + http_send_header(hc, HTTP_STATUS_OK, "application/sdp", q.hq_size, +@@ -1408,8 +1463,9 @@ static int + rtsp_process_play(http_connection_t *hc, int cmd) + { + session_t *rs; +- int errcode = HTTP_STATUS_BAD_REQUEST, valid = 0, i, stream; +- char buf[256], *u = tvh_strdupa(hc->hc_url); ++ int errcode = HTTP_STATUS_BAD_REQUEST, valid = 0, i, stream, used_port; ++ char buf[256], buf1[46], *u = tvh_strdupa(hc->hc_url); ++ const char *used_ip = NULL; + http_arg_list_t args; + + http_arg_init(&args); +@@ -1417,7 +1473,9 @@ rtsp_process_play(http_connection_t *hc, + if ((u = rtsp_check_urlbase(u)) == NULL) + goto error2; + +- if ((stream = rtsp_parse_args(hc, u)) < 0) ++/* if ((stream = rtsp_parse_args(hc, u)) < 0) */ ++ stream = hc->hc_stream; ++ if (stream < 0) + goto error2; + + pthread_mutex_lock(&rtsp_lock); +@@ -1467,10 +1525,11 @@ rtsp_process_play(http_connection_t *hc, + snprintf(buf, sizeof(buf), "%d", rs->stream); + http_arg_set(&args, "com.ses.streamID", buf); + } else { +- if (rtsp_port != 554) +- snprintf(buf, sizeof(buf), "url=rtsp://%s:%d/stream=%d", rtsp_ip, rtsp_port, rs->stream); ++ used_ip = rtsp_conn_ip(hc, buf1, sizeof(buf1), &used_port); ++ if (used_port != 554) ++ snprintf(buf, sizeof(buf), "url=rtsp://%s:%d/stream=%d", used_ip, used_port, rs->stream); + else +- snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", rtsp_ip, rs->stream); ++ snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", used_ip, rs->stream); + http_arg_set(&args, "RTP-Info", buf); + } + +@@ -1587,9 +1646,39 @@ static void + rtsp_stream_status ( void *opaque, htsmsg_t *m ) + { + http_connection_t *hc = opaque; ++ struct session *rs = NULL; ++ htsmsg_t *c, *tcp = NULL, *udp = NULL; ++ int udpport, s32; ++ + htsmsg_add_str(m, "type", "SAT>IP"); ++ + if (hc->hc_username) + htsmsg_add_str(m, "user", hc->hc_username); ++ ++ TAILQ_FOREACH(rs, &rtsp_sessions, link) { ++ if (hc->hc_session && ++ strcmp(rs->session, hc->hc_session) == 0 && ++ strcmp(rs->peer_ipstr, hc->hc_peer_ipstr) == 0 && ++ (udpport = rs->rtp_peer_port) > 0) { ++ if (udpport == RTSP_TCP_DATA) { ++ if (rs->tcp_data == hc) { ++ s32 = htsmsg_get_s32_or_default(m, "peer_port", -1); ++ if (!tcp) tcp = htsmsg_create_list(); ++ htsmsg_add_s32(tcp, NULL, s32); ++ } ++ } else { ++ if (!udp) udp = htsmsg_create_list(); ++ htsmsg_add_s32(udp, NULL, udpport); ++ htsmsg_add_s32(udp, NULL, udpport+1); ++ } ++ } ++ } ++ if (tcp || udp) { ++ c = htsmsg_create_map(); ++ if (tcp) htsmsg_add_msg(c, "tcp", tcp); ++ if (udp) htsmsg_add_msg(c, "udp", udp); ++ htsmsg_add_msg(m, "peer_extra_ports", c); ++ } + } + + /* +@@ -1621,6 +1710,7 @@ rtsp_serve(int fd, void **opaque, struct + hc.hc_peer = peer; + hc.hc_self = self; + hc.hc_process = rtsp_process_request; ++ hc.hc_stream = -1; + hc.hc_cseq = 1; + + http_serve_requests(&hc); +@@ -1655,7 +1745,7 @@ rtsp_close_session(session_t *rs) + rs->tcp_data = NULL; + pthread_mutex_lock(&global_lock); + mpegts_pid_reset(&rs->pids); +- rtsp_clean(rs, 1); ++ rtsp_clean(rs, 0); + mtimer_disarm(&rs->timer); + pthread_mutex_unlock(&global_lock); + } diff --git a/package/lean/dvb/tvheadend/patches/008-delete-docs.patch b/package/lean/dvb/tvheadend/patches/008-delete-docs.patch new file mode 100644 index 000000000..5823268d4 --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/008-delete-docs.patch @@ -0,0 +1,10 @@ +--- a/Makefile 2018-03-22 02:51:32.000000000 +0800 ++++ b/Makefile 2018-03-23 18:31:08.010773484 +0800 +@@ -834,6 +834,7 @@ + $(pCC) $(CFLAGS) -I${ROOTDIR}/src -c -o $@ $< + + $(BUILDDIR)/bundle.c: $(DVBSCAN-yes) make_webui ++ find src/webui/static/img/doc/ -delete + @mkdir -p $(dir $@) + $(pMKBUNDLE) -o $@ -d ${BUILDDIR}/bundle.d $(BUNDLE_FLAGS) $(BUNDLES:%=$(ROOTDIR)/%) + diff --git a/package/lean/luci-app-oscam/Makefile b/package/lean/luci-app-oscam/Makefile deleted file mode 100644 index 70a12e865..000000000 --- a/package/lean/luci-app-oscam/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (C) 2008-2014 The LuCI Team -# -# This is free software, licensed under the Apache License, Version 2.0 . -# - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI for OSCAM -LUCI_DEPENDS:=+oscam -LUCI_PKGARCH:=all -PKG_VERSION:=1.0 -PKG_RELEASE:=1 - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature - - diff --git a/package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua b/package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua deleted file mode 100644 index 03f2b172f..000000000 --- a/package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua +++ /dev/null @@ -1,16 +0,0 @@ -module("luci.controller.admin.sattv", package.seeall) - -function index() - --- entry({"admin", "Others"}, cbi("sattv/epg"), i18n("Others"), 70) - - if nixio.fs.access("/etc/config/epg") then - entry({"admin", "Others"}, cbi("sattv/epg"), _("sattv"), 66).index = true - entry({"admin", "Others", "epg"}, cbi("sattv/epg"), _("EPG"), 1).i18n = "diskapply" - end - - if nixio.fs.access("/etc/config/oscam") then - entry({"admin", "Others", "oscam"}, cbi("sattv/oscam"), _("OSCAM"), 12).i18n = "diskapply" - end - -end diff --git a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua b/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua deleted file mode 100644 index da46cad90..000000000 --- a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua +++ /dev/null @@ -1,50 +0,0 @@ -require("luci.tools.webadmin") - ---[[ -config epg_set - option enable 1 - option time 30 - option src_url http://dm.epg.net.cn/a/epg.xml - option src_url1 http://dm1.epg.net.cn/a/epg.xml - option src_url2 http://epg.xltvrobbs.net/atmosphere/epg/epg.xml - option src_url3 http://epg1.xltvrobbs.net/atmosphere/epg/epg.xml - -]]-- - - -m = Map("epg", translate("epg_title","Set epg download address"),translate("epg_desc", -"Set epg auto download for dm500 atmosphere")) - -s = m:section(TypedSection, "epg_set", translate("epgset","settings")) -s.anonymous = true -s.addremove = false - -enable = s:option(Flag, "enable", translate("enable", "enable")) -enable.default = false -enable.optional = false -enable.rmempty = false - -interval = s:option(Value, "interval", translate("interval","interval")) -interval.default = 30 -interval.optional = false -interval.rmempty = false - - -s = m:section(TypedSection, "downaddress", translate("downaddress","downaddress")) -s.template = "cbi/tblsection" -s.anonymous = false -s.addremove = true - -enable = s:option(Flag, "addr_enable", translate("enable", "enable")) -enable.default = false -enable.optional = false -enable.rmempty = false - - -url = s:option(Value, "address", translate("dowload address","dowload address")) -url.optional = false -url.rmempty = false - - -return m - diff --git a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua b/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua deleted file mode 100644 index 44a19fcfd..000000000 --- a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua +++ /dev/null @@ -1,67 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - -Copyright 2011 flyzjhz - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - - -local fs = require "nixio.fs" -local uci = require "luci.model.uci".cursor() -local lanipaddr = uci:get("network", "lan", "ipaddr") or "192.168.1.1" ---- Retrieves the output of the "get_oscam_port" command. --- @return String containing the current get_oscam_port -function get_oscam_port() - - local oscam_conf= fs.readfile("/usr/oscam/oscam.conf") - local oscam_conf_port = tonumber(oscam_conf:match("[Hh]ttppor[Tt].-= ([^\n]+)")) or "8899" - return oscam_conf_port -end - -local oscamport = get_oscam_port() - -m = Map("oscam", translate("OSCAM","OSCAM"),translate("oscam desc", -"oscam for openwrt")) - -s = m:section(TypedSection, "setting", translate("set","settings")) -s.anonymous = true -s.addremove = false - -enable = s:option(Flag, "enable", translate("enable", "enable")) -enable.default = false -enable.optional = false -enable.rmempty = false - -interval = s:option(Value, "interval", translate("interval","interval"), -translate("interval_desc","interval_desc")) -interval.optional = false -interval.rmempty = false -interval.default = 30 - -s:option(DummyValue,"oscamweb" ,translate("OSCAM Web Intelface "),translate("Open the oscam Web")) - -tmpl = s:option(Value, "_tmpl", - translate("Edit oscam configuration."), - translate("This is the content of the file '/usr/oscam/oscam.conf'")) - -tmpl.template = "cbi/tvalue" -tmpl.rows = 20 - -function tmpl.cfgvalue(self, section) - return nixio.fs.readfile("/usr/oscam/oscam.conf") -end - -function tmpl.write(self, section, value) - value = value:gsub("\r\n?", "\n") - nixio.fs.writefile("//usr/oscam/oscam.conf", value) -end - -return m - - diff --git a/package/lean/luci-app-oscam/root/etc/config/epg b/package/lean/luci-app-oscam/root/etc/config/epg deleted file mode 100644 index 9c2791f68..000000000 --- a/package/lean/luci-app-oscam/root/etc/config/epg +++ /dev/null @@ -1,13 +0,0 @@ - -config 'epg_set' - option 'enable' '0' - option 'interval' '30' - -config 'downaddress' 'epg1' - option 'addr_enable' '1' - option 'address' 'http://dm.epg.net.cn/a/epg.xml' - -config 'downaddress' 'epg2' - option 'addr_enable' '1' - option 'address' 'http://epg.xltvrobbs.net/atmosphere/epg/epg.xml' - diff --git a/package/lean/luci-app-oscam/root/etc/config/oscam b/package/lean/luci-app-oscam/root/etc/config/oscam deleted file mode 100644 index 795ea4e3c..000000000 --- a/package/lean/luci-app-oscam/root/etc/config/oscam +++ /dev/null @@ -1,4 +0,0 @@ - -config 'setting' - option 'enable' '0' - diff --git a/package/lean/luci-app-oscam/root/etc/init.d/epg b/package/lean/luci-app-oscam/root/etc/init.d/epg deleted file mode 100755 index 9b9014cdd..000000000 --- a/package/lean/luci-app-oscam/root/etc/init.d/epg +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh /etc/rc.common -# copyrights -# (1)epg dowload Script VER 0.10for openwrt by zjhzzyf - - - -START=96 - - - -start(){ - - - /usr/bin/epg start -} - -stop() { - echo "not implemented yet!" -} - -restart() { - start -} \ No newline at end of file diff --git a/package/lean/luci-app-oscam/root/etc/init.d/oscam b/package/lean/luci-app-oscam/root/etc/init.d/oscam deleted file mode 100755 index ca40a3608..000000000 --- a/package/lean/luci-app-oscam/root/etc/init.d/oscam +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh /etc/rc.common -# oscam Script VER 0.10 for openwrt by zjhzzyf - -START=94 - -. /etc/functions.sh -path="/usr/oscam/" - - -kill_oscam() -{ -local otherpids -local execute -otherpids=$(ps -a 2>&1 | grep "/usr/bin/oscam" | grep -v $$ | awk -F " " '{print $1}') -echo "$otherpids" | while read execute -do -kill -9 ${execute} -done -} - - - -oscam_start() -{ - - /usr/bin/oscam -b -c $path - echo "readdy go....." - -} - - - -start(){ -echo "game start....." - enable=$(uci get oscam.@setting[0].enable) - if [ "$enable" == "" ];then - enable=0 - fi - - [ "$enable" == "1" ]&&oscam_start - -interval=$(uci get oscam.@setting[0].interval) -oscam_cron=`cat /etc/crontabs/root | grep "/etc/init.d/oscam restart"` -if [ "$enable" == "1" -a "$interval" != "0" ]; then - oscam_new="*/${interval} * * * * /etc/init.d/oscam restart" - if [ "z${oscam_cron}" != "z${oscam_new}" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/oscam restart" > /tmp/crontabs_oscam - echo "" >> /tmp/crontabs_oscam - echo "*/${interval} * * * * /etc/init.d/oscam restart" >> /tmp/crontabs_oscam - cat /tmp/crontabs_oscam | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi -else - if [ "z${oscam_cron}" != "z" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/oscam restart" > /tmp/crontabs_oscam - cat /tmp/crontabs_oscam | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi - -fi -rm -f /tmp/crontabs_oscam - -} - -stop() { - kill_oscam - echo "oscam stopped" -} - - diff --git a/package/lean/luci-app-oscam/root/etc/oscam/oscam.conf b/package/lean/luci-app-oscam/root/etc/oscam/oscam.conf deleted file mode 100644 index 51abc783f..000000000 --- a/package/lean/luci-app-oscam/root/etc/oscam/oscam.conf +++ /dev/null @@ -1,39 +0,0 @@ -# oscam.conf generated automatically by Streamboard OSCAM 1.00-unstable_svn build #r4503 -# Read more: http://streamboard.gmc.to/oscam/browser/trunk/Distribution/doc/txt/oscam.conf.txt - -[global] -logfile = /dev/shm/oscam.log -disablelog = 1 -clientmaxidle = 36000 -bindwait = 5 -netprio = 9 -nice = 9 -waitforcards = 0 -lb_mode = 1 - -[monitor] -port = 9988 -nocrypt = -aulow = 120 -hideclient_to = 0 -monlevel = 255 -appendchaninfo = 0 - -[dvbapi] -enabled = 1 -au = 1 -boxtype = none -user = user1 -pmt_mode = 0 -request_mode = 0 - -[webif] -httpport = 8899 -httpuser = oscam -httppwd = oscam -httprefresh = 0 -httpallowed = 1.0.0.0-255.255.0.0 -httphideidleclients = 0 -httpreadonly = 0 -httpsavefullcfg = 0 - diff --git a/package/lean/luci-app-oscam/root/etc/oscam/oscam.server b/package/lean/luci-app-oscam/root/etc/oscam/oscam.server deleted file mode 100644 index 876103ba0..000000000 --- a/package/lean/luci-app-oscam/root/etc/oscam/oscam.server +++ /dev/null @@ -1,28 +0,0 @@ -# oscam.server generated automatically by Streamboard OSCAM 1.00-unstable_svn build #r4503 -# Read more: http://streamboard.gmc.to/oscam/browser/trunk/Distribution/doc/txt/oscam.server.txt - -[reader] -label = reshare1 -enable = 0 -protocol = cccam -device = oscam.3322.org,13111 -user = test01 -password = test01 -inactivitytimeout = 1 -reconnecttimeout = 3 -group = 1 -blockemm-unknown = 1 -blockemm-u = 1 -blockemm-s = 1 -blockemm-g = 1 -lb_weight = 100 -cccversion = 2.1.2 -cccmaxhops = 12 -ccckeepalive = 1 -audisabled = 1 -cccdisableautoblock = 1 - - - - - diff --git a/package/lean/luci-app-oscam/root/etc/oscam/oscam.user b/package/lean/luci-app-oscam/root/etc/oscam/oscam.user deleted file mode 100644 index f02c1bc84..000000000 --- a/package/lean/luci-app-oscam/root/etc/oscam/oscam.user +++ /dev/null @@ -1,6 +0,0 @@ -[account] -user = 001 -pwd = 001 -group = 1 -keepalive = 1 -uniq = 0 diff --git a/package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv b/package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv deleted file mode 100644 index a9e759580..000000000 --- a/package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@epg[-1] - add ucitrack epg - set ucitrack.@epg[-1].init=epg - delete ucitrack.@oscam[-1] - add ucitrack oscam - set ucitrack.@oscam[-1].init=oscam - add_list ucitrack.@oscam[-1].affects=cron - commit ucitrack -EOF -rm -f /tmp/luci-indexcache -exit 0 diff --git a/package/lean/luci-app-oscam/root/usr/bin/epg b/package/lean/luci-app-oscam/root/usr/bin/epg deleted file mode 100755 index e51b91fc4..000000000 --- a/package/lean/luci-app-oscam/root/usr/bin/epg +++ /dev/null @@ -1,199 +0,0 @@ -#!/bin/sh -# copyrights -# (1)epg dowload Script VER 0.10for openwrt by zjhzzyf - - -. /lib/functions.sh - - -epg_down() -{ - bsuc=1 - echo "File Path:"$path - filename="epg.xml" - echo "Setup FileName:"$filename - sfullfilename=`echo $path$filename` - echo "sFullFileName:"$sfullfilename - - index=0 - echo "Try Times Max:"$trytimes - while [ "$index" -lt "$trytimes" ] - do - echo "Try Times:"$index - if wget -qO- -t3 $url > $sfullfilename;then - break - fi - index=`expr $index + 1` - done - if [ "$index" -eq "$trytimes" ]; then - ErrMsg=`date` - ErrMsg=$ErrMsg" 下载配置文件失败" - bsuc=0 - return - fi - echo "down $filename completed" -mfullfilename=`echo ${path}store/${filename}.md5` - echo "MD5 File Name:"$mfullfilename - md5old=`cat $mfullfilename` - md5old=`echo $md5old|awk '{print $1}'|tr "[a-z]" "[A-Z]"` - echo "Old File MD5:"$md5old - md5new=`/usr/bin/md5sum $sfullfilename` - md5new=`echo $md5new|awk '{print $1}'|tr "[a-z]" "[A-Z]"` - echo "New File MD5:"$md5new - if [ "$md5old" = "$md5new" ]; then - ErrMsg=`date` - ErrMsg=$ErrMsg" 数据不需要更新" - bsuc=1 - return - else - - counttimes=0 - suctimes=0 - counttimes=`expr $counttimes + 1` - url=$(grep -m 1 "URL" $sfullfilename |awk -F "" '{print $2}'|awk -F "" '{print $1}') - echo "Down Data URL:" $url - -filename=`echo ${url##*/}` - echo "Down File Name:"$filename - - echo "=====" -echo $url - replaces=`echo ${url%/*}` - -replaces=`echo ${replaces#*//}` - - echo replaces: $replaces - echo -e `sed -e "s#$replaces#$replaced#g" $sfullfilename` > `echo $sfullfilename` - echo "=====" - - dfullfilename=`echo $path$filename` - echo "Down Data Save File Name:"$dfullfilename - - index=0 - while [ "$index" -lt "$trytimes" ] - do - echo "Try Times:"$index - if wget -t3 -T120 -qO- $url > $dfullfilename;then - suctimes=`expr $suctimes + 1` - - break - fi - index=`expr $index + 1` - - done - - if [ "$index" -eq "$trytimes" ]; then - bsuc=0 - ErrMsg=`date` - ErrMsg=$ErrMsg" 下载"$url"失败" - - fi - - - if [ "$counttimes" -eq "$suctimes" ]; then - echo $md5new > `echo $mfullfilename` - -mount -o bind /tmp/epg/ /www/atmosphere - rm -rf ${path}/epg/* - -cp ${path}$filename ${path}/epg -cp ${path}epg.xml ${path}/epg - rm -rf ${path}$filename - rm -rf ${path}epg.xml - ErrMsg=`date` - ErrMsg=$ErrMsg" 下载EPG数据成功" - echo $ErrMsg - exit 0 - else - ErrMsg=`date` - ErrMsg= $ErrMsg " 未知原因失败" - fi - fi -} - - -epg_start() { - -config_get enable $1 enable -config_get interval $1 interval -[ "$enable" = "" ]&&enable=0 - -#make scheduler - -epg_cron=`cat /etc/crontabs/root | grep "/usr/bin/epg scheduler"` -if [ "$enable" == "1" -a "${interval}" != "0" ]; then - mkdir -p /tmp/epg/ - mkdir -p /tmp/epg/store - mkdir -p /tmp/epg/epg - mkdir -p /www/atmosphere - epg_new="*/${interval} * * * * /usr/bin/epg scheduler" - if [ "z${epg_cron}" != "z${epg_new}" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/epg scheduler" > /tmp/crontabs_epg - echo "*/${interval} * * * * /etc/init.d/epg scheduler" >> /tmp/crontabs_epg - echo "" >> /tmp/crontabs_epg - cat /tmp/crontabs_epg | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi -else - if [ "z${epg_cron}" != "z" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/epg scheduler" > /tmp/crontabs_epg - cat /tmp/crontabs_epg | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi -rm -f /tmp/crontabs_epg - -fi - -/etc/init.d/cron restart - -} - - -con_get_addr(){ - - config_get addr_enable $1 addr_enable - config_get address $1 address - -[ "$addr_enable" == "1" ]&&{ -url=$address -echo $url -ErrMsg=`date` -ErrMsg=$ErrMsg" 开始从"$url"下载" -echo $ErrMsg >> `echo /tmp/epglog.txt` -rm `echo $path"*"` -epg_down -echo $ErrMsg >> `echo /tmp/epglog.txt` -echo $bsuc -echo "******************************************************************" >> `echo /tmp/epglog.txt` -} -} - - - -epg_scheduler(){ - -path="/tmp/epg/" -trytimes=3 -bsuc=1 -ErrMsg="" -lan_ipaddr=$(uci get network.lan.ipaddr) -replaced="${lan_ipaddr}/atmosphere/epg" - - -} - - -config_load epg -case "$1" in - start) - config_foreach epg_start epg_set - ;; - stop) - echo "stop test " - ;; - scheduler) - epg_scheduler - config_foreach con_get_addr downaddress -;; -esac - diff --git a/package/lean/luci-app-oscam/root/usr/oscam/oscam.conf b/package/lean/luci-app-oscam/root/usr/oscam/oscam.conf deleted file mode 100644 index a552326fe..000000000 --- a/package/lean/luci-app-oscam/root/usr/oscam/oscam.conf +++ /dev/null @@ -1,37 +0,0 @@ -[global] -# Prozess -nice = -10 -pidfile = /tmp/oscam.pid -# Logging -logfile = /tmp/oscam.log -disablelog = 0 -maxlogsize = 256 -usrfile = /tmp/oscam_user.log -disableuserfile = 0 -usrfileflag = 1 -# Timeouts - If you have problems adjust or remove rows! -clienttimeout = 2000 -fallbacktimeout = 1000 -serialreadertimeout = 800 -# Sonstiges -clientdyndns = 0 -unlockparental = 1 -saveinithistory = 1 - -[monitor] -port = 15990 -nocrypt = 127.0.0.1,192.168.1.1-192.168.1.255 # "No entry for other IP's!" -aulow = 30 -hideclient_to = 0 -monlevel = 4 -appendchaninfo = 0 - -[camd35] -port = 15991 - -[webif] -httpport = 16000 -httprefresh = 0 -httpallowed = 127.0.0.1,192.168.1.1-192.168.1.255 # "No entry for other IP's!" -httphideidleclients = 0 -httpreadonly = 0 diff --git a/package/lean/oscam/Config.in b/package/lean/oscam/Config.in deleted file mode 100644 index 2a23f71c6..000000000 --- a/package/lean/oscam/Config.in +++ /dev/null @@ -1,240 +0,0 @@ -menu "OSCam build options" - depends on PACKAGE_oscam - - -config OSCAM_USE_LIBCRYPTO - bool "Build with OpenSSL libcrypto" - help - "Use OpenSSL libcrypto instead of OSCam internal crypto functions" - default n - -config OSCAM_USE_LIBUSB - bool "Build with libusb" - default n - - - menu "Protocols" - depends on PACKAGE_oscam - - config OSCAM_MODULE_CAMD33 - bool "camd 3.3" - default n - - config OSCAM_MODULE_CAMD35 - bool "camd 3.5 UDP" - default n - - config OSCAM_MODULE_CAMD35_TCP - bool "camd 3.5 TCP" - default n - - config OSCAM_MODULE_NEWCAMD - bool "newcamd" - default n - - config OSCAM_MODULE_CCCAM - bool "CCcam" - default n - - config OSCAM_MODULE_CCCSHARE - bool "CCcam share" - default n - - config OSCAM_MODULE_GBOX - bool "gbox" - default n - - config OSCAM_MODULE_RADEGAST - bool "radegast" - default n - - config OSCAM_MODULE_SERIAL - bool "Serial" - default n - - config OSCAM_MODULE_CONSTCW - bool "constant CW" - default n - - config OSCAM_MODULE_PANDORA - bool "Pandora" - default n - - config OSCAM_MODULE_GHTTP - bool "Ghttp" - default n - - config OSCAM_MODULE_SCAM - bool "scam" - default n - - endmenu - - menu "Readers" - depends on PACKAGE_oscam - - config OSCAM_READER_NAGRA - bool "Nagravision" - default n - - config OSCAM_READER_IRDETO - bool "Irdeto" - default n - - config OSCAM_READER_CONAX - bool "Conax" - default n - - config OSCAM_READER_CRYPTOWORKS - bool "Cryptoworks" - default n - - config OSCAM_READER_SECA - bool "Seca" - default n - - config OSCAM_READER_VIACCESS - bool "Viaccess" - default n - - config OSCAM_READER_VIDEOGUARD - bool "NDS Videoguard" - default n - - config OSCAM_READER_DRE - bool "DRE Crypt" - default n - - config OSCAM_READER_TONGFANG - bool "Tongfang" - default n - - config OSCAM_READER_BULCRYPT - bool "Bulcrypt" - default n - - config OSCAM_READER_GRIFFIN - bool "Griffin" - default n - - config OSCAM_READER_DGCRYPT - bool "DGCrypt" - default n - - endmenu - - menu "Card readers" - depends on PACKAGE_oscam - - config OSCAM_USE_PCSC - bool "PCSC" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_PHOENIX - bool "Phoenix/mouse" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_SC8IN1 - bool "SC8in1" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_MP35 - bool "AD-Teknik MP 3.6/USB Phoenix" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_SMARGO - bool "Argolis Smargo Smartreader" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_STINGER - bool "STINGER" - select OSCAM_USE_LIBUSB - default n - - endmenu - -comment "Addons" -config OSCAM_HAVE_DVBAPI - bool "DVB API" - default y - -config OSCAM_READ_SDT_CHARSETS - bool "DVB API read-sdt charsets" - default y - -config OSCAM_IRDETO_GUESSING - bool "Irdeto guessing" - default n - -config OSCAM_CS_ANTICASC - bool "Anti cascading" - default y - -config OSCAM_WITH_DEBUG - bool "Debug messages" - default n - -config OSCAM_MODULE_MONITOR - bool "Monitor" - default n - -config OSCAM_WITH_LB - bool "Loadbalancing" - default y - -config OSCAM_S_CACHEEX - bool "Cache exchange" - default y - -config OSCAM_CW_CYCLE_CHECK - bool "CW Cycle Check" - default y - -config OSCAM_LCDSUPPORT - bool "LCD support" - default n - -config OSCAM_LEDSUPPORT - bool "LED support" - default n - -config OSCAM_CLOCKFIX - bool "Clockfix (disable on old systems!)" - default y - -config OSCAM_IPV6SUPPORT - bool "IPv6 support (experimental)" - default n - - -config OSCAM_WEBIF - bool "Web Interface" - default n - - config OSCAM_WEBIF_LIVELOG - bool "LiveLog" - depends on OSCAM_WEBIF - default n - - config OSCAM_WEBIF_JQUERY - bool "Jquery onboard (if disabled webload)" - depends on OSCAM_WEBIF - default n - - config OSCAM_TOUCH - bool "Touch Web Interface" - depends on OSCAM_WEBIF - default n - - config OSCAM_WITH_SSL - bool "SSL support" - depends on OSCAM_WEBIF - select OSCAM_USE_LIBCRYPTO - default n - -endmenu diff --git a/package/lean/oscam/Makefile b/package/lean/oscam/Makefile deleted file mode 100644 index 15b795244..000000000 --- a/package/lean/oscam/Makefile +++ /dev/null @@ -1,204 +0,0 @@ -# -# Copyright (C) 2016 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# -# $Id$ - -include $(TOPDIR)/rules.mk - -PKG_NAME:=oscam -PKG_VERSION:=1.20-$(PKG_REV) -PKG_RELEASE:=1 -PKG_REV:=2780c48789c8e1427df4078ea9b06e0b51594bbc - - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=$(PKG_REV) -PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_URL:=https://github.com/coolsnowwolf/oscam.git -PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.bz2 -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) - -PKG_LICENSE:=GPLv3 -PKG_LICENSE_FILES:=COPYING -PKG_MAINTAINER:=tmn505 - -PKG_CONFIG_DEPENDS := \ - OSCAM_USE_LIBCRYPTO \ - OSCAM_USE_LIBUSB \ - OSCAM_USE_PCSC \ - OSCAM_WEBIF \ - OSCAM_WEBIF_LIVELOG \ - OSCAM_WEBIF_JQUERY \ - OSCAM_TOUCH \ - OSCAM_WITH_SSL \ - OSCAM_HAVE_DVBAPI \ - OSCAM_READ_SDT_CHARSETS \ - OSCAM_IRDETO_GUESSING \ - OSCAM_CS_ANTICASC \ - OSCAM_WITH_DEBUG \ - OSCAM_MODULE_MONITOR \ - OSCAM_WITH_LB \ - OSCAM_CS_CACHEEX \ - OSCAM_CW_CYCLE_CHECK \ - OSCAM_LCDSUPPORT \ - OSCAM_LEDSUPPORT \ - OSCAM_CLOCKFIX \ - OSCAM_IPV6SUPPORT \ - OSCAM_MODULE_CAMD33 \ - OSCAM_MODULE_CAMD35 \ - OSCAM_MODULE_CAMD35_TCP \ - OSCAM_MODULE_NEWCAMD \ - OSCAM_MODULE_CCCAM \ - OSCAM_MODULE_CCCSHARE \ - OSCAM_MODULE_GBOX \ - OSCAM_MODULE_RADEGAST \ - OSCAM_MODULE_SCAM \ - OSCAM_MODULE_SERIAL \ - OSCAM_MODULE_CONSTCW \ - OSCAM_MODULE_PANDORA \ - OSCAM_MODULE_GHTTP \ - OSCAM_READER_NAGRA \ - OSCAM_READER_IRDETO \ - OSCAM_READER_CONAX \ - OSCAM_READER_CRYPTOWORKS \ - OSCAM_READER_SECA \ - OSCAM_READER_VIACCESS \ - OSCAM_READER_VIDEOGUARD \ - OSCAM_READER_DRE \ - OSCAM_READER_TONGFANG \ - OSCAM_READER_BULCRYPT \ - OSCAM_READER_GRIFFIN \ - OSCAM_READER_DGCRYPT \ - OSCAM_CARDREADER_PHOENIX \ - OSCAM_CARDREADER_SC8IN1 \ - OSCAM_CARDREADER_MP35 \ - OSCAM_CARDREADER_SMARGO \ - OSCAM_CARDREADER_STINGER - -include $(INCLUDE_DIR)/package.mk - -define Package/oscam/config - source "$(SOURCE)/Config.in" -endef - -config_files=oscam.ac oscam.cacheex oscam.cert oscam.conf oscam.dvbapi oscam.guess oscam.ird oscam.provid oscam.server oscam.services oscam.srvid oscam.tiers oscam.user oscam.whitelist - -define Package/oscam/conffiles -/etc/oscam/ -endef - -define Package/oscam - SECTION:=net - CATEGORY:=Network - TITLE:=Open Source Conditional Access Modul - URL:=http://www.streamboard.tv/oscam - DEPENDS:=+OSCAM_USE_LIBCRYPTO:libopenssl +OSCAM_USE_LIBUSB:libusb-1.0 +OSCAM_USE_PCSC:pcscd -endef - -define Package/list-smargo - $(call Package/oscam) - TITLE:=List smargo readers - DEPENDS:=oscam -endef - -CONFIGURE_CMD = ./config.sh -CONFIGURE_ARGS = \ - --restore \ - $(if $(CONFIG_OSCAM_WEBIF),--enable,--disable) WEBIF \ - $(if $(CONFIG_OSCAM_WEBIF_LIVELOG),--enable,--disable) WEBIF_LIVELOG \ - $(if $(CONFIG_OSCAM_WEBIF_JQUERY),--enable,--disable) WEBIF_JQUERY \ - $(if $(CONFIG_OSCAM_TOUCH),--enable,--disable) TOUCH \ - $(if $(CONFIG_OSCAM_WITH_SSL),--enable,--disable) WITH_SSL \ - $(if $(CONFIG_OSCAM_HAVE_DVBAPI),--enable,--disable) HAVE_DVBAPI \ - $(if $(CONFIG_OSCAM_READ_SDT_CHARSETS),--enable,--disable) READ_SDT_CHARSETS \ - $(if $(CONFIG_OSCAM_IRDETO_GUESSING),--enable,--disable) IRDETO_GUESSING \ - $(if $(CONFIG_OSCAM_CS_ANTICASC),--enable,--disable) CS_ANTICASC \ - $(if $(CONFIG_OSCAM_WITH_DEBUG),--enable,--disable) WITH_DEBUG \ - $(if $(CONFIG_OSCAM_MODULE_MONITOR),--enable,--disable) MODULE_MONITOR \ - $(if $(CONFIG_OSCAM_WITH_LB),--enable,--disable) WITH_LB \ - $(if $(CONFIG_OSCAM_CS_CACHEEX),--enable,--disable) CS_CACHEEX \ - $(if $(CONFIG_OSCAM_CW_CYCLE_CHECK),--enable,--disable) CW_CYCLE_CHECK \ - $(if $(CONFIG_OSCAM_LCDSUPPORT),--enable,--disable) LCDSUPPORT \ - $(if $(CONFIG_OSCAM_LEDSUPPORT),--enable,--disable) LEDSUPPORT \ - $(if $(CONFIG_OSCAM_CLOCKFIX),--enable,--disable) CLOCKFIX \ - $(if $(CONFIG_OSCAM_IPV6SUPPORT),--enable,--disable) IPV6SUPPORT \ - $(if $(CONFIG_OSCAM_MODULE_CAMD33),--enable,--disable) MODULE_CAMD33 \ - $(if $(CONFIG_OSCAM_MODULE_CAMD35),--enable,--disable) MODULE_CAMD35 \ - $(if $(CONFIG_OSCAM_MODULE_CAMD35_TCP),--enable,--disable) MODULE_CAMD35_TCP \ - $(if $(CONFIG_OSCAM_MODULE_NEWCAMD),--enable,--disable) MODULE_NEWCAMD \ - $(if $(CONFIG_OSCAM_MODULE_CCCAM),--enable,--disable) MODULE_CCCAM \ - $(if $(CONFIG_OSCAM_MODULE_CCCSHARE),--enable,--disable) MODULE_CCCSHARE \ - $(if $(CONFIG_OSCAM_MODULE_GBOX),--enable,--disable) MODULE_GBOX \ - $(if $(CONFIG_OSCAM_MODULE_RADEGAST),--enable,--disable) MODULE_RADEGAST \ - $(if $(CONFIG_OSCAM_MODULE_SCAM),--enable,--disable) MODULE_SCAM \ - $(if $(CONFIG_OSCAM_MODULE_SERIAL),--enable,--disable) MODULE_SERIAL \ - $(if $(CONFIG_OSCAM_MODULE_CONSTCW),--enable,--disable) MODULE_CONSTCW \ - $(if $(CONFIG_OSCAM_MODULE_PANDORA),--enable,--disable) MODULE_PANDORA \ - $(if $(CONFIG_OSCAM_MODULE_GHTTP),--enable,--disable) MODULE_GHTTP \ - $(if $(CONFIG_OSCAM_READER_NAGRA),--enable,--disable) READER_NAGRA \ - $(if $(CONFIG_OSCAM_READER_IRDETO),--enable,--disable) READER_IRDETO \ - $(if $(CONFIG_OSCAM_READER_CONAX),--enable,--disable) READER_CONAX \ - $(if $(CONFIG_OSCAM_READER_CRYPTOWORKS),--enable,--disable) READER_CRYPTOWORKS \ - $(if $(CONFIG_OSCAM_READER_SECA),--enable,--disable) READER_SECA \ - $(if $(CONFIG_OSCAM_READER_VIACCESS),--enable,--disable) READER_VIACCESS \ - $(if $(CONFIG_OSCAM_READER_VIDEOGUARD),--enable,--disable) READER_VIDEOGUARD \ - $(if $(CONFIG_OSCAM_READER_DRE),--enable,--disable) READER_DRE \ - $(if $(CONFIG_OSCAM_READER_TONGFANG),--enable,--disable) READER_TONGFANG \ - $(if $(CONFIG_OSCAM_READER_BULCRYPT),--enable,--disable) READER_BULCRYPT \ - $(if $(CONFIG_OSCAM_READER_GRIFFIN),--enable,--disable) READER_GRIFFIN \ - $(if $(CONFIG_OSCAM_READER_DGCRYPT),--enable,--disable) READER_DGCRYPT \ - $(if $(CONFIG_OSCAM_CARDREADER_PHOENIX),--enable,--disable) CARDREADER_PHOENIX \ - $(if $(CONFIG_OSCAM_CARDREADER_SC8IN1),--enable,--disable) CARDREADER_SC8IN1 \ - $(if $(CONFIG_OSCAM_CARDREADER_MP35),--enable,--disable) CARDREADER_MP35 \ - $(if $(CONFIG_OSCAM_CARDREADER_SMARGO),--enable,--disable) CARDREADER_SMARGO \ - $(if $(CONFIG_OSCAM_CARDREADER_STINGER),--enable,--disable) CARDREADER_STINGER \ - --disable CARDREADER_INTERNAL_AZBOX \ - --disable CARDREADER_INTERNAL_COOLAPI \ - --disable CARDREADER_INTERNAL_COOLAPI2 \ - --disable CARDREADER_INTERNAL_SCI \ - --disable CARDREADER_DB2COM \ - --disable CARDREADER_STAPI \ - --disable CARDREADER_STAPI5 - -MAKE_FLAGS += - -ifeq ($(CONFIG_OSCAM_USE_LIBUSB),y) - MAKE_FLAGS += USE_LIBUSB=1 -endif - -ifeq ($(CONFIG_OSCAM_USE_PCSC),y) - MAKE_FLAGS += USE_PCSC=1 -endif - -ifeq ($(CONFIG_OSCAM_USE_LIBCRYPTO),y) - MAKE_FLAGS += USE_LIBCRYPTO=1 -endif - -ifeq ($(CONFIG_OSCAM_WITH_SSL),y) - MAKE_FLAGS += USE_SSL=1 -endif - -MAKE_FLAGS += CONF_DIR=/etc/oscam -MAKE_FLAGS += OSCAM_BIN=Distribution/oscam -MAKE_FLAGS += LIST_SMARGO_BIN=Distribution/list-smargo - - -define Package/oscam/install - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/Distribution/oscam $(1)/usr/sbin/oscam - $(INSTALL_DIR) $(1)/etc/oscam - $(INSTALL_DATA) $(addprefix $(PKG_BUILD_DIR)/Distribution/doc/example/,$(config_files)) $(1)/etc/oscam/ - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./files/oscam.init $(1)/etc/init.d/oscam -endef - -define Package/list-smargo/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/Distribution/list-smargo $(1)/usr/bin/list-smargo -endef - -$(eval $(call BuildPackage,oscam)) -$(eval $(call BuildPackage,list-smargo)) diff --git a/package/lean/oscam/files/oscam.init b/package/lean/oscam/files/oscam.init deleted file mode 100644 index b0bf41dc5..000000000 --- a/package/lean/oscam/files/oscam.init +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2016 OpenWrt.org - -START=50 -USE_PROCD=1 - -start_service() { - procd_open_instance - procd_set_param command /usr/sbin/oscam - procd_set_param respawn - procd_close_instance -}
    Edit Stream Relay Config
    Mode (requires OSCam restart) ++ ++
    Source Stream Host:
    Source Stream Port:
    Source Stream User:
    Source Stream Password:
    Relay Port:
    ECM fix delay:
    Process EMM from stream: ++ ++
    AU providers:
    [BISS] Enable date-coded keys:
    [Drecrypt] Path to ee36.bin:
    [Drecrypt] Path to ee56.bin:
    [Drecrypt] Center force group:
    [Drecrypt] Siberia force group: