SASC
DVBSoftCAM

shl.c

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines