|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 * 00019 * This code is based on morfsta's version but has been rewritten nearly 00020 * from scratch. 00021 * 00022 * To get it working ensure that GBOX is running with no F: { 01 } line, 00023 * and no pmt.tmp file in /var/tmp. 00024 */ 00025 00026 #include <stdio.h> 00027 00028 #include <vdr/pat.h> 00029 00030 #include "cc.h" 00031 #include "parse.h" 00032 00033 // -- cGboxClient ----------------------------------------------------------- 00034 00035 class cCardClientGbox : public cCardClient { 00036 private: 00037 int GetMsg(int cmd, unsigned char *buff, int len); 00038 public: 00039 cCardClientGbox(const char *Name); 00040 virtual bool Init(const char *CfgDir); 00041 virtual bool Login(void); 00042 virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw); 00043 }; 00044 00045 static cCardClientLinkReg<cCardClientGbox> __ncd("gbox"); 00046 00047 cCardClientGbox::cCardClientGbox(const char *Name) 00048 :cCardClient(Name) 00049 { 00050 so.SetRWTimeout(2*1000); 00051 so.SetUDP(true); 00052 } 00053 00054 bool cCardClientGbox::Init(const char *config) 00055 { 00056 cMutexLock lock(this); 00057 Logout(); 00058 int num=0; 00059 if(!ParseStdConfig(config,&num)) return false; 00060 return true; 00061 } 00062 00063 bool cCardClientGbox::Login(void) 00064 { 00065 Logout(); 00066 if(!so.Bind("127.0.0.1",8003)) return false; 00067 return true; 00068 } 00069 00070 int cCardClientGbox::GetMsg(int cmd, unsigned char *buff, int len) 00071 { 00072 int n; 00073 do { 00074 n=so.Read(buff,-len); 00075 } while(n>0 && buff[0]!=cmd); 00076 return n; 00077 } 00078 00079 bool cCardClientGbox::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw) 00080 { 00081 cMutexLock lock(this); 00082 if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false; 00083 so.Flush(); 00084 00085 const int caid=ecm->caId; 00086 const int pid =ecm->ecm_pid; 00087 int n; 00088 const unsigned char *descr=ecm->GetCaDescr(&n); 00089 if(!descr) { 00090 PRINTF(L_CC_GBOX,"no CA descriptor for caid %04x sid %d prov %04x",caid,ecm->prgId,ecm->provId); 00091 return false; 00092 } 00093 00094 static const unsigned char pmt[] = { 00095 0x87, 00096 0x02,0xb0,0x25, // tid, sct len 00097 0x17,0x74, // sid 00098 0xc3,0x00,0x00, // vers, sctnr 00099 0xff,0xec, // pcr pid 00100 0xf0,0x00, // prg info len 00101 0x02, 0xff,0xec, 0xf0,0x00 00102 }; 00103 unsigned char buff[512]; 00104 if(sizeof(pmt)+n+8>sizeof(buff)) { 00105 PRINTF(L_CC_GBOX,"CA descriptor buffer overflow %d",sizeof(pmt)+n+8); 00106 return false; 00107 } 00108 memcpy(buff,pmt,sizeof(pmt)); 00109 buff[4]=ecm->prgId >> 8; 00110 buff[5]=ecm->prgId & 0xFF; 00111 memcpy(&buff[sizeof(pmt)],descr,n); 00112 buff[16]=0xF0 | ((n>>8)&0x0F); 00113 buff[17]=n & 0xFF; 00114 SetSctLen(&buff[1],sizeof(pmt)-4+n+4); 00115 buff[2]=(buff[2]&0x0F)|0xB0; 00116 00117 if(so.SendTo("127.0.0.1",8004,buff,sizeof(pmt)+n+4)<0) { 00118 PRINTF(L_CC_GBOX,"failed to send PMT data. GBOX running?"); 00119 return false; 00120 } 00121 00122 if((n=GetMsg(0x8a,buff,sizeof(buff)))<0) { 00123 PRINTF(L_CC_GBOX,"failed to get ECM port. GBOX running?"); 00124 return false; 00125 } 00126 int pidnum=-1; 00127 if(n>=2) { 00128 for(int i=0 ; i<buff[1]; i++) { 00129 if(WORD(buff,2+i*2,0x1FFF)==pid) { 00130 pidnum=i; 00131 break; 00132 } 00133 } 00134 } 00135 if(pidnum<0) { 00136 PRINTF(L_CC_ECM,"%s: unable to decode for CAID %04X/PID %04X",name,caid,pid); 00137 return false; 00138 } 00139 00140 n=SCT_LEN(data); 00141 if(n>=256) { 00142 PRINTF(L_CC_ECM,"%s: ECM section too long %d > 255",name,n); 00143 return false; 00144 } 00145 buff[0]=0x88; 00146 buff[1]=(pid>>8)&0x1F; 00147 buff[2]=pid & 0xFF; 00148 buff[3]=n; 00149 memcpy(&buff[4],data,n); 00150 n+=4; 00151 if(so.SendTo("127.0.0.1",8005+pidnum,buff,n)<0) { 00152 PRINTF(L_CC_GBOX,"failed to send ECM data. GBOX running?"); 00153 return false; 00154 } 00155 00156 if(GetMsg(0x89,buff,sizeof(buff))<0) { 00157 PRINTF(L_CC_GBOX,"failed to get CW. GBOX running?"); 00158 return false; 00159 } 00160 if(n<17) { 00161 PRINTF(L_CC_GBOX,"bad CW answer from GBOX"); 00162 return false; 00163 } 00164 memcpy(cw,&buff[1],16); 00165 return true; 00166 }