|
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 <stdlib.h> 00021 #include <stdio.h> 00022 #include <errno.h> 00023 00024 #include <vdr/device.h> 00025 #include <vdr/channels.h> 00026 #include <vdr/thread.h> 00027 #ifndef SASC 00028 #include <vdr/ringbuffer.h> 00029 #endif 00030 00031 #include "cam.h" 00032 #include "global.h" 00033 #include "device.h" 00034 #include "scsetup.h" 00035 #include "filter.h" 00036 #include "system.h" 00037 #include "data.h" 00038 #include "override.h" 00039 #include "misc.h" 00040 #include "log-core.h" 00041 #ifndef SASC 00042 #include "FFdecsa/FFdecsa.h" 00043 #endif 00044 00045 #define IDLE_SLEEP 0 // idleTime when sleeping 00046 #define IDLE_GETCA 200 // idleTime when waiting for ca descriptors 00047 #define IDLE_GETCA_SLOW 20000 // idleTime if no enc. system 00048 #define IDLE_NO_SYNC 800 // idleTime when not in sync 00049 #define IDLE_SYNC 2000 // idleTime when in sync 00050 00051 #define CW_REPEAT_TIME 2000 // rewrite CW after X ms 00052 #define LOG_COUNT 3 // stop logging after X complete ECM cycles 00053 #define CHAIN_HOLD 120000 // min. time to hold a logger chain 00054 #define ECM_DATA_TIME 6000 // time to wait for ECM data updates 00055 #define MAX_ECM_IDLE 300000 // delay before an idle handler can be removed 00056 #define MAX_ECM_HOLD 15000 // delay before an idle handler stops processing 00057 00058 #define ECMCACHE_FILE "ecm.cache" 00059 00060 #define L_HEX 2 00061 #define L_HEX_ECM LCLASS(L_HEX,2) 00062 #define L_HEX_EMM LCLASS(L_HEX,4) 00063 #define L_HEX_CAT LCLASS(L_HEX,8) 00064 #define L_HEX_PMT LCLASS(L_HEX,16) 00065 #define L_HEX_HOOK LCLASS(L_HEX,32) 00066 #define L_HEX_ALL LALL(L_HEX_HOOK) 00067 00068 static const struct LogModule lm_hex = { 00069 (LMOD_ENABLE|L_HEX_ALL)&LOPT_MASK, 00070 (LMOD_ENABLE)&LOPT_MASK, 00071 "hexdata", 00072 { "ecm","emm","cat","pmt","hook" } 00073 }; 00074 ADD_MODULE(L_HEX,lm_hex) 00075 00076 static const char *typeNames[] = { "typ0","typ1","VIDEO","typ3","AUDIO","typ5","DOLBY","typ6+" }; 00077 #define TYPENAME(type) (typeNames[(type)<=7?(type):7]) 00078 00079 // -- cLogStats --------------------------------------------------------------- 00080 00081 #define COUNTS 20 00082 #define SAMPLE (30*1000) 00083 #define AVR1 (60*1000) 00084 #define AVR2 (4*60*1000) 00085 #define AVR3 (10*60*1000) 00086 #define REPORT (60*1000) 00087 00088 class cLogStats : public cThread { 00089 private: 00090 cTimeMs sTime, repTime; 00091 int sCount, sIdx, sCounts[COUNTS][2]; 00092 protected: 00093 virtual void Action(void); 00094 public: 00095 cLogStats(void); 00096 ~cLogStats(); 00097 void Count(void); 00098 }; 00099 00100 static cMutex logstatsMutex; 00101 static cLogStats *logstats=0; 00102 00103 void LogStatsUp(void) 00104 { 00105 logstatsMutex.Lock(); 00106 if(LOG(L_CORE_AUSTATS) && !logstats) logstats=new cLogStats; 00107 logstatsMutex.Unlock(); 00108 } 00109 00110 void LogStatsDown(void) 00111 { 00112 logstatsMutex.Lock(); 00113 if(logstats) { delete logstats; logstats=0; } 00114 logstatsMutex.Unlock(); 00115 } 00116 00117 cLogStats::cLogStats(void) 00118 { 00119 sCount=sIdx=0; 00120 for(int i=0; i<COUNTS; i++) { sCounts[i][0]=0; sCounts[i][1]=SAMPLE; } 00121 SetDescription("logger stats"); 00122 Start(); 00123 } 00124 00125 cLogStats::~cLogStats() 00126 { 00127 Cancel(2); 00128 } 00129 00130 void cLogStats::Count(void) 00131 { 00132 sCount++; 00133 } 00134 00135 void cLogStats::Action(void) 00136 { 00137 while(Running()) { 00138 cCondWait::SleepMs(50); 00139 if(sTime.Elapsed()>SAMPLE) { 00140 sCounts[sIdx][0]=sCount; sCount=0; 00141 sCounts[sIdx][1]=sTime.Elapsed(); sTime.Set(); 00142 if(++sIdx >= COUNTS) sIdx=0; 00143 } 00144 if(repTime.Elapsed()>REPORT) { 00145 repTime.Set(); 00146 if(sCounts[(sIdx+COUNTS-1)%COUNTS][0]>0) { 00147 LBSTART(L_CORE_AUSTATS); 00148 LBPUT("EMM packet load average (%d/%d/%dmin)",AVR1/60000,AVR2/60000,AVR3/60000); 00149 int s=0, t=0; 00150 for(int i=1; i<=COUNTS; i++) { 00151 s+=sCounts[(sIdx+COUNTS-i)%COUNTS][0]; 00152 t+=sCounts[(sIdx+COUNTS-i)%COUNTS][1]; 00153 if(i==(AVR1/SAMPLE) || i==(AVR2/SAMPLE) || i==(AVR3/SAMPLE)) 00154 LBPUT(" %4d",(int)((float)s/(float)t*1000.0)); 00155 } 00156 LBPUT(" pks/s"); 00157 LBEND(); 00158 } 00159 } 00160 } 00161 } 00162 00163 // -- cHookManager ------------------------------------------------------------- 00164 00165 class cHookManager : public cAction { 00166 const char *devId; 00167 cSimpleList<cLogHook> hooks; 00168 // 00169 cPidFilter *AddFilter(int Pid, int Section, int Mask, int IdleTime); 00170 void ClearHooks(void); 00171 void DelHook(cLogHook *hook); 00172 protected: 00173 virtual void Process(cPidFilter *filter, unsigned char *data, int len); 00174 public: 00175 cHookManager(cDevice *Device, const char *DevId); 00176 virtual ~cHookManager(); 00177 void AddHook(cLogHook *hook); 00178 bool TriggerHook(int id); 00179 void Down(void); 00180 }; 00181 00182 cHookManager::cHookManager(cDevice *Device, const char *DevId) 00183 :cAction("hookmanager",Device,DevId) 00184 { 00185 devId=DevId; 00186 Priority(10); 00187 } 00188 00189 cHookManager::~cHookManager() 00190 { 00191 Down(); 00192 } 00193 00194 void cHookManager::Down(void) 00195 { 00196 Lock(); 00197 while(cLogHook *hook=hooks.First()) DelHook(hook); 00198 DelAllFilter(); 00199 Unlock(); 00200 } 00201 00202 bool cHookManager::TriggerHook(int id) 00203 { 00204 Lock(); 00205 for(cLogHook *hook=hooks.First(); hook; hook=hooks.Next(hook)) 00206 if(hook->id==id) { 00207 hook->delay.Set(CHAIN_HOLD); 00208 Unlock(); 00209 return true; 00210 } 00211 Unlock(); 00212 return false; 00213 } 00214 00215 void cHookManager::AddHook(cLogHook *hook) 00216 { 00217 Lock(); 00218 PRINTF(L_CORE_HOOK,"%s: starting hook '%s' (%04x)",devId,hook->name,hook->id); 00219 hook->delay.Set(CHAIN_HOLD); 00220 hooks.Add(hook); 00221 for(cPid *pid=hook->pids.First(); pid; pid=hook->pids.Next(pid)) { 00222 cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,CHAIN_HOLD/8); 00223 if(filter) { 00224 filter->userData=(void *)hook; 00225 pid->filter=filter; 00226 } 00227 } 00228 Unlock(); 00229 } 00230 00231 void cHookManager::DelHook(cLogHook *hook) 00232 { 00233 PRINTF(L_CORE_HOOK,"%s: stopping hook '%s' (%04x)",devId,hook->name,hook->id); 00234 for(cPid *pid=hook->pids.First(); pid; pid=hook->pids.Next(pid)) { 00235 cPidFilter *filter=pid->filter; 00236 if(filter) { 00237 DelFilter(filter); 00238 pid->filter=0; 00239 } 00240 } 00241 hooks.Del(hook); 00242 } 00243 00244 cPidFilter *cHookManager::AddFilter(int Pid, int Section, int Mask, int IdleTime) 00245 { 00246 cPidFilter *filter=NewFilter(IdleTime); 00247 if(filter) { 00248 filter->SetBuffSize(32768); 00249 filter->Start(Pid,Section,Mask); 00250 PRINTF(L_CORE_HOOK,"%s: added filter pid=0x%.4x sct=0x%.2x/0x%.2x idle=%d",devId,Pid,Section,Mask,IdleTime); 00251 } 00252 else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for hookmanager %s",devId); 00253 return filter; 00254 } 00255 00256 void cHookManager::Process(cPidFilter *filter, unsigned char *data, int len) 00257 { 00258 if(data && len>0) { 00259 HEXDUMP(L_HEX_HOOK,data,len,"HOOK pid 0x%04x",filter->Pid()); 00260 if(SCT_LEN(data)==len) { 00261 cLogHook *hook=(cLogHook *)(filter->userData); 00262 if(hook) { 00263 hook->Process(filter->Pid(),data); 00264 if(hook->bailOut || hook->delay.TimedOut()) DelHook(hook); 00265 } 00266 } 00267 else PRINTF(L_CORE_HOOK,"%s: incomplete section %d != %d",devId,len,SCT_LEN(data)); 00268 } 00269 else { 00270 cLogHook *hook=(cLogHook *)(filter->userData); 00271 if(hook && (hook->bailOut || hook->delay.TimedOut())) DelHook(hook); 00272 } 00273 } 00274 00275 // -- cLogChain ---------------------------------------------------------------- 00276 00277 class cLogChain : public cSimpleItem { 00278 public: 00279 cCam *cam; 00280 const char *devId; 00281 int caid, source, transponder; 00282 bool softCSA, active, delayed; 00283 cTimeMs delay; 00284 cPids pids; 00285 cSimpleList<cSystem> systems; 00286 // 00287 cLogChain(cCam *Cam, const char *DevId, bool soft, int src, int tr); 00288 void Process(int pid, const unsigned char *data); 00289 bool Parse(const unsigned char *cat); 00290 }; 00291 00292 cLogChain::cLogChain(cCam *Cam, const char *DevId, bool soft, int src, int tr) 00293 { 00294 cam=Cam; devId=DevId; softCSA=soft; source=src; transponder=tr; 00295 active=delayed=false; 00296 } 00297 00298 void cLogChain::Process(int pid, const unsigned char *data) 00299 { 00300 if(active) { 00301 for(cSystem *sys=systems.First(); sys; sys=systems.Next(sys)) 00302 sys->ProcessEMM(pid,caid,data); 00303 } 00304 } 00305 00306 bool cLogChain::Parse(const unsigned char *cat) 00307 { 00308 if(cat[0]==0x09) { 00309 caid=WORD(cat,2,0xFFFF); 00310 LBSTARTF(L_CORE_AU); 00311 LBPUT("%s: chain caid %04x",devId,caid); 00312 cSystem *sys; 00313 if(systems.Count()>0) { 00314 LBPUT(" ++"); 00315 for(sys=systems.First(); sys; sys=systems.Next(sys)) 00316 sys->ParseCAT(&pids,cat,source,transponder); 00317 } 00318 else { 00319 LBPUT(" ->"); 00320 if(!overrides.Ignore(source,transponder,caid)) { 00321 int Pri=0; 00322 while((sys=cSystems::FindBySysId(caid,!softCSA,Pri))) { 00323 Pri=sys->Pri(); 00324 if(sys->HasLogger()) { 00325 sys->SetOwner(cam); 00326 sys->ParseCAT(&pids,cat,source,transponder); 00327 systems.Add(sys); 00328 LBPUT(" %s(%d)",sys->Name(),sys->Pri()); 00329 } 00330 else 00331 delete sys; 00332 } 00333 } 00334 } 00335 if(systems.Count()==0) LBPUT(" none available"); 00336 for(cPid *pid=pids.First(); pid; pid=pids.Next(pid)) 00337 LBPUT(" [%04x-%02x/%02x]",pid->pid,pid->sct,pid->mask); 00338 LBEND(); 00339 if(systems.Count()>0 && pids.Count()>0) 00340 return true; 00341 } 00342 return false; 00343 } 00344 00345 // -- cLogger ------------------------------------------------------------------ 00346 00347 class cLogger : public cAction { 00348 private: 00349 cCam *cam; 00350 const char *devId; 00351 bool softCSA, up; 00352 cSimpleList<cLogChain> chains; 00353 cSimpleList<cEcmInfo> active; 00354 // 00355 cPidFilter *catfilt; 00356 int catVers; 00357 int source, transponder; 00358 // 00359 enum ePreMode { pmNone, pmStart, pmWait, pmActive, pmStop }; 00360 ePreMode prescan; 00361 cTimeMs pretime; 00362 // 00363 cPidFilter *AddFilter(int Pid, int Section, int Mask, int IdleTime); 00364 void SetChains(void); 00365 void ClearChains(void); 00366 void StartChain(cLogChain *chain); 00367 void StopChain(cLogChain *chain, bool force); 00368 void ProcessCat(unsigned char *data, int len); 00369 protected: 00370 virtual void Process(cPidFilter *filter, unsigned char *data, int len); 00371 public: 00372 cLogger(cCam *Cam, cDevice *Device, const char *DevId, bool soft); 00373 virtual ~cLogger(); 00374 void EcmStatus(const cEcmInfo *ecm, bool on); 00375 void Up(void); 00376 void Down(void); 00377 void PreScan(int src, int tr); 00378 }; 00379 00380 cLogger::cLogger(cCam *Cam, cDevice *Device, const char *DevId, bool soft) 00381 :cAction("logger",Device,DevId) 00382 { 00383 cam=Cam; devId=DevId; softCSA=soft; 00384 catfilt=0; up=false; prescan=pmNone; 00385 Priority(10); 00386 } 00387 00388 cLogger::~cLogger() 00389 { 00390 Down(); 00391 } 00392 00393 void cLogger::Up(void) 00394 { 00395 Lock(); 00396 if(!up) { 00397 PRINTF(L_CORE_AUEXTRA,"%s: UP",devId); 00398 catVers=-1; 00399 catfilt=AddFilter(1,0x01,0xFF,0); 00400 up=true; 00401 } 00402 Unlock(); 00403 } 00404 00405 void cLogger::Down(void) 00406 { 00407 Lock(); 00408 if(up) { 00409 PRINTF(L_CORE_AUEXTRA,"%s: DOWN",devId); 00410 ClearChains(); 00411 DelAllFilter(); 00412 catfilt=0; up=false; prescan=pmNone; 00413 } 00414 Unlock(); 00415 } 00416 00417 void cLogger::PreScan(int src, int tr) 00418 { 00419 Lock(); 00420 source=src; transponder=tr; 00421 prescan=pmStart; Up(); 00422 Unlock(); 00423 } 00424 00425 void cLogger::EcmStatus(const cEcmInfo *ecm, bool on) 00426 { 00427 Lock(); 00428 PRINTF(L_CORE_AUEXTRA,"%s: ecm prgid=%d caid=%04x prov=%.4x %s",devId,ecm->prgId,ecm->caId,ecm->provId,on ? "active":"inactive"); 00429 source=ecm->source; transponder=ecm->transponder; 00430 cEcmInfo *e; 00431 if(on) { 00432 e=new cEcmInfo(ecm); 00433 active.Add(e); 00434 if(!up) Up(); 00435 } 00436 else { 00437 for(e=active.First(); e; e=active.Next(e)) 00438 if(e->Compare(ecm)) { 00439 active.Del(e); 00440 break; 00441 } 00442 } 00443 if(prescan>=pmWait) prescan=pmStop; 00444 SetChains(); 00445 prescan=pmNone; 00446 Unlock(); 00447 } 00448 00449 void cLogger::SetChains(void) 00450 { 00451 for(cLogChain *chain=chains.First(); chain; chain=chains.Next(chain)) { 00452 bool act=false; 00453 if(ScSetup.AutoUpdate>1 || prescan==pmActive) act=true; 00454 else if(ScSetup.AutoUpdate==1) { 00455 for(cEcmInfo *e=active.First(); e; e=active.Next(e)) 00456 if((e->emmCaId && chain->caid==e->emmCaId) || chain->caid==e->caId) { 00457 act=true; break; 00458 } 00459 } 00460 if(act) StartChain(chain); 00461 else StopChain(chain,prescan==pmStop); 00462 } 00463 } 00464 00465 void cLogger::ClearChains(void) 00466 { 00467 for(cLogChain *chain=chains.First(); chain; chain=chains.Next(chain)) 00468 StopChain(chain,true); 00469 chains.Clear(); 00470 } 00471 00472 void cLogger::StartChain(cLogChain *chain) 00473 { 00474 if(chain->delayed) 00475 PRINTF(L_CORE_AUEXTRA,"%s: restarting delayed chain %04x",devId,chain->caid); 00476 chain->delayed=false; 00477 if(!chain->active) { 00478 PRINTF(L_CORE_AU,"%s: starting chain %04x",devId,chain->caid); 00479 chain->active=true; 00480 for(cPid *pid=chain->pids.First(); pid; pid=chain->pids.Next(pid)) { 00481 cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,CHAIN_HOLD/8); 00482 if(filter) { 00483 filter->userData=(void *)chain; 00484 pid->filter=filter; 00485 } 00486 } 00487 } 00488 } 00489 00490 void cLogger::StopChain(cLogChain *chain, bool force) 00491 { 00492 if(chain->active) { 00493 if(force || (chain->delayed && chain->delay.TimedOut())) { 00494 PRINTF(L_CORE_AU,"%s: stopping chain %04x",devId,chain->caid); 00495 chain->active=false; 00496 for(cPid *pid=chain->pids.First(); pid; pid=chain->pids.Next(pid)) { 00497 cPidFilter *filter=pid->filter; 00498 if(filter) { 00499 DelFilter(filter); 00500 pid->filter=0; 00501 } 00502 } 00503 } 00504 else if(!chain->delayed) { 00505 PRINTF(L_CORE_AUEXTRA,"%s: delaying chain %04x",devId,chain->caid); 00506 chain->delayed=true; 00507 chain->delay.Set(CHAIN_HOLD); 00508 } 00509 } 00510 } 00511 00512 cPidFilter *cLogger::AddFilter(int Pid, int Section, int Mask, int IdleTime) 00513 { 00514 cPidFilter *filter=NewFilter(IdleTime); 00515 if(filter) { 00516 if(Pid>1) filter->SetBuffSize(KILOBYTE(64)); 00517 filter->Start(Pid,Section,Mask); 00518 PRINTF(L_CORE_AUEXTRA,"%s: added filter pid=0x%.4x sct=0x%.2x/0x%.2x idle=%d",devId,Pid,Section,Mask,IdleTime); 00519 } 00520 else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for logger %s",devId); 00521 return filter; 00522 } 00523 00524 void cLogger::ProcessCat(unsigned char *data, int len) 00525 { 00526 for(int i=0; i<len; i+=data[i+1]+2) { 00527 if(data[i]==0x09) { 00528 int caid=WORD(data,i+2,0xFFFF); 00529 cLogChain *chain; 00530 for(chain=chains.First(); chain; chain=chains.Next(chain)) 00531 if(chain->caid==caid) break; 00532 if(chain) 00533 chain->Parse(&data[i]); 00534 else { 00535 chain=new cLogChain(cam,devId,softCSA,source,transponder); 00536 if(chain->Parse(&data[i])) 00537 chains.Add(chain); 00538 else 00539 delete chain; 00540 } 00541 } 00542 } 00543 } 00544 00545 void cLogger::Process(cPidFilter *filter, unsigned char *data, int len) 00546 { 00547 if(data && len>0) { 00548 if(filter==catfilt) { 00549 int vers=(data[5]&0x3E)>>1; 00550 if(data[0]==0x01 && vers!=catVers) { 00551 PRINTF(L_CORE_AUEXTRA,"%s: got CAT version %02x",devId,vers); 00552 catVers=vers; 00553 HEXDUMP(L_HEX_CAT,data,len,"CAT vers %02x",catVers); 00554 ClearChains(); 00555 ProcessCat(&data[8],len-4-8); 00556 unsigned char buff[2048]; 00557 if((len=overrides.GetCat(source,transponder,buff,sizeof(buff)))>0) { 00558 HEXDUMP(L_HEX_CAT,buff,len,"override CAT"); 00559 ProcessCat(buff,len); 00560 } 00561 SetChains(); 00562 if(prescan==pmStart) { prescan=pmWait; pretime.Set(2000); } 00563 } 00564 if(prescan==pmWait && pretime.TimedOut()) { prescan=pmActive; SetChains(); } 00565 } 00566 else { 00567 HEXDUMP(L_HEX_EMM,data,len,"EMM pid 0x%04x",filter->Pid()); 00568 if(logstats) logstats->Count(); 00569 if(SCT_LEN(data)==len) { 00570 cLogChain *chain=(cLogChain *)(filter->userData); 00571 if(chain) { 00572 chain->Process(filter->Pid(),data); 00573 if(chain->delayed) StopChain(chain,false); 00574 } 00575 } 00576 else PRINTF(L_CORE_AU,"%s: incomplete section %d != %d",devId,len,SCT_LEN(data)); 00577 } 00578 } 00579 else { 00580 cLogChain *chain=(cLogChain *)(filter->userData); 00581 if(chain && chain->delayed) StopChain(chain,false); 00582 } 00583 } 00584 00585 // -- cEcmData ----------------------------------------------------------------- 00586 00587 #define CACHE_VERS 1 00588 00589 class cEcmData : public cEcmInfo { 00590 public: 00591 cEcmData(void):cEcmInfo() {} 00592 cEcmData(cEcmInfo *e):cEcmInfo(e) {} 00593 virtual cString ToString(bool hide); 00594 bool Parse(const char *buf); 00595 }; 00596 00597 bool cEcmData::Parse(const char *buf) 00598 { 00599 char Name[64]; 00600 int nu=0, num, vers=0; 00601 Name[0]=0; 00602 if(sscanf(buf,"V%d:%d:%x:%x:%63[^:]:%x/%x:%x:%x/%x:%d:%d/%d%n", 00603 &vers,&grPrgId,&source,&transponder,Name,&caId,&emmCaId,&provId, 00604 &ecm_pid,&ecm_table,&rewriterId,&nu,&dataIdx,&num)>=13 00605 && vers==CACHE_VERS) { 00606 SetName(Name); 00607 SetRewriter(); 00608 prgId=grPrgId%SIDGRP_SHIFT; 00609 const char *line=buf+num; 00610 if(nu>0 && *line++==':') { 00611 unsigned char *dat=AUTOMEM(nu); 00612 if(GetHex(line,dat,nu,true)==nu && dat[0]==0x09 && dat[1]==nu-2) 00613 AddCaDescr(dat,nu); 00614 } 00615 return true; 00616 } 00617 return false; 00618 } 00619 00620 cString cEcmData::ToString(bool hide) 00621 { 00622 char *str; 00623 if(caDescr) { 00624 str=AUTOARRAY(char,caDescrLen*2+16); 00625 int q=sprintf(str,"%d/%d:",caDescrLen,dataIdx); 00626 HexStr(str+q,caDescr,caDescrLen); 00627 } 00628 else { 00629 str=AUTOARRAY(char,10); 00630 sprintf(str,"0/%d:",dataIdx); 00631 } 00632 return cString::sprintf("V%d:%d:%x:%x:%s:%x/%x:%x:%x/%x:%d:%s", 00633 CACHE_VERS,grPrgId,source,transponder,name, 00634 caId,emmCaId,provId,ecm_pid,ecm_table,rewriterId, 00635 str); 00636 } 00637 00638 // -- cEcmCache ---------------------------------------------------------------- 00639 00640 cEcmCache ecmcache; 00641 00642 cEcmCache::cEcmCache(void) 00643 :cStructListPlain<cEcmData>("ecm cache",ECMCACHE_FILE,SL_READWRITE|SL_MISSINGOK) 00644 {} 00645 00646 void cEcmCache::New(cEcmInfo *e) 00647 { 00648 if(ScSetup.EcmCache>0) return; 00649 ListLock(true); 00650 cEcmData *dat; 00651 if(!(dat=Exists(e))) { 00652 dat=new cEcmData(e); 00653 Add(dat); 00654 Modified(); 00655 PRINTF(L_CORE_ECM,"cache add prgId=%d source=%x transponder=%x ecm=%x/%x",e->grPrgId,e->source,e->transponder,e->ecm_pid,e->ecm_table); 00656 } 00657 else { 00658 if(strcasecmp(e->name,dat->name)) { 00659 dat->SetName(e->name); 00660 Modified(); 00661 } 00662 if(dat->AddCaDescr(e)) 00663 Modified(); 00664 } 00665 ListUnlock(); 00666 e->SetCached(); 00667 } 00668 00669 cEcmData *cEcmCache::Exists(cEcmInfo *e) 00670 { 00671 cEcmData *dat; 00672 for(dat=First(); dat; dat=Next(dat)) 00673 if(dat->Compare(e)) break; 00674 return dat; 00675 } 00676 00677 int cEcmCache::GetCached(cSimpleList<cEcmInfo> *list, int sid, int Source, int Transponder) 00678 { 00679 int n=0; 00680 list->Clear(); 00681 if(ScSetup.EcmCache>1) return 0; 00682 ListLock(false); 00683 for(cEcmData *dat=First(); dat; dat=Next(dat)) { 00684 if(dat->grPrgId==sid && dat->source==Source && dat->transponder==Transponder) { 00685 cEcmInfo *e=new cEcmInfo(dat); 00686 if(e) { 00687 PRINTF(L_CORE_ECM,"from cache: system %s (%04x) id %04x with ecm %x/%x",e->name,e->caId,e->provId,e->ecm_pid,e->ecm_table); 00688 e->SetCached(); 00689 list->Add(e); 00690 n++; 00691 } 00692 } 00693 } 00694 ListUnlock(); 00695 return n; 00696 } 00697 00698 void cEcmCache::Delete(cEcmInfo *e) 00699 { 00700 if(ScSetup.EcmCache>0) return; 00701 ListLock(false); 00702 cEcmData *dat=Exists(e); 00703 ListUnlock(); 00704 if(dat) { 00705 DelItem(dat); 00706 PRINTF(L_CORE_ECM,"invalidated cached prgId=%d source=%x transponder=%x ecm=%x/%x",dat->grPrgId,dat->source,dat->transponder,dat->ecm_pid,dat->ecm_table); 00707 } 00708 } 00709 00710 void cEcmCache::Flush(void) 00711 { 00712 ListLock(true); 00713 Clear(); 00714 Modified(); 00715 PRINTF(L_CORE_ECM,"cache flushed"); 00716 ListUnlock(); 00717 } 00718 00719 bool cEcmCache::ParseLinePlain(const char *line) 00720 { 00721 cEcmData *dat=new cEcmData; 00722 if(dat && dat->Parse(line) && !Exists(dat)) Add(dat); 00723 else delete dat; 00724 return true; 00725 } 00726 00727 // -- cCaDescr ----------------------------------------------------------------- 00728 00729 cCaDescr::cCaDescr(void) 00730 { 00731 descr=0; len=0; 00732 } 00733 00734 cCaDescr::cCaDescr(const cCaDescr &cd) 00735 { 00736 descr=0; len=0; 00737 Set(cd.descr,cd.len); 00738 } 00739 00740 cCaDescr::~cCaDescr() 00741 { 00742 Clear(); 00743 } 00744 00745 const unsigned char *cCaDescr::Get(int &l) const 00746 { 00747 l=len; 00748 return descr; 00749 } 00750 00751 void cCaDescr::Set(const cCaDescr *d) 00752 { 00753 Set(d->descr,d->len); 00754 } 00755 00756 void cCaDescr::Set(const unsigned char *de, int l) 00757 { 00758 Clear(); 00759 if(l) { 00760 descr=MALLOC(unsigned char,l); 00761 if(descr) { 00762 memcpy(descr,de,l); 00763 len=l; 00764 } 00765 } 00766 } 00767 00768 void cCaDescr::Clear(void) 00769 { 00770 free(descr); descr=0; len=0; 00771 } 00772 00773 void cCaDescr::Join(const cCaDescr *cd, bool rev) 00774 { 00775 if(cd->descr) { 00776 int l=len+cd->len; 00777 unsigned char *m=MALLOC(unsigned char,l); 00778 if(m) { 00779 if(!rev) { 00780 if(descr) memcpy(m,descr,len); 00781 memcpy(m+len,cd->descr,cd->len); 00782 } 00783 else { 00784 memcpy(m,cd->descr,cd->len); 00785 if(descr) memcpy(m+cd->len,descr,len); 00786 } 00787 Clear(); 00788 descr=m; len=l; 00789 } 00790 } 00791 } 00792 00793 bool cCaDescr::operator== (const cCaDescr &cd) const 00794 { 00795 return len==cd.len && (len==0 || memcmp(descr,cd.descr,len)==0); 00796 } 00797 00798 cString cCaDescr::ToString(void) 00799 { 00800 if(!descr) return "<empty>"; 00801 char *str=AUTOARRAY(char,len*3+8); 00802 int q=sprintf(str,"%02X",descr[0]); 00803 for(int i=1; i<len; i++) q+=sprintf(str+q," %02X",descr[i]); 00804 return str; 00805 } 00806 00807 // -- cPrg --------------------------------------------------------------------- 00808 00809 cPrg::cPrg(void) 00810 { 00811 Setup(); 00812 } 00813 00814 cPrg::cPrg(int Sid, bool IsUpdate) 00815 { 00816 Setup(); 00817 sid=Sid; isUpdate=IsUpdate; 00818 } 00819 00820 void cPrg::Setup(void) 00821 { 00822 sid=-1; source=-1; transponder=-1; 00823 isUpdate=pidCaDescr=false; 00824 } 00825 00826 void cPrg::DumpCaDescr(int c) 00827 { 00828 PRINTF(c,"prgca: %s",*caDescr.ToString()); 00829 for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid)) 00830 PRINTF(c,"pidca %04x: %s",pid->pid,*pid->caDescr.ToString()); 00831 } 00832 00833 bool cPrg::SimplifyCaDescr(void) 00834 { 00835 if(HasPidCaDescr()) { 00836 bool equal=true; 00837 if(pids.Count()>1) { 00838 cPrgPid *pid0=pids.First(); 00839 for(cPrgPid *pid1=pids.Next(pid0); pid1; pid1=pids.Next(pid1)) 00840 if(!(pid0->caDescr==pid1->caDescr)) { equal=false; break; } 00841 } 00842 if(equal) { 00843 cPrgPid *pid=pids.First(); 00844 caDescr.Join(&pid->caDescr); 00845 for(; pid; pid=pids.Next(pid)) pid->caDescr.Clear(); 00846 SetPidCaDescr(false); 00847 } 00848 } 00849 if(HasPidCaDescr()) { 00850 for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid)) 00851 pid->caDescr.Join(&caDescr,true); 00852 caDescr.Clear(); 00853 } 00854 00855 PRINTF(L_CORE_PIDS,"Ca descriptors after simplify (pidCa=%d)",HasPidCaDescr()); 00856 DumpCaDescr(L_CORE_PIDS); 00857 00858 return HasPidCaDescr(); 00859 } 00860 00861 // -- cEcmPri ------------------------------------------------------------------ 00862 00863 class cEcmPri : public cSimpleItem { 00864 public: 00865 cEcmInfo *ecm; 00866 int pri, sysIdent; 00867 }; 00868 00869 // -- cEcmHandler -------------------------------------------------------------- 00870 00871 class cEcmHandler : public cSimpleItem, public cAction { 00872 private: 00873 const char *devId; 00874 int cwIndex; 00875 cCam *cam; 00876 char *id; 00877 cTimeMs idleTime; 00878 // 00879 cMutex dataMutex; 00880 cPrg prg; 00881 // 00882 cSystem *sys; 00883 cPidFilter *filter; 00884 int filterCwIndex, filterSource, filterTransponder, filterSid; 00885 cCaDescr filterCaDescr; 00886 unsigned char lastCw[16]; 00887 bool sync, noKey, trigger, ecmUpd; 00888 int triggerMode; 00889 int mode, count; 00890 cTimeMs lastsync, startecm, resendTime; 00891 unsigned int cryptPeriod; 00892 unsigned char parity; 00893 cMsgCache failed; 00894 // 00895 cSimpleList<cEcmInfo> ecmList; 00896 cSimpleList<cEcmPri> ecmPriList; 00897 cEcmInfo *ecm; 00898 cEcmPri *ecmPri; 00899 // 00900 int dolog; 00901 // 00902 void DeleteSys(void); 00903 void NoSync(bool clearParity); 00904 cEcmInfo *NewEcm(void); 00905 cEcmInfo *JumpEcm(void); 00906 void StopEcm(void); 00907 bool UpdateEcm(void); 00908 void EcmOk(void); 00909 void EcmFail(void); 00910 void ParseCAInfo(int sys); 00911 void AddEcmPri(cEcmInfo *n); 00912 protected: 00913 virtual void Process(cPidFilter *filter, unsigned char *data, int len); 00914 public: 00915 cEcmHandler(cCam *Cam, cDevice *Device, const char *DevId, int cwindex); 00916 virtual ~cEcmHandler(); 00917 void Stop(void); 00918 void SetPrg(cPrg *Prg); 00919 void ShiftCwIndex(int cwindex); 00920 char *CurrentKeyStr(void) const; 00921 bool IsRemoveable(void); 00922 bool IsIdle(void); 00923 int Sid(void) const { return prg.sid; } 00924 int CwIndex(void) const { return cwIndex; } 00925 const char *Id(void) const { return id; } 00926 }; 00927 00928 cEcmHandler::cEcmHandler(cCam *Cam, cDevice *Device, const char *DevId, int cwindex) 00929 :cAction("ecmhandler",Device,DevId) 00930 ,failed(32,0) 00931 { 00932 cam=Cam; 00933 devId=DevId; 00934 cwIndex=cwindex; 00935 sys=0; filter=0; ecm=0; ecmPri=0; mode=-1; 00936 trigger=ecmUpd=false; triggerMode=-1; 00937 filterSource=filterTransponder=0; filterCwIndex=-1; filterSid=-1; 00938 id=bprintf("%s.%d",devId,cwindex); 00939 } 00940 00941 cEcmHandler::~cEcmHandler() 00942 { 00943 Lock(); 00944 StopEcm(); 00945 DelAllFilter(); // delete filters before sys for multi-threading reasons 00946 DeleteSys(); 00947 Unlock(); 00948 free(id); 00949 } 00950 00951 bool cEcmHandler::IsIdle(void) 00952 { 00953 dataMutex.Lock(); 00954 int n=prg.pids.Count(); 00955 dataMutex.Unlock(); 00956 return n==0; 00957 } 00958 00959 bool cEcmHandler::IsRemoveable(void) 00960 { 00961 return IsIdle() && idleTime.Elapsed()>MAX_ECM_IDLE; 00962 } 00963 00964 void cEcmHandler::Stop(void) 00965 { 00966 dataMutex.Lock(); 00967 if(!IsIdle() || prg.sid!=-1) { 00968 PRINTF(L_CORE_ECM,"%s: stop",id); 00969 prg.sid=-1; 00970 idleTime.Set(); 00971 prg.pids.Clear(); 00972 trigger=true; 00973 } 00974 dataMutex.Unlock(); 00975 if(filter) filter->Wakeup(); 00976 } 00977 00978 void cEcmHandler::ShiftCwIndex(int cwindex) 00979 { 00980 if(cwIndex!=cwindex) { 00981 PRINTF(L_CORE_PIDS,"%s: shifting cwIndex from %d to %d",id,cwIndex,cwindex); 00982 free(id); 00983 id=bprintf("%s.%d",devId,cwindex); 00984 dataMutex.Lock(); 00985 trigger=true; 00986 cwIndex=cwindex; 00987 for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid)) 00988 cam->SetCWIndex(pid->pid,cwIndex); 00989 dataMutex.Unlock(); 00990 if(filter) filter->Wakeup(); 00991 } 00992 } 00993 00994 void cEcmHandler::SetPrg(cPrg *Prg) 00995 { 00996 dataMutex.Lock(); 00997 bool wasIdle=IsIdle(); 00998 if(Prg->sid!=prg.sid) { 00999 PRINTF(L_CORE_ECM,"%s: setting new SID %d",id,Prg->sid); 01000 prg.sid=Prg->sid; 01001 prg.source=Prg->source; 01002 prg.transponder=Prg->transponder; 01003 idleTime.Set(); 01004 prg.pids.Clear(); 01005 trigger=true; 01006 } 01007 if(Prg->HasPidCaDescr()) 01008 PRINTF(L_GEN_DEBUG,"internal: pid specific caDescr not supported at this point (sid=%d)",Prg->sid); 01009 LBSTART(L_CORE_PIDS); 01010 LBPUT("%s: pids on entry",id); 01011 for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid)) 01012 LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid); 01013 LBEND(); 01014 01015 for(cPrgPid *pid=prg.pids.First(); pid;) { 01016 cPrgPid *npid; 01017 for(npid=Prg->pids.First(); npid; npid=Prg->pids.Next(npid)) { 01018 if(pid->pid==npid->pid) { 01019 npid->Proc(true); 01020 break; 01021 } 01022 } 01023 if(!npid) { 01024 npid=prg.pids.Next(pid); 01025 prg.pids.Del(pid); 01026 pid=npid; 01027 } 01028 else pid=prg.pids.Next(pid); 01029 } 01030 LBSTART(L_CORE_PIDS); 01031 LBPUT("%s: pids after delete",id); 01032 for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid)) 01033 LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid); 01034 LBEND(); 01035 for(cPrgPid *npid=Prg->pids.First(); npid; npid=Prg->pids.Next(npid)) { 01036 if(!npid->Proc()) { 01037 cPrgPid *pid=new cPrgPid(npid->type,npid->pid); 01038 prg.pids.Add(pid); 01039 cam->SetCWIndex(pid->pid,cwIndex); 01040 } 01041 } 01042 LBSTART(L_CORE_PIDS); 01043 LBPUT("%s: pids after add",id); 01044 for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid)) 01045 LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid); 01046 LBEND(); 01047 if(!IsIdle()) { 01048 if(!(prg.caDescr==Prg->caDescr)) prg.caDescr.Set(&Prg->caDescr); 01049 trigger=true; 01050 triggerMode=0; 01051 if(wasIdle) PRINTF(L_CORE_ECM,"%s: is no longer idle",id); 01052 } 01053 else { 01054 if(!wasIdle) idleTime.Set(); 01055 PRINTF(L_CORE_ECM,"%s: is idle%s",id,wasIdle?"":" now"); 01056 } 01057 01058 if(!filter) { 01059 filter=NewFilter(IDLE_SLEEP); 01060 if(!filter) PRINTF(L_GEN_ERROR,"failed to open ECM filter in handler %s",id); 01061 } 01062 dataMutex.Unlock(); 01063 if(filter) filter->Wakeup(); 01064 } 01065 01066 void cEcmHandler::Process(cPidFilter *filter, unsigned char *data, int len) 01067 { 01068 dataMutex.Lock(); 01069 if(trigger) { 01070 PRINTF(L_CORE_ECM,"%s: triggered SID %d/%d idx %d/%d mode %d/%d %s", 01071 id,filterSid,prg.sid,filterCwIndex,cwIndex,mode,triggerMode,(mode==3 && sync)?"sync":"-"); 01072 trigger=false; 01073 if(filterSid!=prg.sid) { 01074 filterSid=prg.sid; 01075 filterSource=prg.source; 01076 filterTransponder=prg.transponder; 01077 filterCwIndex=cwIndex; 01078 noKey=true; mode=0; 01079 } 01080 else { 01081 if(filterCwIndex!=cwIndex) { 01082 filterCwIndex=cwIndex; 01083 if(mode==3 && sync) 01084 cam->WriteCW(filterCwIndex,lastCw,true); 01085 } 01086 if(mode<triggerMode) mode=triggerMode; 01087 } 01088 if(!(prg.caDescr==filterCaDescr)) { 01089 filterCaDescr.Set(&prg.caDescr); 01090 ecmUpd=true; 01091 //XXX 01092 PRINTF(L_CORE_ECM,"%s: new caDescr: %s",id,*filterCaDescr.ToString()); 01093 } 01094 triggerMode=-1; 01095 } 01096 dataMutex.Unlock(); 01097 01098 switch(mode) { 01099 case -1: 01100 filter->SetIdleTime(IDLE_SLEEP); 01101 break; 01102 01103 case 0: 01104 StopEcm(); 01105 if(IsIdle()) { mode=-1; break; } 01106 01107 dolog=LOG_COUNT; 01108 NewEcm(); 01109 filter->SetIdleTime(IDLE_GETCA); 01110 startecm.Set(); 01111 mode=1; 01112 break; 01113 01114 case 1: 01115 if(!ecm && !JumpEcm()) { 01116 if(startecm.Elapsed()>IDLE_GETCA_SLOW) { 01117 if(IsIdle()) { mode=0; break; } 01118 PRINTF(L_CORE_ECM,"%s: no encryption system found",id); 01119 filter->SetIdleTime(IDLE_GETCA_SLOW/4); 01120 startecm.Set(); 01121 } 01122 break; 01123 } 01124 mode=4; 01125 // fall through 01126 01127 case 4: 01128 case 5: 01129 NoSync(mode==4); 01130 failed.Clear(); 01131 filter->SetIdleTime(IDLE_NO_SYNC/2); 01132 lastsync.Set(); 01133 cryptPeriod=20*1000; 01134 mode=2; 01135 // fall through 01136 01137 case 2: 01138 if(sys->NeedsData()) { 01139 if(!UpdateEcm()) { 01140 if(lastsync.Elapsed()<ECM_DATA_TIME) break; 01141 PRINTF(L_CORE_ECM,"%s: no ecm extra data update (waited %d ms)",id,(int)lastsync.Elapsed()); 01142 } 01143 if(lastsync.Elapsed()>IDLE_NO_SYNC/4 && dolog) 01144 PRINTF(L_CORE_ECM,"%s: ecm extra data update took %d ms",id,(int)lastsync.Elapsed()); 01145 } 01146 filter->SetIdleTime(IDLE_NO_SYNC); 01147 mode=3; 01148 // fall through 01149 01150 case 3: 01151 { 01152 bool resend=false, cwok=false; 01153 if(resendTime.TimedOut()) { 01154 resend=sync; resendTime.Set(8*24*60*60*1000); 01155 } 01156 01157 if(startecm.Elapsed()<3*60*1000) cam->DumpAV7110(); 01158 01159 if(data && len>0) { 01160 HEXDUMP(L_HEX_ECM,data,len,"ECM sys 0x%04x id 0x%02x pid 0x%04x",ecm->caId,ecm->provId,filter->Pid()); 01161 if(SCT_LEN(data)==len) { 01162 if(ecm->rewriter) { 01163 ecm->rewriter->Rewrite(data,len); 01164 HEXDUMP(L_HEX_ECM,data,len,"rewritten to"); 01165 } 01166 LDUMP(L_CORE_ECMPROC,data,16,"%s: ECM",id); 01167 int n; 01168 if(!(n=sys->CheckECM(ecm,data,sync))) { 01169 if(resend || parity!=(data[0]&1)) { 01170 int ecmid; 01171 cTimeMs procTime; 01172 cwok=(ecmid=failed.Get(data,len,0))>=0 && sys->ProcessECM(ecm,data); 01173 n=(ecmid>0)?failed.Cache(ecmid,cwok,0):99; 01174 sys->CheckECMResult(ecm,data,cwok); 01175 if(cwok) { 01176 parity=data[0]&1; 01177 } 01178 else { 01179 if(procTime.Elapsed()>6000) { 01180 PRINTF(L_CORE_ECM,"%s: filter flush (elapsed %d)",id,(int)procTime.Elapsed()); 01181 filter->Flush(); 01182 } 01183 if(n>=2) { count++; if(n==2) count++; } 01184 parity=0xFF; 01185 if(sync && lastsync.Elapsed()>cryptPeriod*2) { 01186 PRINTF(L_CORE_ECM,"%s: lost sync (period %d, elapsed %d)",id,cryptPeriod,(int)lastsync.Elapsed()); 01187 NoSync(true); 01188 } 01189 } 01190 PRINTF(L_CORE_ECMPROC,"%s: (%s) cwok=%d ecmid=%d n=%d sync=%d parity=%d count=%d ELA=%d", 01191 id,sys->Name(),cwok,ecmid,n,sync,parity,count,(int)procTime.Elapsed()); 01192 } 01193 } 01194 else { 01195 PRINTF(L_CORE_ECMPROC,"%s: check result %d",id,n); 01196 switch(n) { 01197 case 1: NoSync(true); break; 01198 case 2: count++; break; 01199 case 3: break; 01200 } 01201 } 01202 } 01203 else { 01204 PRINTF(L_CORE_ECM,"%s: incomplete section %d != %d",id,len,SCT_LEN(data)); 01205 count++; 01206 } 01207 } 01208 else if(sys->Constant()) { 01209 if(sys->ProcessECM(ecm,NULL)) { 01210 cwok=true; 01211 if(sync) filter->SetIdleTime(IDLE_SYNC*10); 01212 } 01213 else count++; 01214 } 01215 else count++; 01216 01217 if(cwok) { 01218 dolog=LOG_COUNT; sys->DoLog(true); 01219 cam->WriteCW(filterCwIndex,sys->CW(),resend || !sync); 01220 memcpy(lastCw,sys->CW(),sizeof(lastCw)); 01221 noKey=false; count=0; 01222 UpdateEcm(); EcmOk(); 01223 if(!sync) { 01224 sync=true; 01225 filter->SetIdleTime(IDLE_SYNC); 01226 PRINTF(L_CORE_ECM,"%s: correct key found",id); 01227 if(!cam->IsSoftCSA(filterCwIndex==0)) 01228 resendTime.Set(CW_REPEAT_TIME); 01229 } 01230 else if(!resend) 01231 cryptPeriod=max(5000,min(60000,(int)lastsync.Elapsed())); 01232 lastsync.Set(); 01233 } 01234 01235 if(!sync && !trigger) { 01236 if(count>=sys->MaxEcmTry()) { 01237 EcmFail(); JumpEcm(); 01238 mode=4; 01239 if(!ecm) { 01240 JumpEcm(); 01241 if(!ecm) { // this should not happen! 01242 PRINTF(L_GEN_DEBUG,"internal: handler %s, empty ecm list in sync loop",id); 01243 mode=0; break; 01244 } 01245 // if we looped through all systems, we wait until the next parity 01246 // change before we try again. 01247 if(dolog!=LOG_COUNT && data) { parity=data[0]&1; mode=5; } 01248 if(dolog && !--dolog) { 01249 sys->DoLog(false); 01250 PRINTF(L_CORE_ECM,"%s: stopping message log until valid key is found",id); 01251 } 01252 } 01253 break; 01254 } 01255 } 01256 01257 if(IsIdle() && idleTime.Elapsed()>MAX_ECM_HOLD) { 01258 PRINTF(L_CORE_ECM,"%s: hold timeout expired",id); 01259 mode=0; 01260 } 01261 01262 break; 01263 } 01264 } 01265 } 01266 01267 void cEcmHandler::NoSync(bool clearParity) 01268 { 01269 if(clearParity) parity=0xFF; 01270 count=0; sync=false; 01271 } 01272 01273 void cEcmHandler::DeleteSys(void) 01274 { 01275 delete sys; sys=0; 01276 } 01277 01278 char *cEcmHandler::CurrentKeyStr(void) const 01279 { 01280 if(noKey || !sys) return 0; 01281 return strdup(sys->CurrentKeyStr()); 01282 } 01283 01284 cEcmInfo *cEcmHandler::NewEcm(void) 01285 { 01286 ecmcache.GetCached(&ecmList,filterSid,filterSource,filterTransponder); 01287 ecmPriList.Clear(); 01288 for(cEcmInfo *n=ecmList.First(); n; n=ecmList.Next(n)) AddEcmPri(n); 01289 ecm=0; ecmPri=0; 01290 return JumpEcm(); 01291 } 01292 01293 void cEcmHandler::AddEcmPri(cEcmInfo *n) 01294 { 01295 int ident, pri=0; 01296 while(1) { 01297 if(overrides.Ignore(n->source,n->transponder,n->caId)) break; 01298 if(!n->Cached()) ident=cSystems::FindIdentBySysId(n->caId,!cam->IsSoftCSA(filterCwIndex==0),pri); 01299 else ident=(pri==0) ? cSystems::FindIdentBySysName(n->caId,!cam->IsSoftCSA(filterCwIndex==0),n->name,pri) : 0; 01300 if(ident<=0) break; 01301 01302 cEcmPri *ep=new cEcmPri; 01303 if(ep) { 01304 ep->ecm=n; 01305 ep->pri=pri; 01306 ep->sysIdent=ident; 01307 if(n->Cached() && (!ScSetup.LocalPriority || pri!=-15)) ep->pri+=20; 01308 ep->pri=ep->pri*100 + overrides.GetEcmPrio(n->source,n->transponder,n->caId,n->provId); 01309 01310 // no double entries in ecmPriList 01311 for(cEcmPri *epp=ecmPriList.First(); epp; epp=ecmPriList.Next(epp)) 01312 if(epp->ecm==ep->ecm && epp->sysIdent==ep->sysIdent) { 01313 delete ep; ep=0; 01314 break; 01315 } 01316 } 01317 if(ep) { 01318 // keep ecmPriList sorted 01319 cEcmPri *eppp, *epp=ecmPriList.First(); 01320 if(!epp || epp->pri<ep->pri) 01321 ecmPriList.Ins(ep); 01322 else { 01323 do { 01324 eppp=ecmPriList.Next(epp); 01325 if(!eppp || eppp->pri<ep->pri) { 01326 ecmPriList.Add(ep,epp); 01327 break; 01328 } 01329 } while((epp=eppp)); 01330 } 01331 } 01332 } 01333 } 01334 01335 void cEcmHandler::StopEcm(void) 01336 { 01337 filter->Stop(); filter->Flush(); 01338 if(ecm) cam->LogEcmStatus(ecm,false); 01339 DeleteSys(); 01340 } 01341 01342 bool cEcmHandler::UpdateEcm(void) 01343 { 01344 if(ecmUpd) { 01345 bool log=dolog; 01346 dolog=(sys && sys->NeedsData() && ecm->Data()==0); 01347 if(dolog) PRINTF(L_CORE_ECM,"%s: try to update ecm extra data",id); 01348 ParseCAInfo(ecm->caId); 01349 dolog=log; 01350 } 01351 return ecm->Data()!=0; 01352 } 01353 01354 cEcmInfo *cEcmHandler::JumpEcm(void) 01355 { 01356 noKey=true; 01357 if(!ecmPri) { 01358 ParseCAInfo(0xFFFF); // all systems 01359 ecmPri=ecmPriList.First(); 01360 } 01361 else ecmPri=ecmPriList.Next(ecmPri); 01362 if(ecmPri) { 01363 if(ecmPri->ecm!=ecm) { 01364 StopEcm(); 01365 ecm=ecmPri->ecm; 01366 filter->Start(ecm->ecm_pid,ecm->ecm_table,0xfe); 01367 cam->LogEcmStatus(ecm,true); 01368 } 01369 else { 01370 DeleteSys(); 01371 filter->Flush(); 01372 } 01373 sys=cSystems::FindBySysIdent(ecmPri->sysIdent); 01374 if(!sys) { 01375 if(dolog) PRINTF(L_GEN_DEBUG,"internal: handler %s, no system found for ident %04x (caid %04x pri %d)",id,ecmPri->sysIdent,ecmPri->ecm->caId,ecmPri->pri); 01376 return JumpEcm(); 01377 } 01378 sys->DoLog(dolog!=0); 01379 sys->SetOwner(cam); 01380 failed.SetMaxFail(sys->MaxEcmTry()); 01381 01382 if(dolog) PRINTF(L_CORE_ECM,"%s: try system %s (%04x) id %04x with ecm %x%s (pri=%d)", 01383 id,sys->Name(),ecm->caId,ecm->provId,ecm->ecm_pid,ecm->Cached()?" (cached)":"",sys->Pri()); 01384 } 01385 else { 01386 StopEcm(); 01387 ecm=0; 01388 } 01389 return ecm; 01390 } 01391 01392 void cEcmHandler::EcmOk(void) 01393 { 01394 ecm->SetName(sys->Name()); 01395 ecm->Fail(false); 01396 ecmcache.New(ecm); 01397 cEcmInfo *e=ecmList.First(); 01398 while(e) { 01399 if(e->Cached() && e->Failed()) ecmcache.Delete(e); 01400 e=ecmList.Next(e); 01401 } 01402 } 01403 01404 void cEcmHandler::EcmFail(void) 01405 { 01406 ecm->Fail(true); 01407 } 01408 01409 void cEcmHandler::ParseCAInfo(int SysId) 01410 { 01411 ecmUpd=false; 01412 int len; 01413 const unsigned char *buff=filterCaDescr.Get(len); 01414 if(buff && len>0) { 01415 if(dolog) PRINTF(L_CORE_ECM,"%s: CA descriptors for SID %d (len=%d)",id,filterSid,len); 01416 HEXDUMP(L_HEX_PMT,buff,len,"PMT"); 01417 for(int index=0; index<len; index+=buff[index+1]+2) { 01418 if(buff[index]==0x09) { 01419 int sysId=WORD(buff,index+2,0xFFFF); 01420 if(SysId!=0xFFFF && sysId!=SysId) continue; 01421 if(dolog) LDUMP(L_CORE_ECM,&buff[index+2],buff[index+1],"%s: descriptor",id); 01422 if(overrides.Ignore(filterSource,filterTransponder,sysId)) { 01423 if(dolog) PRINTF(L_CORE_ECM,"%s: system %04x ignored",id,sysId); 01424 continue; 01425 } 01426 int sysPri=0; 01427 cSystem *sys; 01428 while((sys=cSystems::FindBySysId(sysId,!cam->IsSoftCSA(filterCwIndex==0),sysPri))) { 01429 sysPri=sys->Pri(); 01430 cSimpleList<cEcmInfo> ecms; 01431 sys->ParseCADescriptor(&ecms,sysId,filterSource,&buff[index+2],buff[index+1]); 01432 delete sys; 01433 if(ecms.Count()) { 01434 cEcmInfo *n; 01435 while((n=ecms.First())) { 01436 ecms.Del(n,false); 01437 n->SetSource(filterSid,filterSource,filterTransponder); 01438 n->SetDvb(cam->Adapter(),cam->Frontend()); 01439 n->AddCaDescr(&buff[index],buff[index+1]+2); 01440 overrides.UpdateEcm(n,dolog); 01441 LBSTARTF(L_CORE_ECM); 01442 if(dolog) LBPUT("%s: found %04x(%04x) (%s) id %04x with ecm %x/%x ",id,n->caId,n->emmCaId,n->name,n->provId,n->ecm_pid,n->ecm_table); 01443 cEcmInfo *e=ecmList.First(); 01444 while(e) { 01445 if(e->ecm_pid==n->ecm_pid) { 01446 if(e->caId==n->caId && e->provId==n->provId) { 01447 if(e->AddCaDescr(n) && dolog) LBPUT("(updated) "); 01448 if(dolog) LBPUT("(already present)"); 01449 AddEcmPri(e); 01450 delete n; n=0; 01451 break; 01452 } 01453 else { 01454 e->Fail(true); 01455 if(dolog) LBPUT("(dup) "); 01456 } 01457 } 01458 e=ecmList.Next(e); 01459 } 01460 if(n) { 01461 if(dolog) LBPUT("(new)"); 01462 ecmList.Add(n); 01463 AddEcmPri(n); 01464 } 01465 LBEND(); 01466 } 01467 break; 01468 } 01469 } 01470 if(sysPri==0 && dolog) PRINTF(L_CORE_ECM,"%s: no module available for system %04x",id,sysId); 01471 } 01472 } 01473 } 01474 01475 for(cEcmPri *ep=ecmPriList.First(); ep; ep=ecmPriList.Next(ep)) 01476 PRINTF(L_CORE_ECMPROC,"%s: ecmPriList pri=%d ident=%04x caid=%04x pid=%04x",id,ep->pri,ep->sysIdent,ep->ecm->caId,ep->ecm->ecm_pid); 01477 PRINTF(L_CORE_ECMPROC,"%s: ecmPri list end",id); 01478 } 01479 01480 // --- cChannelCaids ----------------------------------------------------------- 01481 01482 #ifndef SASC 01483 01484 class cChannelCaids : public cSimpleItem { 01485 private: 01486 int prg, source, transponder; 01487 int numcaids; 01488 caid_t caids[MAX_CI_SLOT_CAIDS+1]; 01489 public: 01490 cChannelCaids(cChannel *channel); 01491 bool IsChannel(cChannel *channel); 01492 void Sort(void); 01493 void Del(caid_t caid); 01494 bool HasCaid(caid_t caid); 01495 bool Same(cChannelCaids *ch, bool full); 01496 void HistAdd(unsigned short *hist); 01497 void Dump(const char *devId); 01498 const caid_t *Caids(void) { caids[numcaids]=0; return caids; } 01499 int NumCaids(void) { return numcaids; } 01500 int Source(void) const { return source; } 01501 int Transponder(void) const { return transponder; } 01502 }; 01503 01504 cChannelCaids::cChannelCaids(cChannel *channel) 01505 { 01506 prg=channel->Sid(); source=channel->Source(); transponder=channel->Transponder(); 01507 numcaids=0; 01508 for(const caid_t *ids=channel->Caids(); *ids; ids++) 01509 if(numcaids<MAX_CI_SLOT_CAIDS) caids[numcaids++]=*ids; 01510 Sort(); 01511 } 01512 01513 bool cChannelCaids::IsChannel(cChannel *channel) 01514 { 01515 return prg==channel->Sid() && source==channel->Source() && transponder==channel->Transponder(); 01516 } 01517 01518 void cChannelCaids::Sort(void) 01519 { 01520 caid_t tmp[MAX_CI_SLOT_CAIDS]; 01521 int c=0xFFFF; 01522 for(int i=0; i<numcaids; i++) { 01523 int d=0; 01524 for(int j=0; j<numcaids; j++) if(caids[j]>d && caids[j]<c) d=caids[j]; 01525 tmp[i]=d; c=d; 01526 } 01527 memcpy(caids,tmp,sizeof(caids)); 01528 } 01529 01530 void cChannelCaids::Del(caid_t caid) 01531 { 01532 for(int i=0; i<numcaids; i++) 01533 if(caids[i]==caid) { 01534 numcaids--; caids[i]=caids[numcaids]; 01535 if(numcaids>0) Sort(); 01536 caids[numcaids]=0; 01537 break; 01538 } 01539 } 01540 01541 bool cChannelCaids::HasCaid(caid_t caid) 01542 { 01543 for(int i=0; i<numcaids; i++) if(caids[i]==caid) return true; 01544 return false; 01545 } 01546 01547 bool cChannelCaids::Same(cChannelCaids *ch, bool full) 01548 { 01549 if(full && (source!=ch->source || transponder!=ch->transponder)) return false; 01550 if(numcaids!=ch->numcaids) return false; 01551 return memcmp(caids,ch->caids,numcaids*sizeof(caid_t))==0; 01552 } 01553 01554 void cChannelCaids::HistAdd(unsigned short *hist) 01555 { 01556 for(int i=numcaids-1; i>=0; i--) hist[caids[i]]++; 01557 } 01558 01559 void cChannelCaids::Dump(const char *devId) 01560 { 01561 LBSTART(L_CORE_CAIDS); 01562 LBPUT("%s: channel %d/%x/%x",devId,prg,source,transponder); 01563 for(const caid_t *ids=Caids(); *ids; ids++) LBPUT(" %04x",*ids); 01564 LBEND(); 01565 } 01566 01567 // --- cChannelList ------------------------------------------------------------ 01568 01569 class cChannelList : public cSimpleList<cChannelCaids> { 01570 private: 01571 const char *devId; 01572 public: 01573 cChannelList(const char *DevId); 01574 void Unique(bool full); 01575 void CheckIgnore(void); 01576 int Histo(void); 01577 void Purge(int caid, bool fullch); 01578 }; 01579 01580 cChannelList::cChannelList(const char *DevId) 01581 { 01582 devId=DevId; 01583 } 01584 01585 void cChannelList::CheckIgnore(void) 01586 { 01587 char *cache=MALLOC(char,0x10000); 01588 if(!cache) return; 01589 memset(cache,0,sizeof(char)*0x10000); 01590 int cTotal=0, cHits=0; 01591 for(cChannelCaids *ch=First(); ch; ch=Next(ch)) { 01592 const caid_t *ids=ch->Caids(); 01593 while(*ids) { 01594 int pri=0; 01595 if(overrides.Ignore(ch->Source(),ch->Transponder(),*ids)) 01596 ch->Del(*ids); 01597 else { 01598 char c=cache[*ids]; 01599 if(c==0) cache[*ids]=c=(cSystems::FindIdentBySysId(*ids,false,pri) ? 1 : -1); 01600 else cHits++; 01601 cTotal++; 01602 if(c<0) { 01603 for(cChannelCaids *ch2=Next(ch); ch2; ch2=Next(ch2)) ch2->Del(*ids); 01604 ch->Del(*ids); 01605 } 01606 else ids++; 01607 } 01608 } 01609 } 01610 free(cache); 01611 PRINTF(L_CORE_CAIDS,"%s: after check",devId); 01612 for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId); 01613 PRINTF(L_CORE_CAIDS,"%s: check cache usage: %d requests, %d hits, %d%% hits",devId,cTotal,cHits,(cTotal>0)?(cHits*100/cTotal):0); 01614 } 01615 01616 void cChannelList::Unique(bool full) 01617 { 01618 for(cChannelCaids *ch1=First(); ch1; ch1=Next(ch1)) { 01619 for(cChannelCaids *ch2=Next(ch1); ch2;) { 01620 if(ch1->Same(ch2,full) || ch2->NumCaids()<1) { 01621 cChannelCaids *t=Next(ch2); 01622 Del(ch2); 01623 ch2=t; 01624 } 01625 else ch2=Next(ch2); 01626 } 01627 } 01628 if(Count()==1 && First() && First()->NumCaids()<1) Del(First()); 01629 PRINTF(L_CORE_CAIDS,"%s: after unique (%d)",devId,full); 01630 for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId); 01631 } 01632 01633 int cChannelList::Histo(void) 01634 { 01635 int h=-1; 01636 unsigned short *hist=MALLOC(unsigned short,0x10000); 01637 if(hist) { 01638 memset(hist,0,sizeof(unsigned short)*0x10000); 01639 for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->HistAdd(hist); 01640 int c=0; 01641 for(int i=0; i<0x10000; i++) 01642 if(hist[i]>c) { h=i; c=hist[i]; } 01643 free(hist); 01644 } 01645 else PRINTF(L_GEN_ERROR,"malloc failed in cChannelList::Histo"); 01646 return h; 01647 } 01648 01649 void cChannelList::Purge(int caid, bool fullch) 01650 { 01651 for(cChannelCaids *ch=First(); ch;) { 01652 if(!fullch) ch->Del(caid); 01653 if(ch->NumCaids()<=0 || (fullch && ch->HasCaid(caid))) { 01654 cChannelCaids *t=Next(ch); 01655 Del(ch); 01656 ch=t; 01657 } 01658 else ch=Next(ch); 01659 } 01660 if(Count()>0) { 01661 PRINTF(L_CORE_CAIDS,"%s: still left",devId); 01662 for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId); 01663 } 01664 } 01665 01666 // -- cCiFrame ----------------------------------------------------------------- 01667 01668 #define LEN_OFF 2 01669 01670 cCiFrame::cCiFrame(void) 01671 { 01672 rb=0; mem=0; len=alen=glen=0; 01673 } 01674 01675 cCiFrame::~cCiFrame() 01676 { 01677 free(mem); 01678 } 01679 01680 unsigned char *cCiFrame::GetBuff(int l) 01681 { 01682 if(!mem || l>alen) { 01683 free(mem); mem=0; alen=0; 01684 mem=MALLOC(unsigned char,l+LEN_OFF); 01685 if(mem) alen=l; 01686 } 01687 len=l; 01688 if(!mem) { 01689 PRINTF(L_GEN_DEBUG,"internal: ci-frame alloc failed"); 01690 return 0; 01691 } 01692 return mem+LEN_OFF; 01693 } 01694 01695 void cCiFrame::Put(void) 01696 { 01697 if(rb && mem) { 01698 *((short *)mem)=len; 01699 rb->Put(mem,len+LEN_OFF); 01700 } 01701 } 01702 01703 unsigned char *cCiFrame::Get(int &l) 01704 { 01705 if(rb) { 01706 int c; 01707 unsigned char *data=rb->Get(c); 01708 if(data) { 01709 if(c>LEN_OFF) { 01710 int s=*((short *)data); 01711 if(c>=s+LEN_OFF) { 01712 l=glen=s; 01713 return data+LEN_OFF; 01714 } 01715 } 01716 LDUMP(L_GEN_DEBUG,data,c,"internal: ci rb frame sync got=%d avail=%d -",c,rb->Available()); 01717 rb->Clear(); 01718 } 01719 } 01720 return 0; 01721 } 01722 01723 int cCiFrame::Avail(void) 01724 { 01725 return rb ? rb->Available() : 0; 01726 } 01727 01728 void cCiFrame::Del(void) 01729 { 01730 if(rb && glen) { 01731 rb->Del(glen+LEN_OFF); 01732 glen=0; 01733 } 01734 } 01735 01736 // -- cScCamSlot --------------------------------------------------------------- 01737 01738 #define TDPU_SIZE_INDICATOR 0x80 01739 01740 #define CAID_TIME 300000 // time between caid scans 01741 #define TRIGGER_TIME 10000 // min. time between caid scan trigger 01742 #define SLOT_CAID_CHECK 10000 01743 #define SLOT_RESET_TIME 600 01744 01745 class cScCamSlot : public cCamSlot { 01746 private: 01747 cCam *cam; 01748 unsigned short caids[MAX_CI_SLOT_CAIDS+1]; 01749 int slot, version; 01750 const char *devId; 01751 cTimeMs checkTimer; 01752 bool reset, doReply; 01753 cTimeMs resetTimer; 01754 eModuleStatus lastStatus; 01755 cRingBufferLinear rb; 01756 cCiFrame frame; 01757 // 01758 int GetLength(const unsigned char * &data); 01759 int LengthSize(int n); 01760 void SetSize(int n, unsigned char * &p); 01761 void CaInfo(int tcid, int cid); 01762 bool Check(void); 01763 public: 01764 cScCamSlot(cCam *Cam, const char *DevId, int Slot); 01765 void Process(const unsigned char *data, int len); 01766 eModuleStatus Status(void); 01767 bool Reset(bool log=true); 01768 cCiFrame *Frame(void) { return &frame; } 01769 }; 01770 01771 cScCamSlot::cScCamSlot(cCam *Cam, const char *DevId, int Slot) 01772 :cCamSlot(Cam) 01773 ,checkTimer(-SLOT_CAID_CHECK-1000) 01774 ,rb(KILOBYTE(4),5+LEN_OFF,false,"SC-CI slot answer") 01775 { 01776 cam=Cam; devId=DevId; slot=Slot; 01777 version=0; caids[0]=0; doReply=false; lastStatus=msReset; 01778 frame.SetRb(&rb); 01779 Reset(false); 01780 } 01781 01782 eModuleStatus cScCamSlot::Status(void) 01783 { 01784 eModuleStatus status; 01785 if(reset) { 01786 status=msReset; 01787 if(resetTimer.TimedOut()) reset=false; 01788 } 01789 else if(caids[0]) status=msReady; 01790 else { 01791 status=msPresent; //msNone; 01792 Check(); 01793 } 01794 if(status!=lastStatus) { 01795 static const char *stext[] = { "none","reset","present","ready" }; 01796 PRINTF(L_CORE_CI,"%s.%d: status '%s'",devId,slot,stext[status]); 01797 lastStatus=status; 01798 } 01799 return status; 01800 } 01801 01802 bool cScCamSlot::Reset(bool log) 01803 { 01804 reset=true; resetTimer.Set(SLOT_RESET_TIME); 01805 rb.Clear(); 01806 if(log) PRINTF(L_CORE_CI,"%s.%d: reset",devId,slot); 01807 return true; 01808 } 01809 01810 bool cScCamSlot::Check(void) 01811 { 01812 bool res=false; 01813 bool dr=cam->IsSoftCSA(false) || ScSetup.ConcurrentFF>0; 01814 if(dr!=doReply && !IsDecrypting()) { 01815 PRINTF(L_CORE_CI,"%s.%d: doReply changed, reset triggered",devId,slot); 01816 Reset(false); 01817 doReply=dr; 01818 } 01819 if(checkTimer.TimedOut()) { 01820 if(version!=cam->GetCaids(slot,0,0)) { 01821 version=cam->GetCaids(slot,caids,MAX_CI_SLOT_CAIDS); 01822 PRINTF(L_CORE_CI,"%s.%d: now using CAIDs version %d",devId,slot,version); 01823 res=true; 01824 } 01825 checkTimer.Set(SLOT_CAID_CHECK); 01826 } 01827 return res; 01828 } 01829 01830 int cScCamSlot::GetLength(const unsigned char * &data) 01831 { 01832 int len=*data++; 01833 if(len&TDPU_SIZE_INDICATOR) { 01834 int i; 01835 for(i=len&~TDPU_SIZE_INDICATOR, len=0; i>0; i--) len=(len<<8) + *data++; 01836 } 01837 return len; 01838 } 01839 01840 int cScCamSlot::LengthSize(int n) 01841 { 01842 return n<TDPU_SIZE_INDICATOR?1:3; 01843 } 01844 01845 void cScCamSlot::SetSize(int n, unsigned char * &p) 01846 { 01847 if(n<TDPU_SIZE_INDICATOR) *p++=n; 01848 else { *p++=2|TDPU_SIZE_INDICATOR; *p++=n>>8; *p++=n&0xFF; } 01849 } 01850 01851 void cScCamSlot::CaInfo(int tcid, int cid) 01852 { 01853 int cn=0; 01854 for(int i=0; caids[i]; i++) cn+=2; 01855 int n=cn+8+LengthSize(cn); 01856 unsigned char *p; 01857 if(!(p=frame.GetBuff(n+1+LengthSize(n)))) return; 01858 *p++=0xa0; 01859 SetSize(n,p); 01860 *p++=tcid; 01861 *p++=0x90; 01862 *p++=0x02; *p++=cid>>8; *p++=cid&0xff; 01863 *p++=0x9f; *p++=0x80; *p++=0x31; // AOT_CA_INFO 01864 SetSize(cn,p); 01865 for(int i=0; caids[i]; i++) { *p++=caids[i]>>8; *p++=caids[i]&0xff; } 01866 frame.Put(); 01867 PRINTF(L_CORE_CI,"%s.%d sending CA info",devId,slot); 01868 } 01869 01870 void cScCamSlot::Process(const unsigned char *data, int len) 01871 { 01872 const unsigned char *save=data; 01873 data+=3; 01874 int dlen=GetLength(data); 01875 if(dlen>len-(data-save)) { 01876 PRINTF(L_CORE_CI,"%s.%d TDPU length exceeds data length",devId,slot); 01877 dlen=len-(data-save); 01878 } 01879 int tcid=data[0]; 01880 01881 if(Check()) CaInfo(tcid,0x01); 01882 01883 if(dlen<8 || data[1]!=0x90) return; 01884 int cid=(data[3]<<8)+data[4]; 01885 int tag=(data[5]<<16)+(data[6]<<8)+data[7]; 01886 data+=8; 01887 dlen=GetLength(data); 01888 if(dlen>len-(data-save)) { 01889 PRINTF(L_CORE_CI,"%s.%d tag length exceeds data length",devId,slot); 01890 dlen=len-(data-save); 01891 } 01892 switch(tag) { 01893 case 0x9f8030: // AOT_CA_INFO_ENQ 01894 CaInfo(tcid,cid); 01895 break; 01896 01897 case 0x9f8032: // AOT_CA_PMT 01898 if(dlen>=6) { 01899 int ca_lm=data[0]; 01900 int ci_cmd=-1; 01901 cPrg *prg=new cPrg((data[1]<<8)+data[2],ca_lm==5); 01902 int ilen=(data[4]<<8)+data[5]; 01903 LBSTARTF(L_CORE_CI); 01904 LBPUT("%s.%d CA_PMT decoding len=%x lm=%x prg=%d len=%x",devId,slot,dlen,ca_lm,(data[1]<<8)+data[2],ilen); 01905 data+=6; dlen-=6; 01906 LBPUT("/%x",dlen); 01907 if(ilen>0 && dlen>=ilen) { 01908 ci_cmd=data[0]; 01909 if(ilen>1) 01910 prg->caDescr.Set(&data[1],ilen-1); 01911 LBPUT(" ci_cmd(G)=%02x",ci_cmd); 01912 } 01913 data+=ilen; dlen-=ilen; 01914 while(dlen>=5) { 01915 cPrgPid *pid=new cPrgPid(data[0],(data[1]<<8)+data[2]); 01916 prg->pids.Add(pid); 01917 ilen=(data[3]<<8)+data[4]; 01918 LBPUT(" pid=%d,%x len=%x",data[0],(data[1]<<8)+data[2],ilen); 01919 data+=5; dlen-=5; 01920 LBPUT("/%x",dlen); 01921 if(ilen>0 && dlen>=ilen) { 01922 ci_cmd=data[0]; 01923 if(ilen>1) { 01924 pid->caDescr.Set(&data[1],ilen-1); 01925 prg->SetPidCaDescr(true); 01926 } 01927 LBPUT(" ci_cmd(S)=%x",ci_cmd); 01928 } 01929 data+=ilen; dlen-=ilen; 01930 } 01931 LBEND(); 01932 PRINTF(L_CORE_CI,"%s.%d got CA pmt ciCmd=%d caLm=%d",devId,slot,ci_cmd,ca_lm); 01933 if(doReply && (ci_cmd==0x03 || (ci_cmd==0x01 && ca_lm==0x03))) { 01934 unsigned char *b; 01935 if((b=frame.GetBuff(4+11))) { 01936 b[0]=0xa0; b[2]=tcid; 01937 b[3]=0x90; 01938 b[4]=0x02; b[5]=cid<<8; b[6]=cid&0xff; 01939 b[7]=0x9f; b[8]=0x80; b[9]=0x33; // AOT_CA_PMT_REPLY 01940 b[11]=prg->sid<<8; 01941 b[12]=prg->sid&0xff; 01942 b[13]=0x00; 01943 b[14]=0x81; // CA_ENABLE 01944 b[10]=4; b[1]=4+9; 01945 frame.Put(); 01946 PRINTF(L_CORE_CI,"%s.%d answer to query",devId,slot); 01947 } 01948 } 01949 if(prg->sid!=0) { 01950 if(ci_cmd==0x04 || (ci_cmd==-1 && ca_lm==0x03)) { 01951 PRINTF(L_CORE_CI,"%s.%d stop decrypt",devId,slot); 01952 cam->Stop(); 01953 } 01954 if(ci_cmd==0x01 || (ci_cmd==-1 && (ca_lm==0x04 || ca_lm==0x05))) { 01955 PRINTF(L_CORE_CI,"%s.%d set CAM decrypt (prg %d)",devId,slot,prg->sid); 01956 cam->AddPrg(prg); 01957 } 01958 } 01959 delete prg; 01960 } 01961 break; 01962 } 01963 } 01964 01965 #endif //!SASC 01966 01967 // -- cCams -------------------------------------------------------------------- 01968 01969 class cCams : public cSimpleList<cCam> { 01970 public: 01971 cMutex listMutex; 01972 // 01973 void Register(cCam *cam); 01974 void Unregister(cCam *cam); 01975 }; 01976 01977 static cCams cams; 01978 01979 void cCams::Register(cCam *cam) 01980 { 01981 cMutexLock lock(&listMutex); 01982 Add(cam); 01983 } 01984 01985 void cCams::Unregister(cCam *cam) 01986 { 01987 cMutexLock lock(&listMutex); 01988 Del(cam,false); 01989 } 01990 01991 // -- cGlobal ------------------------------------------------------------------ 01992 01993 char *cGlobal::CurrKeyStr(int camindex, int num, const char **id) 01994 { 01995 cMutexLock lock(&cams.listMutex); 01996 char *str=0; 01997 cCam *c; 01998 for(c=cams.First(); c && camindex>0; c=cams.Next(c), camindex--); 01999 if(c) { 02000 str=c->CurrentKeyStr(num,id); 02001 if(!str && num==0) str=strdup(tr("(none)")); 02002 } 02003 return str; 02004 } 02005 02006 void cGlobal::HouseKeeping(void) 02007 { 02008 cMutexLock lock(&cams.listMutex); 02009 for(cCam *c=cams.First(); c; c=cams.Next(c)) c->HouseKeeping(); 02010 } 02011 02012 bool cGlobal::Active(bool log) 02013 { 02014 cMutexLock lock(&cams.listMutex); 02015 for(cCam *c=cams.First(); c; c=cams.Next(c)) if(c->Active(log)) return true; 02016 return false; 02017 } 02018 02019 void cGlobal::CaidsChanged(void) 02020 { 02021 cMutexLock lock(&cams.listMutex); 02022 PRINTF(L_CORE_CAIDS,"caid list rebuild triggered"); 02023 for(cCam *c=cams.First(); c; c=cams.Next(c)) c->CaidsChanged(); 02024 } 02025 02026 // -- cCam --------------------------------------------------------------- 02027 02028 #ifndef SASC 02029 struct TPDU { 02030 unsigned char slot; 02031 unsigned char tcid; 02032 unsigned char tag; 02033 unsigned char len; 02034 unsigned char data[1]; 02035 }; 02036 #endif 02037 02038 cCam::cCam(cDevice *Device, int Adapter, int Frontend, const char *DevId, cScDevicePlugin *DevPlugin, bool SoftCSA, bool FullTS) 02039 { 02040 device=Device; devplugin=DevPlugin; adapter=Adapter; frontend=Frontend; devId=DevId; 02041 softcsa=SoftCSA; fullts=FullTS; 02042 tcid=0; rebuildcaids=false; 02043 memset(version,0,sizeof(version)); 02044 #ifndef SASC 02045 memset(slots,0,sizeof(slots)); 02046 SetDescription("SC-CI adapter on device %s",devId); 02047 rb=new cRingBufferLinear(KILOBYTE(8),6+LEN_OFF,false,"SC-CI adapter read"); 02048 if(rb) { 02049 rb->SetTimeouts(0,CAM_READ_TIMEOUT); 02050 frame.SetRb(rb); 02051 BuildCaids(true); 02052 slots[0]=new cScCamSlot(this,devId,0); 02053 Start(); 02054 } 02055 else PRINTF(L_GEN_ERROR,"failed to create ringbuffer for SC-CI adapter %s.",devId); 02056 02057 decsa=softcsa ? new cDeCSA(devId) : 0; 02058 #endif //!SASC 02059 02060 source=transponder=-1; liveVpid=liveApid=0; logger=0; hookman=0; 02061 memset(lastCW,0,sizeof(lastCW)); 02062 memset(indexMap,0,sizeof(indexMap)); 02063 memset(splitSid,0,sizeof(splitSid)); 02064 cams.Register(this); 02065 } 02066 02067 cCam::~cCam() 02068 { 02069 cams.Unregister(this); 02070 handlerList.Clear(); 02071 delete hookman; 02072 delete logger; 02073 #ifndef SASC 02074 Cancel(3); 02075 ciMutex.Lock(); 02076 delete rb; rb=0; 02077 ciMutex.Unlock(); 02078 delete decsa; decsa=0; 02079 #endif //!SASC 02080 } 02081 02082 #ifndef SASC 02083 bool cCam::OwnSlot(const cCamSlot *slot) const 02084 { 02085 if(slots[0]==slot) return true; 02086 //for(int i=0; i<MAX_CI_SLOTS; i++) if(slots[i]==slot) return true; 02087 return false; 02088 } 02089 02090 int cCam::GetCaids(int slot, unsigned short *Caids, int max) 02091 { 02092 BuildCaids(false); 02093 cMutexLock lock(&ciMutex); 02094 if(Caids) { 02095 int i; 02096 for(i=0; i<MAX_CI_SLOT_CAIDS && i<max && caids[i]; i++) Caids[i]=caids[slot][i]; 02097 Caids[i]=0; 02098 } 02099 return version[slot]; 02100 } 02101 #endif //!SASC 02102 02103 void cCam::CaidsChanged(void) 02104 { 02105 rebuildcaids=true; 02106 } 02107 02108 #ifndef SASC 02109 void cCam::BuildCaids(bool force) 02110 { 02111 if(caidTimer.TimedOut() || force || (rebuildcaids && triggerTimer.TimedOut())) { 02112 PRINTF(L_CORE_CAIDS,"%s: building caid lists",devId); 02113 cChannelList list(devId); 02114 Channels.Lock(false); 02115 for(cChannel *channel=Channels.First(); channel; channel=Channels.Next(channel)) { 02116 if(!channel->GroupSep() && channel->Ca()>=CA_ENCRYPTED_MIN && device->ProvidesTransponder(channel)) { 02117 cChannelCaids *ch=new cChannelCaids(channel); 02118 if(ch) list.Add(ch); 02119 } 02120 } 02121 Channels.Unlock(); 02122 list.Unique(true); 02123 list.CheckIgnore(); 02124 list.Unique(false); 02125 02126 int n=0, h; 02127 caid_t c[MAX_CI_SLOT_CAIDS+1]; 02128 memset(c,0,sizeof(c)); 02129 do { 02130 if((h=list.Histo())<0) break; 02131 c[n++]=h; 02132 LBSTART(L_CORE_CAIDS); 02133 LBPUT("%s: added %04x caids now",devId,h); for(int i=0; i<n; i++) LBPUT(" %04x",c[i]); 02134 LBEND(); 02135 list.Purge(h,false); 02136 } while(n<MAX_CI_SLOT_CAIDS && list.Count()>0); 02137 c[n]=0; 02138 if(n==0) PRINTF(L_CORE_CI,"%s: no active CAIDs",devId); 02139 else if(list.Count()>0) PRINTF(L_GEN_ERROR,"too many CAIDs. You should ignore some CAIDs."); 02140 02141 ciMutex.Lock(); 02142 if((version[0]==0 && c[0]!=0) || memcmp(caids[0],c,sizeof(caids[0]))) { 02143 memcpy(caids[0],c,sizeof(caids[0])); 02144 version[0]++; 02145 if(version[0]>0) { 02146 LBSTART(L_CORE_CI); 02147 LBPUT("card %s, slot %d (v=%2d) caids:",devId,0,version[0]); 02148 for(int i=0; caids[0][i]; i++) LBPUT(" %04x",caids[0][i]); 02149 LBEND(); 02150 } 02151 } 02152 ciMutex.Unlock(); 02153 02154 caidTimer.Set(CAID_TIME); 02155 triggerTimer.Set(TRIGGER_TIME); 02156 rebuildcaids=false; 02157 } 02158 } 02159 02160 int cCam::Read(unsigned char *Buffer, int MaxLength) 02161 { 02162 cMutexLock lock(&ciMutex); 02163 if(rb && Buffer && MaxLength>0) { 02164 int s; 02165 unsigned char *data=frame.Get(s); 02166 if(data) { 02167 if(s<=MaxLength) memcpy(Buffer,data,s); 02168 else PRINTF(L_GEN_DEBUG,"internal: sc-ci %s rb frame size exceeded %d",devId,s); 02169 frame.Del(); 02170 if(Buffer[2]!=0x80 || LOG(L_CORE_CIFULL)) { 02171 LDUMP(L_CORE_CI,Buffer,s,"%s.%d <-",devId,Buffer[0]); 02172 readTimer.Set(); 02173 } 02174 return s; 02175 } 02176 } 02177 else cCondWait::SleepMs(CAM_READ_TIMEOUT); 02178 if(LOG(L_CORE_CIFULL) && readTimer.Elapsed()>2000) { 02179 PRINTF(L_CORE_CIFULL,"%s: read heartbeat",devId); 02180 readTimer.Set(); 02181 } 02182 return 0; 02183 } 02184 02185 #define TPDU(data,slot) do { unsigned char *_d=(data); _d[0]=(slot); _d[1]=tcid; } while(0) 02186 #define TAG(data,tag,len) do { unsigned char *_d=(data); _d[0]=(tag); _d[1]=(len); } while(0) 02187 #define SB_TAG(data,sb) do { unsigned char *_d=(data); _d[0]=0x80; _d[1]=0x02; _d[2]=tcid; _d[3]=(sb); } while(0) 02188 02189 void cCam::Write(const unsigned char *buff, int len) 02190 { 02191 cMutexLock lock(&ciMutex); 02192 if(buff && len>=5) { 02193 struct TPDU *tpdu=(struct TPDU *)buff; 02194 int slot=tpdu->slot; 02195 cCiFrame *slotframe=slots[slot]->Frame(); 02196 if(buff[2]!=0xA0 || buff[3]>0x01 || LOG(L_CORE_CIFULL)) 02197 LDUMP(L_CORE_CI,buff,len,"%s.%d ->",devId,slot); 02198 if(slots[slot]) { 02199 switch(tpdu->tag) { 02200 case 0x81: // T_RCV 02201 { 02202 int s; 02203 unsigned char *d=slotframe->Get(s); 02204 if(d) { 02205 unsigned char *b; 02206 if((b=frame.GetBuff(s+6))) { 02207 TPDU(b,slot); 02208 memcpy(b+2,d,s); 02209 slotframe->Del(); // delete from rb before Avail() 02210 SB_TAG(b+2+s,slotframe->Avail()>0 ? 0x80:0x00); 02211 frame.Put(); 02212 } 02213 else slotframe->Del(); 02214 } 02215 break; 02216 } 02217 case 0x82: // T_CREATE_TC 02218 { 02219 tcid=tpdu->data[0]; 02220 unsigned char *b; 02221 static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 }; 02222 if((b=slotframe->GetBuff(sizeof(reqCAS)))) { 02223 memcpy(b,reqCAS,sizeof(reqCAS)); 02224 b[2]=tcid; 02225 slotframe->Put(); 02226 } 02227 if((b=frame.GetBuff(9))) { 02228 TPDU(b,slot); 02229 TAG(&b[2],0x83,0x01); b[4]=tcid; 02230 SB_TAG(&b[5],slotframe->Avail()>0 ? 0x80:0x00); 02231 frame.Put(); 02232 } 02233 break; 02234 } 02235 case 0xA0: // T_DATA_LAST 02236 { 02237 slots[slot]->Process(buff,len); 02238 unsigned char *b; 02239 if((b=frame.GetBuff(6))) { 02240 TPDU(b,slot); 02241 SB_TAG(&b[2],slotframe->Avail()>0 ? 0x80:0x00); 02242 frame.Put(); 02243 } 02244 break; 02245 } 02246 } 02247 } 02248 } 02249 else PRINTF(L_CORE_CIFULL,"%s: short write (buff=%d len=%d)",devId,buff!=0,len); 02250 } 02251 02252 bool cCam::Reset(int Slot) 02253 { 02254 cMutexLock lock(&ciMutex); 02255 PRINTF(L_CORE_CI,"%s: reset of slot %d requested",devId,Slot); 02256 return slots[Slot] ? slots[Slot]->Reset():false; 02257 } 02258 02259 eModuleStatus cCam::ModuleStatus(int Slot) 02260 { 02261 cMutexLock lock(&ciMutex); 02262 bool enable=ScSetup.CapCheck(device->CardIndex()); 02263 if(!enable) Stop(); 02264 return (enable && slots[Slot]) ? slots[Slot]->Status():msNone; 02265 } 02266 02267 bool cCam::Assign(cDevice *Device, bool Query) 02268 { 02269 return Device ? (Device==device) : true; 02270 } 02271 #endif //!SASC 02272 02273 bool cCam::IsSoftCSA(bool live) 02274 { 02275 return softcsa && (!fullts || !live); 02276 } 02277 02278 void cCam::Tune(const cChannel *channel) 02279 { 02280 cMutexLock lock(&camMutex); 02281 if(source!=channel->Source() || transponder!=channel->Transponder()) { 02282 source=channel->Source(); transponder=channel->Transponder(); 02283 PRINTF(L_CORE_PIDS,"%s: now tuned to source %x(%s) transponder %x",devId,source,*cSource::ToString(source),transponder); 02284 Stop(); 02285 } 02286 else PRINTF(L_CORE_PIDS,"%s: tune to same source/transponder",devId); 02287 } 02288 02289 void cCam::PostTune(void) 02290 { 02291 if(ScSetup.PrestartAU) { 02292 LogStartup(); 02293 if(logger) logger->PreScan(source,transponder); 02294 } 02295 } 02296 02297 void cCam::SetPid(int type, int pid, bool on) 02298 { 02299 cMutexLock lock(&camMutex); 02300 int oldA=liveApid, oldV=liveVpid; 02301 if(type==1) liveVpid=on ? pid:0; 02302 else if(type==0) liveApid=on ? pid:0; 02303 else if(liveVpid==pid && on) liveVpid=0; 02304 else if(liveApid==pid && on) liveApid=0; 02305 if(oldA!=liveApid || oldV!=liveVpid) 02306 PRINTF(L_CORE_PIDS,"%s: livepids video=%04x audio=%04x",devId,liveVpid,liveApid); 02307 } 02308 02309 void cCam::Stop(void) 02310 { 02311 cMutexLock lock(&camMutex); 02312 for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler)) 02313 handler->Stop(); 02314 if(logger) logger->Down(); 02315 if(hookman) hookman->Down(); 02316 memset(splitSid,0,sizeof(splitSid)); 02317 } 02318 02319 void cCam::AddPrg(cPrg *prg) 02320 { 02321 cMutexLock lock(&camMutex); 02322 bool islive=false; 02323 for(cPrgPid *pid=prg->pids.First(); pid; pid=prg->pids.Next(pid)) 02324 if(pid->pid==liveVpid || pid->pid==liveApid) { 02325 islive=true; 02326 break; 02327 } 02328 bool needZero=!IsSoftCSA(islive) && (islive || !ScSetup.ConcurrentFF); 02329 bool noshift=IsSoftCSA(true) || (prg->IsUpdate() && prg->pids.Count()==0); 02330 PRINTF(L_CORE_PIDS,"%s: %s SID %d (zero=%d noshift=%d)",devId,prg->IsUpdate()?"update":"add",prg->sid,needZero,noshift); 02331 if(prg->pids.Count()>0) { 02332 LBSTART(L_CORE_PIDS); 02333 LBPUT("%s: pids",devId); 02334 for(cPrgPid *pid=prg->pids.First(); pid; pid=prg->pids.Next(pid)) 02335 LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid); 02336 LBEND(); 02337 } 02338 bool isSplit=false; 02339 if(prg->pids.Count()>0 && prg->SimplifyCaDescr()) isSplit=true; 02340 else { 02341 for(int i=0; splitSid[i]; i++) 02342 if(splitSid[i]==prg->sid) { isSplit=true; break; } 02343 } 02344 if(!isSplit) { 02345 cEcmHandler *handler=GetHandler(prg->sid,needZero,noshift); 02346 if(handler) { 02347 PRINTF(L_CORE_PIDS,"%s: found handler for SID %d (%s idle=%d idx=%d)",devId,prg->sid,handler->Id(),handler->IsIdle(),handler->CwIndex()); 02348 prg->source=source; 02349 prg->transponder=transponder; 02350 handler->SetPrg(prg); 02351 } 02352 } 02353 else { 02354 PRINTF(L_CORE_PIDS,"%s: SID %d is handled as splitted",devId,prg->sid); 02355 // first update the splitSid list 02356 if(prg->pids.Count()==0) { // delete 02357 for(int i=0; splitSid[i]; i++) 02358 if(splitSid[i]==prg->sid) { 02359 memmove(&splitSid[i],&splitSid[i+1],sizeof(splitSid[0])*(MAX_SPLIT_SID-i)); 02360 break; 02361 } 02362 PRINTF(L_CORE_PIDS,"%s: deleted from list",devId); 02363 } 02364 else { // add 02365 bool has=false; 02366 int i; 02367 for(i=0; splitSid[i]; i++) if(splitSid[i]==prg->sid) has=true; 02368 if(!has) { 02369 if(i<MAX_SPLIT_SID) { 02370 splitSid[i]=prg->sid; 02371 splitSid[i+1]=0; 02372 PRINTF(L_CORE_PIDS,"%s: added to list",devId); 02373 } 02374 else PRINTF(L_CORE_PIDS,"%s: split SID list overflow",devId); 02375 } 02376 } 02377 LBSTART(L_CORE_PIDS); 02378 LBPUT("%s: split SID list now:",devId); 02379 for(int i=0; i<=MAX_SPLIT_SID; i++) LBPUT(" %d",splitSid[i]); 02380 LBEND(); 02381 // prepare an empty prg head 02382 cPrg work; 02383 work.source=source; 02384 work.transponder=transponder; 02385 // loop through pids 02386 int group=1; 02387 cPrgPid *first; 02388 while((first=prg->pids.First())) { 02389 LBSTARTF(L_CORE_PIDS); 02390 LBPUT("%s: group %d pids",devId,group); 02391 prg->pids.Del(first,false); 02392 work.caDescr.Set(&first->caDescr); 02393 first->caDescr.Clear(); 02394 work.pids.Add(first); 02395 LBPUT(" %04x",first->pid); 02396 for(cPrgPid *pid=prg->pids.First(); pid;) { 02397 cPrgPid *next=prg->pids.Next(pid); 02398 if(work.caDescr==pid->caDescr) { // same group 02399 prg->pids.Del(pid,false); 02400 pid->caDescr.Clear(); 02401 work.pids.Add(pid); 02402 LBPUT(" %04x",pid->pid); 02403 } 02404 pid=next; 02405 } 02406 LBEND(); 02407 // get a handler for the group 02408 int grsid=group*SIDGRP_SHIFT+prg->sid; 02409 cEcmHandler *handler=0; 02410 if(group==1) { 02411 // in the first group check if we have a non-split handler 02412 // for the sid 02413 for(handler=handlerList.First(); handler; handler=handlerList.Next(handler)) 02414 if(handler->Sid()==prg->sid) { 02415 // let GetHandler() take care of needZero/noshift stuff 02416 handler=GetHandler(prg->sid,needZero,noshift); 02417 break; 02418 } 02419 } 02420 // otherwise get the group-sid handler 02421 if(!handler) handler=GetHandler(grsid,needZero,noshift); 02422 if(handler) { 02423 PRINTF(L_CORE_PIDS,"%s: found handler for group-SID %d (%s idle=%d idx=%d)",devId,grsid,handler->Id(),handler->IsIdle(),handler->CwIndex()); 02424 work.sid=grsid; 02425 handler->SetPrg(&work); 02426 } 02427 // prepare for next group 02428 work.pids.Clear(); 02429 needZero=false; // only one group can have this 02430 group++; 02431 } 02432 // now we scan the handler list for leftover group handlers 02433 for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler)) { 02434 int sid=handler->Sid(); 02435 if(!handler->IsIdle() && sid>SIDGRP_SHIFT) { 02436 int gr=sid/SIDGRP_SHIFT; 02437 sid%=SIDGRP_SHIFT; 02438 if(sid==prg->sid && gr>=group) { 02439 PRINTF(L_CORE_PIDS,"%s: idle group handler %s idx=%d",devId,handler->Id(),handler->CwIndex()); 02440 work.sid=handler->Sid(); 02441 handler->SetPrg(&work); 02442 } 02443 } 02444 } 02445 } 02446 } 02447 02448 bool cCam::HasPrg(int prg) 02449 { 02450 cMutexLock lock(&camMutex); 02451 for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler)) 02452 if(!handler->IsIdle() && handler->Sid()==prg) 02453 return true; 02454 return false; 02455 } 02456 02457 char *cCam::CurrentKeyStr(int num, const char **id) 02458 { 02459 cMutexLock lock(&camMutex); 02460 if(id) *id=devId; 02461 cEcmHandler *handler; 02462 for(handler=handlerList.First(); handler; handler=handlerList.Next(handler)) 02463 if(--num<0) return handler->CurrentKeyStr(); 02464 return 0; 02465 } 02466 02467 bool cCam::Active(bool log) 02468 { 02469 cMutexLock lock(&camMutex); 02470 for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler)) 02471 if(!handler->IsIdle()) { 02472 if(log) PRINTF(L_GEN_INFO,"handler %s on card %s is not idle",handler->Id(),devId); 02473 return true; 02474 } 02475 return false; 02476 } 02477 02478 void cCam::HouseKeeping(void) 02479 { 02480 cMutexLock lock(&camMutex); 02481 for(cEcmHandler *handler=handlerList.First(); handler;) { 02482 cEcmHandler *next=handlerList.Next(handler); 02483 if(handler->IsRemoveable()) RemHandler(handler); 02484 handler=next; 02485 } 02486 if(handlerList.Count()<1 && !ScSetup.PrestartAU) { 02487 delete hookman; hookman=0; 02488 delete logger; logger=0; 02489 } 02490 } 02491 02492 void cCam::LogStartup(void) 02493 { 02494 cMutexLock lock(&camMutex); 02495 if(!logger && ScSetup.AutoUpdate) { 02496 logger=new cLogger(this,device,devId,IsSoftCSA(false)); 02497 LogStatsUp(); 02498 } 02499 } 02500 02501 void cCam::LogEcmStatus(const cEcmInfo *ecm, bool on) 02502 { 02503 cMutexLock lock(&camMutex); 02504 if(on) LogStartup(); 02505 if(logger) logger->EcmStatus(ecm,on); 02506 } 02507 02508 void cCam::AddHook(cLogHook *hook) 02509 { 02510 cMutexLock lock(&camMutex); 02511 if(!hookman) hookman=new cHookManager(device,devId); 02512 if(hookman) hookman->AddHook(hook); 02513 } 02514 02515 bool cCam::TriggerHook(int id) 02516 { 02517 return hookman && hookman->TriggerHook(id); 02518 } 02519 02520 void cCam::SetCWIndex(int pid, int index) 02521 { 02522 if(index<MAX_CW_IDX) { 02523 ca_pid_t ca_pid; 02524 ca_pid.pid=pid; 02525 ca_pid.index=index; 02526 PRINTF(L_CORE_PIDS,"%s: descrambling pid %04x on index %x",devId,pid,index); 02527 if(!SetCaPid(&ca_pid)) 02528 if(index>0) { 02529 PRINTF(L_GEN_ERROR,"CA_SET_PID failed (%s). Expect a black screen/bad recording. Do you use the patched DVB driver?",strerror(errno)); 02530 PRINTF(L_GEN_WARN,"Adjusting 'Concurrent FF streams' to NO"); 02531 ScSetup.ConcurrentFF=0; 02532 ScSetup.Store(true); 02533 } 02534 } 02535 } 02536 02537 void cCam::WriteCW(int index, unsigned char *cw, bool force) 02538 { 02539 if(index<MAX_CW_IDX) { 02540 for(int i=0; i<16; i+=4) cw[i+3]=cw[i]+cw[i+1]+cw[i+2]; 02541 ca_descr_t ca_descr; 02542 ca_descr.index=index; 02543 unsigned char *last=lastCW[index]; 02544 if(force || memcmp(&cw[0],&last[0],8)) { 02545 memcpy(&last[0],&cw[0],8); 02546 ca_descr.parity=0; 02547 memcpy(ca_descr.cw,&cw[0],8); 02548 if(!SetCaDescr(&ca_descr,force)) 02549 PRINTF(L_GEN_ERROR,"CA_SET_DESCR failed (%s). Expect a black screen.",strerror(errno)); 02550 } 02551 02552 if(force || memcmp(&cw[8],&last[8],8)) { 02553 memcpy(&last[8],&cw[8],8); 02554 ca_descr.parity=1; 02555 memcpy(ca_descr.cw,&cw[8],8); 02556 if(!SetCaDescr(&ca_descr,force)) 02557 PRINTF(L_GEN_ERROR,"CA_SET_DESCR failed (%s). Expect a black screen.",strerror(errno)); 02558 } 02559 } 02560 } 02561 02562 bool cCam::SetCaDescr(ca_descr_t *ca_descr, bool initial) 02563 { 02564 if(!softcsa || (fullts && ca_descr->index==0)) 02565 return devplugin->SetCaDescr(device,ca_descr,initial); 02566 #ifndef SASC 02567 else if(decsa) 02568 return decsa->SetDescr(ca_descr,initial); 02569 #endif //!SASC 02570 return false; 02571 } 02572 02573 bool cCam::SetCaPid(ca_pid_t *ca_pid) 02574 { 02575 if(!softcsa || (fullts && ca_pid->index==0)) 02576 return devplugin->SetCaPid(device,ca_pid); 02577 #ifndef SASC 02578 else if(decsa) 02579 return decsa->SetCaPid(ca_pid); 02580 #endif //!SASC 02581 return false; 02582 } 02583 02584 void cCam::DumpAV7110(void) 02585 { 02586 devplugin->DumpAV(device); 02587 } 02588 02589 int cCam::GetFreeIndex(void) 02590 { 02591 for(int idx=0; idx<MAX_CW_IDX; idx++) 02592 if(!indexMap[idx]) return idx; 02593 return -1; 02594 } 02595 02596 cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift) 02597 { 02598 cEcmHandler *zerohandler=0, *sidhandler=0, *idlehandler=0; 02599 for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler)) { 02600 if(handler->Sid()==sid) 02601 sidhandler=handler; 02602 if(handler->CwIndex()==0) 02603 zerohandler=handler; 02604 if(handler->IsIdle() && (!idlehandler || (!(needZero ^ (idlehandler->CwIndex()!=0)) && (needZero ^ (handler->CwIndex()!=0))) )) 02605 idlehandler=handler; 02606 } 02607 LBSTART(L_CORE_PIDS); 02608 LBPUT("%s: SID=%d zero=%d |",devId,sid,needZero); 02609 if(sidhandler) LBPUT(" sid=%d/%d/%d",sidhandler->CwIndex(),sidhandler->Sid(),sidhandler->IsIdle()); 02610 else LBPUT(" sid=-/-/-"); 02611 if(zerohandler) LBPUT(" zero=%d/%d/%d",zerohandler->CwIndex(),zerohandler->Sid(),zerohandler->IsIdle()); 02612 else LBPUT(" zero=-/-/-"); 02613 if(idlehandler) LBPUT(" idle=%d/%d/%d",idlehandler->CwIndex(),idlehandler->Sid(),idlehandler->IsIdle()); 02614 else LBPUT(" idle=-/-/-"); 02615 LBEND(); 02616 02617 if(sidhandler) { 02618 if(needZero && sidhandler->CwIndex()!=0 && !noshift) { 02619 if(!sidhandler->IsIdle()) 02620 PRINTF(L_CORE_ECM,"%s: shifting cwindex on non-idle handler.",devId); 02621 if(zerohandler) { 02622 if(!zerohandler->IsIdle()) 02623 PRINTF(L_CORE_ECM,"%s: shifting non-idle zero handler. This shouldn't happen!",devId); 02624 zerohandler->ShiftCwIndex(sidhandler->CwIndex()); 02625 sidhandler->ShiftCwIndex(0); 02626 } 02627 else if(indexMap[0]==0) { 02628 indexMap[0]=1; 02629 indexMap[sidhandler->CwIndex()]=0; 02630 sidhandler->ShiftCwIndex(0); 02631 } 02632 else PRINTF(L_CORE_ECM,"%s: zero index not free.",devId); 02633 } 02634 02635 if(!needZero && sidhandler->CwIndex()==0 && !noshift) { 02636 if(!sidhandler->IsIdle()) 02637 PRINTF(L_CORE_ECM,"%s: shifting cwindex on non-idle handler.",devId); 02638 int idx=GetFreeIndex(); 02639 if(idx>=0) { 02640 indexMap[idx]=1; 02641 sidhandler->ShiftCwIndex(idx); 02642 indexMap[0]=0; 02643 } 02644 else PRINTF(L_CORE_ECM,"%s: no free cwindex. Can't free zero index.",devId); 02645 } 02646 02647 return sidhandler; 02648 } 02649 02650 if(needZero && zerohandler) { 02651 if(!zerohandler->IsIdle()) 02652 PRINTF(L_CORE_ECM,"%s: changing SID on non-idle zero handler. This shouldn't happen!",devId); 02653 return zerohandler; 02654 } 02655 02656 if(idlehandler) { 02657 if(needZero && idlehandler->CwIndex()!=0 && !noshift) { 02658 if(indexMap[0]==0) { 02659 indexMap[0]=1; 02660 indexMap[idlehandler->CwIndex()]=0; 02661 idlehandler->ShiftCwIndex(0); 02662 } 02663 else PRINTF(L_CORE_ECM,"%s: zero index not free. (2)",devId); 02664 } 02665 if(!needZero && idlehandler->CwIndex()==0 && !noshift) { 02666 int idx=GetFreeIndex(); 02667 if(idx>=0) { 02668 indexMap[idx]=1; 02669 idlehandler->ShiftCwIndex(idx); 02670 indexMap[0]=0; 02671 } 02672 else PRINTF(L_CORE_ECM,"%s: no free cwindex. Can't free zero index. (2)",devId); 02673 } 02674 if((needZero ^ (idlehandler->CwIndex()==0))) 02675 PRINTF(L_CORE_ECM,"%s: idlehandler index doesn't match needZero",devId); 02676 return idlehandler; 02677 } 02678 02679 int idx=GetFreeIndex(); 02680 if(!needZero && idx==0) { 02681 indexMap[0]=1; 02682 idx=GetFreeIndex(); 02683 indexMap[0]=0; 02684 if(idx<0) { 02685 idx=0; 02686 PRINTF(L_CORE_ECM,"%s: can't respect !needZero for new handler",devId); 02687 } 02688 } 02689 if(idx<0) { 02690 PRINTF(L_CORE_ECM,"%s: no free cwindex",devId); 02691 return 0; 02692 } 02693 indexMap[idx]=1; 02694 idlehandler=new cEcmHandler(this,device,devId,idx); 02695 handlerList.Add(idlehandler); 02696 return idlehandler; 02697 } 02698 02699 void cCam::RemHandler(cEcmHandler *handler) 02700 { 02701 int idx=handler->CwIndex(); 02702 PRINTF(L_CORE_PIDS,"%s: removing %s on cw index %d",devId,handler->Id(),idx); 02703 handlerList.Del(handler); 02704 indexMap[idx]=0; 02705 } 02706 02707 // -- cDeCSA ------------------------------------------------------------------- 02708 02709 #ifndef SASC 02710 02711 #define MAX_STALL_MS 70 02712 02713 #define MAX_REL_WAIT 100 // time to wait if key in used on set 02714 #define MAX_KEY_WAIT 500 // time to wait if key not ready on change 02715 02716 #define FL_EVEN_GOOD 1 02717 #define FL_ODD_GOOD 2 02718 #define FL_ACTIVITY 4 02719 02720 02721 cDeCSA::cDeCSA(const char *DevId) 02722 :stall(MAX_STALL_MS) 02723 { 02724 devId=DevId; 02725 cs=get_suggested_cluster_size(); 02726 PRINTF(L_CORE_CSA,"%s: clustersize=%d rangesize=%d",devId,cs,cs*2+5); 02727 range=MALLOC(unsigned char *,(cs*2+5)); 02728 memset(keys,0,sizeof(keys)); 02729 memset(pidmap,0,sizeof(pidmap)); 02730 ResetState(); 02731 } 02732 02733 cDeCSA::~cDeCSA() 02734 { 02735 for(int i=0; i<MAX_CSA_IDX; i++) 02736 if(keys[i]) free_key_struct(keys[i]); 02737 free(range); 02738 } 02739 02740 void cDeCSA::ResetState(void) 02741 { 02742 PRINTF(L_CORE_CSA,"%s: reset state",devId); 02743 memset(even_odd,0,sizeof(even_odd)); 02744 memset(flags,0,sizeof(flags)); 02745 lastData=0; 02746 } 02747 02748 void cDeCSA::SetActive(bool on) 02749 { 02750 if(!on && active) ResetState(); 02751 active=on; 02752 PRINTF(L_CORE_CSA,"%s: set active %s",devId,active?"on":"off"); 02753 } 02754 02755 bool cDeCSA::GetKeyStruct(int idx) 02756 { 02757 if(!keys[idx]) keys[idx]=get_key_struct(); 02758 return keys[idx]!=0; 02759 } 02760 02761 bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial) 02762 { 02763 cMutexLock lock(&mutex); 02764 int idx=ca_descr->index; 02765 if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) { 02766 if(!initial && active && ca_descr->parity==(even_odd[idx]&0x40)>>6) { 02767 if(flags[idx] & (ca_descr->parity?FL_ODD_GOOD:FL_EVEN_GOOD)) { 02768 PRINTF(L_CORE_CSA,"%s.%d: %s key in use (%d ms)",devId,idx,ca_descr->parity?"odd":"even",MAX_REL_WAIT); 02769 if(wait.TimedWait(mutex,MAX_REL_WAIT)) PRINTF(L_CORE_CSA,"%s.%d: successfully waited for release",devId,idx); 02770 else PRINTF(L_CORE_CSA,"%s.%d: timed out. setting anyways",devId,idx); 02771 } 02772 else PRINTF(L_CORE_CSA,"%s.%d: late key set...",devId,idx); 02773 } 02774 LDUMP(L_CORE_CSA,ca_descr->cw,8,"%s.%d: %4s key set",devId,idx,ca_descr->parity?"odd":"even"); 02775 if(ca_descr->parity==0) { 02776 set_even_control_word(keys[idx],ca_descr->cw); 02777 if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_EVEN_GOOD|FL_ACTIVITY; 02778 else PRINTF(L_CORE_CSA,"%s.%d: zero even CW",devId,idx); 02779 wait.Broadcast(); 02780 } 02781 else { 02782 set_odd_control_word(keys[idx],ca_descr->cw); 02783 if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_ODD_GOOD|FL_ACTIVITY; 02784 else PRINTF(L_CORE_CSA,"%s.%d: zero odd CW",devId,idx); 02785 wait.Broadcast(); 02786 } 02787 } 02788 return true; 02789 } 02790 02791 bool cDeCSA::SetCaPid(ca_pid_t *ca_pid) 02792 { 02793 cMutexLock lock(&mutex); 02794 if(ca_pid->index<MAX_CSA_IDX && ca_pid->pid<MAX_CSA_PIDS) { 02795 pidmap[ca_pid->pid]=ca_pid->index; 02796 PRINTF(L_CORE_CSA,"%s.%d: set pid %04x",devId,ca_pid->index,ca_pid->pid); 02797 } 02798 return true; 02799 } 02800 02801 bool cDeCSA::Decrypt(unsigned char *data, int len, bool force) 02802 { 02803 cMutexLock lock(&mutex); 02804 int r=-2, ccs=0, currIdx=-1; 02805 bool newRange=true; 02806 range[0]=0; 02807 len-=(TS_SIZE-1); 02808 int l; 02809 for(l=0; l<len; l+=TS_SIZE) { 02810 if(data[l]!=TS_SYNC_BYTE) { // let higher level cope with that 02811 PRINTF(L_CORE_CSA,"%s: garbage in TS buffer",devId); 02812 if(ccs) force=true; // prevent buffer stall 02813 break; 02814 } 02815 unsigned int ev_od=data[l+3]&0xC0; 02816 if(ev_od==0x80 || ev_od==0xC0) { // encrypted 02817 int idx=pidmap[((data[l+1]<<8)+data[l+2])&(MAX_CSA_PIDS-1)]; 02818 if(currIdx<0 || idx==currIdx) { // same or no index 02819 currIdx=idx; 02820 if(ccs==0 && ev_od!=even_odd[idx]) { 02821 even_odd[idx]=ev_od; 02822 wait.Broadcast(); 02823 PRINTF(L_CORE_CSA,"%s.%d: change to %s key",devId,idx,(ev_od&0x40)?"odd":"even"); 02824 bool doWait=false; 02825 if(ev_od&0x40) { 02826 flags[idx]&=~FL_EVEN_GOOD; 02827 if(!(flags[idx]&FL_ODD_GOOD)) doWait=true; 02828 } 02829 else { 02830 flags[idx]&=~FL_ODD_GOOD; 02831 if(!(flags[idx]&FL_EVEN_GOOD)) doWait=true; 02832 } 02833 if(doWait) { 02834 PRINTF(L_CORE_CSA,"%s.%d: %s key not ready (%d ms)",devId,idx,(ev_od&0x40)?"odd":"even",MAX_KEY_WAIT); 02835 if(flags[idx]&FL_ACTIVITY) { 02836 flags[idx]&=~FL_ACTIVITY; 02837 if(wait.TimedWait(mutex,MAX_KEY_WAIT)) PRINTF(L_CORE_CSA,"%s.%d: successfully waited for key",devId,idx); 02838 else PRINTF(L_CORE_CSA,"%s.%d: timed out. proceeding anyways",devId,idx); 02839 } 02840 else PRINTF(L_CORE_CSA,"%s.%d: not active. wait skipped",devId,idx); 02841 } 02842 } 02843 if(newRange) { 02844 r+=2; newRange=false; 02845 range[r]=&data[l]; 02846 range[r+2]=0; 02847 } 02848 range[r+1]=&data[l+TS_SIZE]; 02849 if(++ccs>=cs) break; 02850 } 02851 else newRange=true; // other index, create hole 02852 } 02853 else { // unencrypted 02854 // nothing, we don't create holes for unencrypted packets 02855 } 02856 } 02857 int scanTS=l/TS_SIZE; 02858 int stallP=ccs*100/scanTS; 02859 02860 LBSTART(L_CORE_CSAVERB); 02861 LBPUT("%s: %s-%d-%d : %d-%d-%d stall=%d :: ", 02862 devId,data==lastData?"SAME":"MOVE",(len+(TS_SIZE-1))/TS_SIZE,force, 02863 currIdx,ccs,scanTS,stallP); 02864 for(int l=0; l<len; l+=TS_SIZE) { 02865 if(data[l]!=TS_SYNC_BYTE) break; 02866 unsigned int ev_od=data[l+3]&0xC0; 02867 if(ev_od&0x80) { 02868 int pid=(data[l+1]<<8)+data[l+2]; 02869 int idx=pidmap[pid&(MAX_CSA_PIDS-1)]; 02870 LBPUT("%s/%x/%d ",(ev_od&0x40)?"o":"e",pid,idx); 02871 } 02872 else { 02873 LBPUT("*/%x ",(data[l+1]<<8)+data[l+2]); 02874 } 02875 } 02876 LBEND(); 02877 02878 if(r>=0 && ccs<cs && !force) { 02879 if(lastData==data && stall.TimedOut()) { 02880 PRINTF(L_CORE_CSAVERB,"%s: stall timeout -> forced",devId); 02881 force=true; 02882 } 02883 else if(stallP<=10 && scanTS>=cs) { 02884 PRINTF(L_CORE_CSAVERB,"%s: flow factor stall -> forced",devId); 02885 force=true; 02886 } 02887 } 02888 lastData=data; 02889 02890 if(r>=0) { // we have some range 02891 if(ccs>=cs || force) { 02892 if(GetKeyStruct(currIdx)) { 02893 int n=decrypt_packets(keys[currIdx],range); 02894 PRINTF(L_CORE_CSAVERB,"%s.%d: decrypting ccs=%3d cs=%3d %s -> %3d decrypted",devId,currIdx,ccs,cs,ccs>=cs?"OK ":"INC",n); 02895 if(n>0) { 02896 stall.Set(MAX_STALL_MS); 02897 return true; 02898 } 02899 } 02900 } 02901 else PRINTF(L_CORE_CSAVERB,"%s.%d: incomplete ccs=%3d cs=%3d",devId,currIdx,ccs,cs); 02902 } 02903 return false; 02904 } 02905 02906 #endif //!SASC