|
SASC-NG
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 00020 #include <stdio.h> 00021 #include <string.h> 00022 #include <errno.h> 00023 #include <malloc.h> 00024 #include <sys/ioctl.h> 00025 #include <sys/poll.h> 00026 #include <linux/dvb/dmx.h> 00027 00028 #include <openssl/des.h> 00029 00030 #include "system-common.h" 00031 #include "data.h" 00032 #include "filter.h" 00033 #include "misc.h" 00034 #include "log-sys.h" 00035 #include "version.h" 00036 00037 SCAPIVERSTAG(); 00038 00039 #define SYSTEM_SHL 0x4A60 00040 00041 #define SYSTEM_NAME "@SHL" 00042 #define SYSTEM_PRI -10 00043 #define SYSTEM_CAN_HANDLE(x) ((x)==SYSTEM_SHL) 00044 00045 #define L_SYS 15 00046 #define L_SYS_HOPPER LCLASS(L_SYS,L_SYS_LASTDEF<<1) 00047 #define L_SYS_HSTATS LCLASS(L_SYS,L_SYS_LASTDEF<<2) 00048 #define L_SYS_ALL LALL(L_SYS_HSTATS) 00049 00050 static const struct LogModule lm_sys = { 00051 (LMOD_ENABLE|L_SYS_ALL)&LOPT_MASK, 00052 (LMOD_ENABLE|L_SYS_DEFDEF)&LOPT_MASK, 00053 "shl", 00054 { L_SYS_DEFNAMES,"pidHopper","hopperStats" } 00055 }; 00056 ADD_MODULE(L_SYS,lm_sys) 00057 00058 // This system is dead. 00059 // Not worth to invest time to keep it compilig.... 00060 00061 #if 0 00062 00063 static cTimeMs __time; 00064 #define time_ms() ((int)__time.Elapsed()) 00065 00066 static cPlainKeyTypeReg<cPlainKeyStd,'Z',false> KeyReg; 00067 00068 // -- cPesFilter --------------------------------------------------------------- 00069 00070 class cPesFilter : public cPidFilter { 00071 public: 00072 cPesFilter(const char *Id, int Num, int DvbNum, int IdleTime); 00073 virtual void Start(int Pid, int Section, int Mask, int Mode, bool Crc); 00074 }; 00075 00076 cPesFilter::cPesFilter(const char *Id, int Num, int DvbNum, int IdleTime) 00077 :cPidFilter(Id,Num,DvbNum,IdleTime) 00078 {} 00079 00080 void cPesFilter::Start(int Pid, int Section, int Mask, int Mode, bool Crc) 00081 { 00082 if(fd>=0) { 00083 Stop(); 00084 struct dmx_pes_filter_params FilterParams; 00085 FilterParams.input=DMX_IN_FRONTEND; 00086 FilterParams.output=DMX_OUT_TAP; 00087 FilterParams.pes_type=DMX_PES_OTHER; 00088 FilterParams.flags=DMX_IMMEDIATE_START; 00089 FilterParams.pid=Pid; 00090 CHECK(ioctl(fd,DMX_SET_PES_FILTER,&FilterParams)); 00091 pid=Pid; 00092 active=true; 00093 } 00094 } 00095 00096 // -- cPidHopper --------------------------------------------------------------- 00097 00098 struct FilterPacket { 00099 struct FilterPacket *next; 00100 int lastTime, dataLen; 00101 unsigned char lastData[1]; 00102 }; 00103 00104 struct FilterData { 00105 cPidFilter *filter; 00106 int lastTime, lastRead, createTime, readCount; 00107 struct FilterPacket *first, *last; 00108 }; 00109 00110 class cPidHopper : public cAction { 00111 private: 00112 struct FilterData *d; 00113 int numFilters; 00114 cMutex sleepMutex; 00115 cCondVar sleep; 00116 // 00117 void PurgeFilter(struct FilterData *dd); 00118 void PurgePacket(struct FilterData *dd, struct FilterPacket *p); 00119 protected: 00120 virtual void Process(cPidFilter *filter, unsigned char *data, int len); 00121 virtual cPidFilter *CreateFilter(const char *Id, int Num, int DvbNum, int IdleTime); 00122 public: 00123 cPidHopper(int DvbNum, int NumFilters); 00124 virtual ~cPidHopper(); 00125 int Read(int pid, int & now, unsigned char *buff, int len, int timeout); 00126 bool AddPid(int pid); 00127 void CutOff(int now); 00128 }; 00129 00130 cPidHopper::cPidHopper(int DvbNum, int NumFilters) 00131 :cAction("pidhopper",DvbNum) 00132 { 00133 numFilters=NumFilters; 00134 d=MALLOC(struct FilterData,NumFilters); 00135 memset(d,0,sizeof(struct FilterData)*NumFilters); 00136 PRINTF(L_SYS_HOPPER,"pid hopper started (%d filters)",numFilters); 00137 } 00138 00139 cPidHopper::~cPidHopper() 00140 { 00141 Lock(); 00142 int now=time_ms(), num=1; 00143 PRINTF(L_SYS_HSTATS,"active pids: (now=%d)\n",now); 00144 for(int i=0; i<numFilters; i++) { 00145 struct FilterData *dd=&d[i]; 00146 if(dd->filter) { 00147 if(dd->filter->Pid()>=0) 00148 PRINTF(L_SYS_HSTATS,"%2d. pid %04x lastTime=%4d lastRead=%4d created=%4d count=%4d", 00149 num++, 00150 dd->filter->Pid(), 00151 dd->lastTime>0 ? (now-dd->lastTime)/1000 : -1, 00152 dd->lastRead>0 ? (now-dd->lastRead)/1000 : -1, 00153 dd->createTime>0 ? (now-dd->createTime)/1000 : -1, 00154 dd->readCount); 00155 DelFilter(dd->filter); 00156 dd->filter=0; 00157 } 00158 PurgeFilter(dd); 00159 } 00160 Unlock(); 00161 free(d); 00162 } 00163 00164 void cPidHopper::PurgeFilter(struct FilterData *dd) 00165 { 00166 if(dd->first && dd->last) PurgePacket(dd,dd->last); 00167 } 00168 00169 void cPidHopper::PurgePacket(struct FilterData *dd, struct FilterPacket *p) 00170 { 00171 while(dd->first) { 00172 struct FilterPacket *del=dd->first; 00173 dd->first=del->next; 00174 if(dd->filter) PRINTF(L_SYS_HOPPER,"PID %04x purging packet %p (time=%d)",dd->filter->Pid(),del,del->lastTime); 00175 free(del); 00176 if(del==p) break; 00177 } 00178 if(!dd->first) dd->last=0; 00179 } 00180 00181 void cPidHopper::CutOff(int now) 00182 { 00183 Lock(); 00184 PRINTF(L_SYS_HOPPER,"cutoff (now=%d)",now); 00185 for(int i=0; i<numFilters; i++) { 00186 struct FilterData *dd=&d[i]; 00187 struct FilterPacket *p=dd->first, *del=0; 00188 while(p) { 00189 if(p->lastTime>=now) break; 00190 del=p; 00191 p=p->next; 00192 } 00193 if(del) { 00194 PurgePacket(dd,del); 00195 dd->lastTime=dd->first ? dd->first->lastTime : -1; 00196 } 00197 } 00198 Unlock(); 00199 } 00200 00201 cPidFilter *cPidHopper::CreateFilter(const char *Id, int Num, int DvbNum, int IdleTime) 00202 { 00203 cPidFilter *filter=new cPesFilter(Id,Num,DvbNum,IdleTime); 00204 d[Num].filter=filter; 00205 d[Num].lastTime=-1; 00206 d[Num].lastRead=-1; 00207 d[Num].createTime=time_ms(); 00208 d[Num].readCount=0; 00209 d[Num].first=0; 00210 d[Num].last=0; 00211 return filter; 00212 } 00213 00214 void cPidHopper::Process(cPidFilter *filter, unsigned char *data, int len) 00215 { 00216 if(data && len>0) { 00217 int now=time_ms(); 00218 for(int i=0; i<numFilters; i++) 00219 if(d[i].filter==filter) { 00220 do { 00221 int l=min(len,184); 00222 struct FilterPacket *p=(struct FilterPacket *)malloc(sizeof(struct FilterPacket)+l-1); 00223 if(p) { 00224 p->next=0; 00225 memcpy(p->lastData,data,l); 00226 p->dataLen=l; 00227 p->lastTime=now; 00228 if(d[i].first) 00229 d[i].last->next=p; 00230 else { 00231 d[i].first=p; 00232 d[i].lastTime=now; 00233 } 00234 d[i].last=p; 00235 PRINTF(L_SYS_HOPPER,"PID %04x queued packet %p (time=%d len=%d) (%s)",d[i].filter->Pid(),p,p->lastTime,l,d[i].first==p?"first":"queue"); 00236 } 00237 len-=l; data+=l; 00238 } while(len>0); 00239 sleep.Broadcast(); 00240 break; 00241 } 00242 } 00243 } 00244 00245 bool cPidHopper::AddPid(int pid) 00246 { 00247 cPidFilter *filter=NewFilter(0); 00248 if(!filter) return false; 00249 filter->Start(pid,0,0,0,false); 00250 return true; 00251 } 00252 00253 int cPidHopper::Read(int pid, int & now, unsigned char *buff, int len, int timeout) 00254 { 00255 Lock(); 00256 timeout+=time_ms(); 00257 PRINTF(L_SYS_HOPPER,"PID %04x read (now=%d)",pid,now); 00258 int n=-1; 00259 while(time_ms()<timeout) { 00260 struct FilterData *dd=0, *old=0; 00261 for(int i=0; i<numFilters; i++) 00262 if(d[i].filter) { 00263 if(d[i].filter->Pid()==pid) { dd=&d[i]; break; } 00264 if(!old || 00265 (d[i].lastRead<0 && d[i].createTime<old->createTime) || 00266 (d[i].lastRead>=0 && d[i].lastRead<old->lastRead)) 00267 old=&d[i]; 00268 } 00269 if(!dd) { 00270 LBSTARTF(L_SYS_VERBOSE); 00271 LBPUT("NEW "); 00272 if(!AddPid(pid)) { 00273 if(!old) break; 00274 LBPUT("{0x%04x/%d/%d} ",old->filter->Pid(),old->lastRead>0 ? (time_ms()-old->lastRead)/1000:-1,old->lastTime>0 ? (time_ms()-old->lastTime)/1000:-1); 00275 old->filter->Stop(); // purge LRU filter 00276 PurgeFilter(old); 00277 old->lastTime=-1; 00278 old->lastRead=-1; 00279 old->createTime=time_ms(); 00280 old->readCount=0; 00281 old->filter->Start(pid,0,0,0,false); 00282 } 00283 LBEND(); 00284 continue; 00285 } 00286 for(struct FilterPacket *p=dd->first; p; p=p->next) { 00287 if(p->lastTime>=now) { 00288 n=min(len,p->dataLen); 00289 memcpy(buff,p->lastData,n); 00290 now=p->lastTime; 00291 PRINTF(L_SYS_HOPPER,"PID %04x returning packet %p (time=%d)",dd->filter->Pid(),p,p->lastTime); 00292 PurgePacket(dd,p); 00293 dd->lastRead=time_ms(); 00294 dd->readCount++; 00295 dd->lastTime=dd->first ? dd->first->lastTime : -1; 00296 break; 00297 } 00298 else { 00299 PRINTF(L_SYS_HOPPER,"PID %04x skipping packet %p (time=%d)",dd->filter->Pid(),p,p->lastTime); 00300 if(!p->next) { 00301 PRINTF(L_SYS_HOPPER,"PID %04x queue empty",dd->filter->Pid()); 00302 PurgePacket(dd,p); 00303 break; 00304 } 00305 } 00306 } 00307 if(n>0) break; 00308 Unlock(); 00309 sleepMutex.Lock(); 00310 sleep.TimedWait(sleepMutex,200); 00311 sleepMutex.Unlock(); 00312 Lock(); 00313 } 00314 Unlock(); 00315 return n; 00316 } 00317 00318 // -- cShl --------------------------------------------------------------------- 00319 00320 class cShl { 00321 private: 00322 DES_key_schedule sched; 00323 public: 00324 void SetKey( const unsigned char *key); 00325 void Decode(unsigned char *data, int n); 00326 }; 00327 00328 void cShl::SetKey(const unsigned char *key) 00329 { 00330 DES_key_sched((DES_cblock *)key,&sched); 00331 } 00332 00333 void cShl::Decode(unsigned char *data, int n) 00334 { 00335 int r=n&7; 00336 n-=r; 00337 for(int i=0; i<n; i+=8) 00338 DES_ecb_encrypt((DES_cblock *)&data[i],(DES_cblock *)&data[i],&sched,DES_DECRYPT); 00339 if(r) { // possible last incomplete block 00340 DES_cblock out; 00341 DES_ecb_encrypt((DES_cblock *)&data[n],&out,&sched,DES_DECRYPT); 00342 memcpy(&data[n],out,r); 00343 } 00344 } 00345 00346 // -- SHL provider ------------------------------------------------------------- 00347 00348 struct ShlProv { 00349 const char *name; 00350 unsigned short id; 00351 bool hasXor; 00352 int filters, pidRange; 00353 const unsigned short pids[128]; 00354 const unsigned char xorTab[16]; 00355 }; 00356 00357 static const struct ShlProv prov[] = { 00358 /* 00359 { "FreeX",0x4A90,false,40,0x1300, 00360 { 0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f,0x1390, 00361 0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397,0x1398, 00362 0x1399,0x139a,0x139b,0x139c,0x13a4,0x13a5,0x13a6,0x13a7, 00363 0x13a8,0x13a9,0x13bf,0x13c0,0x13c1,0x13c2,0x13c3,0x13c4, 00364 0x13c5,0x13c6,0x13c7,0x13c8,0x13c9,0x13ca,0x13cb,0x13cc }, 00365 {} }, 00366 */ 00367 { "FullX-2",0x4A90,false,128,0x0000, 00368 { 0x0bb9,0x0bba,0x0bbc,0x0bbf,0x0bc0,0x0bc2,0x0bc3,0x0bc4, 00369 0x0bc7,0x0bc8,0x0bc9,0x0bcc,0x0bcd,0x0bce,0x0bcf,0x0bd0, 00370 0x0bd3,0x0bd5,0x0bd6,0x0bd7,0x0bd8,0x0bd9,0x0bdb,0x0bdd, 00371 0x0bdf,0x0be0,0x0be1,0x0be2,0x0be3,0x0be4,0x0be5,0x0be6, 00372 0x0be7,0x0be8,0x0be9,0x0bea,0x1784,0x177c,0x178a,0x1796, 00373 0x1774,0x1772,0x17a2,0x1783,0x1792,0x177b,0x1775,0x179b, 00374 0x1794,0x1789,0x1778,0x1799,0x1793,0x1797,0x1782,0x1779, 00375 0x179e,0x1787,0x178d,0x177d,0x1771,0x1791,0x1776,0x1788, 00376 0x178f,0x179c,0x177e,0x178b,0x1785,0x1781,0x0bc5,0x17a1, 00377 0x0bbe,0x179f,0x0bdc,0x1780,0x0bca,0x0bd2,0x0bbd,0x179a, 00378 0x1773,0x178e,0x1795 }, 00379 {} }, 00380 { "FullX",0x6997,true,60,0x1700, 00381 { 0x178e,0x178f,0x1783,0x1780,0x1776,0x177b,0x1772,0x1779, 00382 0x1785,0x179e,0x1791,0x1771,0x177e,0x1793,0x1778,0x179a, 00383 0x17a2,0x17a1,0x178d,0x1787,0x1797,0x1796,0x177d,0x1781, 00384 0x1799,0x1794,0x179b,0x1784,0x1795,0x177c,0x1782,0x179c, 00385 0x1773,0x1788,0x1789,0x178b,0x179f,0x1775,0x1792,0x1774, 00386 0x178a }, 00387 { 0x4E,0x9E,0x5C,0xFA,0x62,0x80,0x4C,0x86,0x56,0xDF,0x7E,0x03,0x9B,0x05,0xB2,0xE7 } }, 00388 { "DP",0x6996,true,48,0x1300, 00389 { 0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f,0x1390, 00390 0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397,0x1398, 00391 0x1399,0x139a,0x139b,0x139c,0x13a4,0x13a5,0x13a6,0x13a7, 00392 0x13a8,0x13a9,0x13bf,0x13c0,0x13c1,0x13c2,0x13c3,0x13c4, 00393 0x13c5,0x13c6,0x13c7,0x13c8,0x13c9,0x13ca,0x13cb,0x13cc }, 00394 { 0x30,0x61,0xD7,0xC0,0x8E,0x41,0x2C,0xB9,0xAA,0x50,0xB2,0xF4,0x5B,0x2E,0x84,0xCF } } 00395 }; 00396 00397 static const struct ShlProv *FindProv(unsigned short id) 00398 { 00399 for(unsigned int i=0; i<(sizeof(prov)/sizeof(struct ShlProv)); i++) 00400 if(prov[i].id==id) return &prov[i]; 00401 return 0; 00402 } 00403 00404 // -- cSystemShl --------------------------------------------------------------- 00405 00406 #define ENC_OFF 12 // encrypted bytes offset 00407 #define ENC_LEN 24 // encrypted bytes length 00408 00409 #define KEY_OFF 7 00410 #define PID_OFF 15 00411 #define EMASK_OFF 8 00412 #define OMASK_OFF 12 00413 #define CW_OFF 17 00414 00415 class cSystemShl : public cSystem, private cShl { 00416 private: 00417 cPidHopper *ph; 00418 int prvId; 00419 bool hasPrvId; 00420 cMutex mutex; 00421 cCondVar wait; 00422 // 00423 void ProcessCw(const unsigned char *data, int prvId, const unsigned char *xorTable); 00424 public: 00425 cSystemShl(void); 00426 virtual ~cSystemShl(); 00427 virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *source); 00428 virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer); 00429 }; 00430 00431 cSystemShl::cSystemShl(void) 00432 :cSystem(SYSTEM_NAME,SYSTEM_PRI) 00433 { 00434 ph=0; hasPrvId=false; 00435 hasLogger=needsLogger=true; maxEcmTry=20; 00436 } 00437 00438 cSystemShl::~cSystemShl() 00439 { 00440 delete ph; 00441 } 00442 00443 bool cSystemShl::ProcessECM(const cEcmInfo *ecm, unsigned char *source) 00444 { 00445 static const unsigned char tester[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; 00446 // in old SHL algo ECM starts with 12 0xFF 00447 if(SCT_LEN(source)<(ENC_OFF+ENC_LEN+3)) { 00448 PRINTF(L_SYS_VERBOSE,"short ecm"); 00449 return false; 00450 } 00451 if(memcmp(tester,&source[3],sizeof(tester))) { // new SHL 00452 mutex.Lock(); 00453 if(!hasPrvId) { 00454 wait.TimedWait(mutex,500); // wait for provider ID 00455 if(!hasPrvId) { 00456 PRINTF(L_SYS_ECM,"no provider ID (logger enabled?)"); 00457 mutex.Unlock(); 00458 return false; 00459 } 00460 } 00461 const struct ShlProv *prv=FindProv(prvId); 00462 if(!prv) { 00463 PRINTF(L_SYS_ECM,"provider %04x not supported",prvId); 00464 mutex.Unlock(); 00465 return false; 00466 } 00467 mutex.Unlock(); 00468 if(!ph) { 00469 PRINTF(L_SYS_ECM,"using card %d",CardNum()); 00470 ph=new cPidHopper(CardNum(),prv->filters); 00471 if(!ph) { 00472 PRINTF(L_SYS_ECM,"no pid hopper"); 00473 return false; 00474 } 00475 #if 1 00476 unsigned int l=min((int)(sizeof(prv->pids)/sizeof(unsigned short)),prv->filters); 00477 for(unsigned int i=0; i<l; i++) { 00478 if(prv->pids[i]<=0) break; 00479 ph->AddPid(prv->pids[i]); 00480 } 00481 #endif 00482 } 00483 00484 int pid=ecm->ecm_pid; 00485 int now=time_ms(); 00486 unsigned char buff[4096]; 00487 unsigned char emask=0, omask=0; 00488 memcpy(buff+1,source,SCT_LEN(source)); buff[0]=0; 00489 LBSTARTF(L_SYS_VERBOSE); 00490 LBPUT("chain 0x%04x [%d] ",pid,SCT_LEN(source)+1); 00491 while(1) { 00492 unsigned char *ptr=buff; 00493 if(ptr[0]!=0) { // decrypt whole payload 00494 LBPUT("PES"); 00495 unsigned char test[8]; 00496 memcpy(test,ptr,sizeof(test)); Decode(test,sizeof(test)); 00497 if(test[0]!=source[0] && (ptr[0]==0x11 || ptr[0]==0x12)) { // Section is available at section_pointer offset. 00498 SetKey(&ptr[KEY_OFF+1]); // Use the same key and pid offsets which you use 00499 Decode(&ptr[PID_OFF+1],183-PID_OFF); // for normal SHL section data decoding. 00500 ptr+=ptr[0]+1; 00501 if(ptr[0]==0x91 && SCT_LEN(ptr)==11) ptr+=11; 00502 LBPUT("s"); 00503 } 00504 else if(test[0]!=source[0] && ptr[0]==0x0a) { 00505 SetKey(&ptr[1]); 00506 Decode(&ptr[9],183-9); 00507 ptr+=ptr[0]+1; 00508 LBPUT("a"); 00509 } 00510 else { 00511 Decode(ptr,184); 00512 LBPUT("n"); 00513 } 00514 LBPUT(" "); 00515 } 00516 else { // decrypt data only 00517 LBPUT("SCT "); 00518 ptr++; 00519 SetKey(&ptr[KEY_OFF]); 00520 Decode(&ptr[PID_OFF],SCT_LEN(ptr)-PID_OFF); 00521 } 00522 if(ptr[0]!=source[0]) { 00523 LBPUT("wrong section %02x != %02x",ptr[0],source[0]); 00524 return false; 00525 } 00526 pid=(ptr[PID_OFF]<<8)+ptr[PID_OFF+1]; 00527 if(pid==0x1FFF) { // finished 00528 if(prv->hasXor) ProcessCw(ptr,prv->id,prv->xorTab); 00529 else { 00530 for(int i=0; i<8; i++) { 00531 const int m=1<<(7-i); 00532 if(!(emask & m)) cw[i ]=ptr[CW_OFF+i]; 00533 if(!(omask & m)) cw[i+8]=ptr[CW_OFF+i+8]; 00534 } 00535 } 00536 LBPUT("done"); 00537 ph->CutOff(now); 00538 return true; 00539 } 00540 else { // next hop 00541 if(prv->hasXor) ProcessCw(ptr,prv->id,prv->xorTab); 00542 else { 00543 emask=ptr[EMASK_OFF]; 00544 omask=ptr[OMASK_OFF]; 00545 memcpy(cw,&ptr[CW_OFF],16); 00546 } 00547 LBPUT("0x%04x ",pid); 00548 #if 1 00549 if(prv->pidRange && (pid&0xFF00)!=prv->pidRange) { 00550 LBPUT("wrong pid range"); 00551 return false; 00552 } 00553 #endif 00554 int n=ph->Read(pid,now,buff,sizeof(buff),1000); 00555 if(n<CW_OFF+16+1) { 00556 LBPUT("read failed"); 00557 return false; 00558 } 00559 LBPUT("[%d] ",n); 00560 } 00561 } 00562 LBEND(); 00563 } 00564 else { // old SHL 00565 static const unsigned char signature[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; 00566 source+=ENC_OFF+3; // here's the DES crypto content 00567 00568 cPlainKey *pk=0; 00569 cKeySnoop ks(this,'Z',ecm->provId,0x00); 00570 unsigned char key[8]; 00571 while((pk=keys.FindKey('Z',ecm->provId,0x00,sizeof(key),pk))) { 00572 pk->Get(key); 00573 SetKey(key); 00574 Decode(source,ENC_LEN); 00575 unsigned char sigbuf[8]; 00576 memcpy(&sigbuf[0],&source[0],2); 00577 memcpy(&sigbuf[2],&source[18],6); 00578 if(!memcmp(sigbuf,signature,sizeof(sigbuf))) { 00579 memcpy(cw,&source[2],16); 00580 ks.OK(pk); 00581 return true; 00582 } 00583 } 00584 } 00585 return false; 00586 } 00587 00588 void cSystemShl::ProcessCw(const unsigned char *data, int prvId, const unsigned char *xorTable) 00589 { 00590 if(SCT_LEN(data)<150) { 00591 PRINTF(L_SYS_VERBOSE,"data is too short"); 00592 return; 00593 } 00594 const unsigned int dataStart=data[33]; 00595 if((dataStart+35)>184) { 00596 PRINTF(L_SYS_VERBOSE,"data broken (%d)",dataStart); 00597 return; 00598 } 00599 const unsigned int xorVal=data[dataStart+35]; 00600 const unsigned int emask =data[dataStart+34]; 00601 const unsigned int omask =data[dataStart+33]; 00602 for(int i=0; i<8; i++) { 00603 const unsigned int m=1<<i; 00604 if(emask & m) cw[i ]=data[CW_OFF+i ]^xorVal^xorTable[i ]; 00605 if(omask & m) cw[i+8]=data[CW_OFF+8+i]^xorVal^xorTable[i+8]; 00606 } 00607 } 00608 00609 void cSystemShl::ProcessEMM(int pid, int caid, const unsigned char *buffer) 00610 { 00611 int n=SCT_LEN(buffer)-3; 00612 buffer+=3; 00613 for(int i=0; i<n;) { 00614 switch(buffer[i]) { 00615 case 0x0a: 00616 mutex.Lock(); 00617 prvId=WORD(buffer,i+2,0xFFFF); 00618 if(!hasPrvId) { 00619 const struct ShlProv *prv=FindProv(prvId); 00620 PRINTF(L_SYS_EMM,"provider id %04x (%s)\n",prvId,prv ? prv->name:"unknown"); 00621 wait.Broadcast(); 00622 } 00623 hasPrvId=true; 00624 mutex.Unlock(); 00625 break; 00626 case 0x08: 00627 case 0x0b: 00628 case 0x09: 00629 case 0x06: 00630 case 0x02: 00631 case 0x30: 00632 case 0x07: 00633 break; 00634 default: 00635 HEXDUMP(L_SYS_EMM,&buffer[i+2],buffer[i+1],"unknown nano: %02x:",buffer[i]); 00636 break; 00637 } 00638 i+=buffer[i+1]+2; 00639 } 00640 } 00641 00642 // -- cSystemLinkShl ----------------------------------------------------------- 00643 00644 class cSystemLinkShl : public cSystemLink { 00645 public: 00646 cSystemLinkShl(void); 00647 virtual bool CanHandle(unsigned short SysId); 00648 virtual cSystem *Create(void) { return new cSystemShl; } 00649 }; 00650 00651 static cSystemLinkShl staticInit; 00652 00653 cSystemLinkShl::cSystemLinkShl(void) 00654 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI) 00655 { 00656 Feature.NeedsKeyFile(); 00657 } 00658 00659 bool cSystemLinkShl::CanHandle(unsigned short SysId) 00660 { 00661 SysId&=0xFFF0; 00662 return SYSTEM_CAN_HANDLE(SysId); 00663 } 00664 00665 #endif //#if 0