#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <sys/ioctl.h>
+#include <vdr/device.h>
#include <vdr/channels.h>
#include <vdr/thread.h>
+#include <vdr/ringbuffer.h>
#include "cam.h"
+#include "global.h"
#include "device.h"
#include "scsetup.h"
#include "filter.h"
#include "override.h"
#include "misc.h"
#include "log-core.h"
+#include "FFdecsa/FFdecsa.h"
#define IDLE_SLEEP 0 // idleTime when sleeping
#define IDLE_GETCA 200 // idleTime when waiting for ca descriptors
// -- cHookManager -------------------------------------------------------------
class cHookManager : public cAction {
- int cardNum;
+ const char *devId;
cSimpleList<cLogHook> hooks;
//
- cPidFilter *AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc);
+ cPidFilter *AddFilter(int Pid, int Section, int Mask, int IdleTime);
void ClearHooks(void);
void DelHook(cLogHook *hook);
protected:
virtual void Process(cPidFilter *filter, unsigned char *data, int len);
public:
- cHookManager(int CardNum);
+ cHookManager(cDevice *Device, const char *DevId);
virtual ~cHookManager();
void AddHook(cLogHook *hook);
bool TriggerHook(int id);
void Down(void);
};
-cHookManager::cHookManager(int CardNum)
-:cAction("hookmanager",CardNum)
+cHookManager::cHookManager(cDevice *Device, const char *DevId)
+:cAction("hookmanager",Device,DevId)
{
- cardNum=CardNum;
+ devId=DevId;
Priority(10);
}
void cHookManager::AddHook(cLogHook *hook)
{
Lock();
- PRINTF(L_CORE_HOOK,"%d: starting hook '%s' (%04x)",cardNum,hook->name,hook->id);
+ PRINTF(L_CORE_HOOK,"%s: starting hook '%s' (%04x)",devId,hook->name,hook->id);
hook->delay.Set(CHAIN_HOLD);
- hook->cardNum=cardNum;
hooks.Add(hook);
for(cPid *pid=hook->pids.First(); pid; pid=hook->pids.Next(pid)) {
- cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,pid->mode,CHAIN_HOLD/8,false);
+ cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,CHAIN_HOLD/8);
if(filter) {
filter->userData=(void *)hook;
pid->filter=filter;
void cHookManager::DelHook(cLogHook *hook)
{
- PRINTF(L_CORE_HOOK,"%d: stopping hook '%s' (%04x)",cardNum,hook->name,hook->id);
+ PRINTF(L_CORE_HOOK,"%s: stopping hook '%s' (%04x)",devId,hook->name,hook->id);
for(cPid *pid=hook->pids.First(); pid; pid=hook->pids.Next(pid)) {
cPidFilter *filter=pid->filter;
if(filter) {
hooks.Del(hook);
}
-cPidFilter *cHookManager::AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc)
+cPidFilter *cHookManager::AddFilter(int Pid, int Section, int Mask, int IdleTime)
{
cPidFilter *filter=NewFilter(IdleTime);
if(filter) {
filter->SetBuffSize(32768);
- filter->Start(Pid,Section,Mask,Mode,Crc);
- PRINTF(L_CORE_HOOK,"%d: added filter pid=0x%.4x sct=0x%.2x/0x%.2x/0x%.2x idle=%d crc=%d",cardNum,Pid,Section,Mask,Mode,IdleTime,Crc);
+ filter->Start(Pid,Section,Mask);
+ PRINTF(L_CORE_HOOK,"%s: added filter pid=0x%.4x sct=0x%.2x/0x%.2x idle=%d",devId,Pid,Section,Mask,IdleTime);
}
- else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for hookmanager %d",cardNum);
+ else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for hookmanager %s",devId);
return filter;
}
if(hook->bailOut || hook->delay.TimedOut()) DelHook(hook);
}
}
- else PRINTF(L_CORE_HOOK,"%d: incomplete section %d != %d",cardNum,len,SCT_LEN(data));
+ else PRINTF(L_CORE_HOOK,"%s: incomplete section %d != %d",devId,len,SCT_LEN(data));
}
else {
cLogHook *hook=(cLogHook *)(filter->userData);
class cLogChain : public cSimpleItem {
public:
- int cardNum, caid, source, transponder;
+ cCam *cam;
+ const char *devId;
+ int caid, source, transponder;
bool softCSA, active, delayed;
cTimeMs delay;
cPids pids;
cSimpleList<cSystem> systems;
//
- cLogChain(int CardNum, bool soft, int src, int tr);
+ cLogChain(cCam *Cam, const char *DevId, bool soft, int src, int tr);
void Process(int pid, const unsigned char *data);
bool Parse(const unsigned char *cat);
};
-cLogChain::cLogChain(int CardNum, bool soft, int src, int tr)
+cLogChain::cLogChain(cCam *Cam, const char *DevId, bool soft, int src, int tr)
{
- cardNum=CardNum; softCSA=soft; source=src; transponder=tr;
+ cam=Cam; devId=DevId; softCSA=soft; source=src; transponder=tr;
active=delayed=false;
}
if(cat[0]==0x09) {
caid=WORD(cat,2,0xFFFF);
LBSTARTF(L_CORE_AU);
- LBPUT("%d: chain caid %04x",cardNum,caid);
+ LBPUT("%s: chain caid %04x",devId,caid);
cSystem *sys;
if(systems.Count()>0) {
LBPUT(" ++");
while((sys=cSystems::FindBySysId(caid,!softCSA,Pri))) {
Pri=sys->Pri();
if(sys->HasLogger()) {
- sys->CardNum(cardNum);
+ sys->SetOwner(cam);
sys->ParseCAT(&pids,cat,source,transponder);
systems.Add(sys);
LBPUT(" %s(%d)",sys->Name(),sys->Pri());
}
if(systems.Count()==0) LBPUT(" none available");
for(cPid *pid=pids.First(); pid; pid=pids.Next(pid))
- LBPUT(" [%04x-%02x/%02x/%02x]",pid->pid,pid->sct,pid->mask,pid->mode);
+ LBPUT(" [%04x-%02x/%02x]",pid->pid,pid->sct,pid->mask);
LBEND();
if(systems.Count()>0 && pids.Count()>0)
return true;
class cLogger : public cAction {
private:
- int cardNum;
+ cCam *cam;
+ const char *devId;
bool softCSA, up;
cSimpleList<cLogChain> chains;
cSimpleList<cEcmInfo> active;
ePreMode prescan;
cTimeMs pretime;
//
- cPidFilter *AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc);
+ cPidFilter *AddFilter(int Pid, int Section, int Mask, int IdleTime);
void SetChains(void);
void ClearChains(void);
void StartChain(cLogChain *chain);
protected:
virtual void Process(cPidFilter *filter, unsigned char *data, int len);
public:
- cLogger(int CardNum, bool soft);
+ cLogger(cCam *Cam, cDevice *Device, const char *DevId, bool soft);
virtual ~cLogger();
void EcmStatus(const cEcmInfo *ecm, bool on);
void Up(void);
void PreScan(int src, int tr);
};
-cLogger::cLogger(int CardNum, bool soft)
-:cAction("logger",CardNum)
+cLogger::cLogger(cCam *Cam, cDevice *Device, const char *DevId, bool soft)
+:cAction("logger",Device,DevId)
{
- cardNum=CardNum; softCSA=soft;
+ cam=Cam; devId=DevId; softCSA=soft;
catfilt=0; up=false; prescan=pmNone;
Priority(10);
}
{
Lock();
if(!up) {
- PRINTF(L_CORE_AUEXTRA,"%d: UP",cardNum);
+ PRINTF(L_CORE_AUEXTRA,"%s: UP",devId);
catVers=-1;
- catfilt=AddFilter(1,0x01,0xFF,0,0,true);
+ catfilt=AddFilter(1,0x01,0xFF,0);
up=true;
}
Unlock();
{
Lock();
if(up) {
- PRINTF(L_CORE_AUEXTRA,"%d: DOWN",cardNum);
+ PRINTF(L_CORE_AUEXTRA,"%s: DOWN",devId);
ClearChains();
DelAllFilter();
catfilt=0; up=false; prescan=pmNone;
void cLogger::EcmStatus(const cEcmInfo *ecm, bool on)
{
Lock();
- PRINTF(L_CORE_AUEXTRA,"%d: ecm prgid=%d caid=%04x prov=%.4x %s",cardNum,ecm->prgId,ecm->caId,ecm->provId,on ? "active":"inactive");
+ PRINTF(L_CORE_AUEXTRA,"%s: ecm prgid=%d caid=%04x prov=%.4x %s",devId,ecm->prgId,ecm->caId,ecm->provId,on ? "active":"inactive");
source=ecm->source; transponder=ecm->transponder;
cEcmInfo *e;
if(on) {
void cLogger::StartChain(cLogChain *chain)
{
if(chain->delayed)
- PRINTF(L_CORE_AUEXTRA,"%d: restarting delayed chain %04x",cardNum,chain->caid);
+ PRINTF(L_CORE_AUEXTRA,"%s: restarting delayed chain %04x",devId,chain->caid);
chain->delayed=false;
if(!chain->active) {
- PRINTF(L_CORE_AU,"%d: starting chain %04x",cardNum,chain->caid);
+ PRINTF(L_CORE_AU,"%s: starting chain %04x",devId,chain->caid);
chain->active=true;
for(cPid *pid=chain->pids.First(); pid; pid=chain->pids.Next(pid)) {
- cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,pid->mode,CHAIN_HOLD/8,false);
+ cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,CHAIN_HOLD/8);
if(filter) {
filter->userData=(void *)chain;
pid->filter=filter;
{
if(chain->active) {
if(force || (chain->delayed && chain->delay.TimedOut())) {
- PRINTF(L_CORE_AU,"%d: stopping chain %04x",cardNum,chain->caid);
+ PRINTF(L_CORE_AU,"%s: stopping chain %04x",devId,chain->caid);
chain->active=false;
for(cPid *pid=chain->pids.First(); pid; pid=chain->pids.Next(pid)) {
cPidFilter *filter=pid->filter;
}
}
else if(!chain->delayed) {
- PRINTF(L_CORE_AUEXTRA,"%d: delaying chain %04x",cardNum,chain->caid);
+ PRINTF(L_CORE_AUEXTRA,"%s: delaying chain %04x",devId,chain->caid);
chain->delayed=true;
chain->delay.Set(CHAIN_HOLD);
}
}
}
-cPidFilter *cLogger::AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc)
+cPidFilter *cLogger::AddFilter(int Pid, int Section, int Mask, int IdleTime)
{
cPidFilter *filter=NewFilter(IdleTime);
if(filter) {
if(Pid>1) filter->SetBuffSize(KILOBYTE(64));
- filter->Start(Pid,Section,Mask,Mode,Crc);
- PRINTF(L_CORE_AUEXTRA,"%d: added filter pid=0x%.4x sct=0x%.2x/0x%.2x/0x%.2x idle=%d crc=%d",cardNum,Pid,Section,Mask,Mode,IdleTime,Crc);
+ filter->Start(Pid,Section,Mask);
+ PRINTF(L_CORE_AUEXTRA,"%s: added filter pid=0x%.4x sct=0x%.2x/0x%.2x idle=%d",devId,Pid,Section,Mask,IdleTime);
}
- else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for logger %d",cardNum);
+ else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for logger %s",devId);
return filter;
}
if(chain)
chain->Parse(&data[i]);
else {
- chain=new cLogChain(cardNum,softCSA,source,transponder);
+ chain=new cLogChain(cam,devId,softCSA,source,transponder);
if(chain->Parse(&data[i]))
chains.Add(chain);
else
if(filter==catfilt) {
int vers=(data[5]&0x3E)>>1;
if(data[0]==0x01 && vers!=catVers) {
- PRINTF(L_CORE_AUEXTRA,"%d: got CAT version %02x",cardNum,vers);
+ PRINTF(L_CORE_AUEXTRA,"%s: got CAT version %02x",devId,vers);
catVers=vers;
HEXDUMP(L_HEX_CAT,data,len,"CAT vers %02x",catVers);
ClearChains();
if(chain->delayed) StopChain(chain,false);
}
}
- else PRINTF(L_CORE_AU,"%d: incomplete section %d != %d",cardNum,len,SCT_LEN(data));
+ else PRINTF(L_CORE_AU,"%s: incomplete section %d != %d",devId,len,SCT_LEN(data));
}
}
else {
return true;
}
+// -- cCaDescr -----------------------------------------------------------------
+
+class cCaDescr {
+private:
+ unsigned char *descr;
+ int len;
+public:
+ cCaDescr(void);
+ cCaDescr(const cCaDescr &arg);
+ ~cCaDescr();
+ const unsigned char *Get(int &l) const;
+ void Set(const cCaDescr *d);
+ void Set(const unsigned char *de, int l);
+ void Clear(void);
+ bool operator== (const cCaDescr &arg) const;
+ void Join(const cCaDescr *cd, bool rev=false);
+ cString ToString(void);
+ };
+
+cCaDescr::cCaDescr(void)
+{
+ descr=0; len=0;
+}
+
+cCaDescr::cCaDescr(const cCaDescr &cd)
+{
+ descr=0; len=0;
+ Set(cd.descr,cd.len);
+}
+
+cCaDescr::~cCaDescr()
+{
+ Clear();
+}
+
+const unsigned char *cCaDescr::Get(int &l) const
+{
+ l=len;
+ return descr;
+}
+
+void cCaDescr::Set(const cCaDescr *d)
+{
+ Set(d->descr,d->len);
+}
+
+void cCaDescr::Set(const unsigned char *de, int l)
+{
+ Clear();
+ if(l) {
+ descr=MALLOC(unsigned char,l);
+ if(descr) {
+ memcpy(descr,de,l);
+ len=l;
+ }
+ }
+}
+
+void cCaDescr::Clear(void)
+{
+ free(descr); descr=0; len=0;
+}
+
+void cCaDescr::Join(const cCaDescr *cd, bool rev)
+{
+ if(cd->descr) {
+ int l=len+cd->len;
+ unsigned char *m=MALLOC(unsigned char,l);
+ if(m) {
+ if(!rev) {
+ if(descr) memcpy(m,descr,len);
+ memcpy(m+len,cd->descr,cd->len);
+ }
+ else {
+ memcpy(m,cd->descr,cd->len);
+ if(descr) memcpy(m+cd->len,descr,len);
+ }
+ Clear();
+ descr=m; len=l;
+ }
+ }
+}
+
+bool cCaDescr::operator== (const cCaDescr &cd) const
+{
+ return len==cd.len && (len==0 || memcmp(descr,cd.descr,len)==0);
+}
+
+cString cCaDescr::ToString(void)
+{
+ if(!descr) return "<empty>";
+ char *str=AUTOARRAY(char,len*3+8);
+ int q=sprintf(str,"%02X",descr[0]);
+ for(int i=1; i<len; i++) q+=sprintf(str+q," %02X",descr[i]);
+ return str;
+}
+
+// -- cPrgPid ------------------------------------------------------------------
+
+class cPrgPid : public cSimpleItem {
+private:
+ bool proc;
+public:
+ int type, pid;
+ cCaDescr caDescr;
+ //
+ cPrgPid(int Type, int Pid) { type=Type; pid=Pid; proc=false; }
+ bool Proc(void) const { return proc; }
+ void Proc(bool is) { proc=is; };
+ };
+
+// -- cPrg ---------------------------------------------------------------------
+
+class cPrg : public cSimpleItem {
+private:
+ bool isUpdate, pidCaDescr;
+ //
+ void Setup(void);
+public:
+ int sid, source, transponder;
+ cSimpleList<cPrgPid> pids;
+ cCaDescr caDescr;
+ //
+ cPrg(void);
+ cPrg(int Sid, bool IsUpdate);
+ bool IsUpdate(void) const { return isUpdate; }
+ bool HasPidCaDescr(void) const { return pidCaDescr; }
+ void SetPidCaDescr(bool val) { pidCaDescr=val; }
+ bool SimplifyCaDescr(void);
+ void DumpCaDescr(int c);
+ };
+
+cPrg::cPrg(void)
+{
+ Setup();
+}
+
+cPrg::cPrg(int Sid, bool IsUpdate)
+{
+ Setup();
+ sid=Sid; isUpdate=IsUpdate;
+}
+
+void cPrg::Setup(void)
+{
+ sid=-1; source=-1; transponder=-1;
+ isUpdate=pidCaDescr=false;
+}
+
+void cPrg::DumpCaDescr(int c)
+{
+ PRINTF(c,"prgca: %s",*caDescr.ToString());
+ for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
+ PRINTF(c,"pidca %04x: %s",pid->pid,*pid->caDescr.ToString());
+}
+
+bool cPrg::SimplifyCaDescr(void)
+{
+//XXX
+PRINTF(L_CORE_PIDS,"SimplyCa entry pidCa=%d",HasPidCaDescr());
+DumpCaDescr(L_CORE_PIDS);
+//XXX
+
+ if(HasPidCaDescr()) {
+ bool equal=true;
+ if(pids.Count()>1) {
+ cPrgPid *pid0=pids.First();
+ for(cPrgPid *pid1=pids.Next(pid0); pid1; pid1=pids.Next(pid1))
+ if(!(pid0->caDescr==pid1->caDescr)) { equal=false; break; }
+ }
+ if(equal) {
+ cPrgPid *pid=pids.First();
+ caDescr.Join(&pid->caDescr);
+ for(; pid; pid=pids.Next(pid)) pid->caDescr.Clear();
+ SetPidCaDescr(false);
+ }
+ }
+ if(HasPidCaDescr()) {
+ for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
+ pid->caDescr.Join(&caDescr,true);
+ caDescr.Clear();
+ }
+
+//XXX
+PRINTF(L_CORE_PIDS,"SimplyCa exit pidCa=%d",HasPidCaDescr());
+DumpCaDescr(L_CORE_PIDS);
+//XXX
+
+ return HasPidCaDescr();
+}
+
// -- cEcmPri ------------------------------------------------------------------
class cEcmPri : public cSimpleItem {
class cEcmHandler : public cSimpleItem, public cAction {
private:
- int cardNum, cwIndex;
+ const char *devId;
+ int cwIndex;
cCam *cam;
char *id;
cTimeMs idleTime;
protected:
virtual void Process(cPidFilter *filter, unsigned char *data, int len);
public:
- cEcmHandler(cCam *Cam, int CardNum, int cwindex);
+ cEcmHandler(cCam *Cam, cDevice *Device, const char *DevId, int cwindex);
virtual ~cEcmHandler();
void Stop(void);
void SetPrg(cPrg *Prg);
const char *Id(void) const { return id; }
};
-cEcmHandler::cEcmHandler(cCam *Cam, int CardNum, int cwindex)
-:cAction("ecmhandler",CardNum)
+cEcmHandler::cEcmHandler(cCam *Cam, cDevice *Device, const char *DevId, int cwindex)
+:cAction("ecmhandler",Device,DevId)
,failed(32,0)
{
cam=Cam;
- cardNum=CardNum;
+ devId=DevId;
cwIndex=cwindex;
sys=0; filter=0; ecm=0; ecmPri=0; mode=-1;
trigger=ecmUpd=false; triggerMode=-1;
filterSource=filterTransponder=0; filterCwIndex=-1; filterSid=-1;
- id=bprintf("%d.%d",cardNum,cwindex);
+ id=bprintf("%s.%d",devId,cwindex);
}
cEcmHandler::~cEcmHandler()
if(cwIndex!=cwindex) {
PRINTF(L_CORE_PIDS,"%s: shifting cwIndex from %d to %d",id,cwIndex,cwindex);
free(id);
- id=bprintf("%d.%d",cardNum,cwindex);
+ id=bprintf("%s.%d",devId,cwindex);
dataMutex.Lock();
trigger=true;
cwIndex=cwindex;
if(ecmPri->ecm!=ecm) {
StopEcm();
ecm=ecmPri->ecm;
- filter->Start(ecm->ecm_pid,ecm->ecm_table,0xfe,0,false);
+ filter->Start(ecm->ecm_pid,ecm->ecm_table,0xfe);
cam->LogEcmStatus(ecm,true);
}
else {
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);
return JumpEcm();
}
- sys->DoLog(dolog!=0); sys->CardNum(cardNum);
+ sys->DoLog(dolog!=0);
+ sys->SetOwner(cam);
failed.SetMaxFail(sys->MaxEcmTry());
if(dolog) PRINTF(L_CORE_ECM,"%s: try system %s (%04x) id %04x with ecm %x%s (pri=%d)",
while((n=ecms.First())) {
ecms.Del(n,false);
n->SetSource(filterSid,filterSource,filterTransponder);
+ n->SetDvb(cam->Adapter(),cam->Frontend());
n->AddCaDescr(&buff[index],buff[index+1]+2);
overrides.UpdateEcm(n,dolog);
LBSTARTF(L_CORE_ECM);
PRINTF(L_CORE_ECMPROC,"%s: ecmPri list end",id);
}
-// -- cCam ---------------------------------------------------------------
+// --- cChannelCaids -----------------------------------------------------------
+
+#ifndef SASC
+
+class cChannelCaids : public cSimpleItem {
+private:
+ int prg, source, transponder;
+ int numcaids;
+ caid_t caids[MAX_CI_SLOT_CAIDS+1];
+public:
+ cChannelCaids(cChannel *channel);
+ bool IsChannel(cChannel *channel);
+ void Sort(void);
+ void Del(caid_t caid);
+ bool HasCaid(caid_t caid);
+ bool Same(cChannelCaids *ch, bool full);
+ void HistAdd(unsigned short *hist);
+ void Dump(const char *devId);
+ const caid_t *Caids(void) { caids[numcaids]=0; return caids; }
+ int NumCaids(void) { return numcaids; }
+ int Source(void) const { return source; }
+ int Transponder(void) const { return transponder; }
+ };
+
+cChannelCaids::cChannelCaids(cChannel *channel)
+{
+ prg=channel->Sid(); source=channel->Source(); transponder=channel->Transponder();
+ numcaids=0;
+ for(const caid_t *ids=channel->Caids(); *ids; ids++)
+ if(numcaids<MAX_CI_SLOT_CAIDS) caids[numcaids++]=*ids;
+ Sort();
+}
+
+bool cChannelCaids::IsChannel(cChannel *channel)
+{
+ return prg==channel->Sid() && source==channel->Source() && transponder==channel->Transponder();
+}
+
+void cChannelCaids::Sort(void)
+{
+ caid_t tmp[MAX_CI_SLOT_CAIDS];
+ int c=0xFFFF;
+ for(int i=0; i<numcaids; i++) {
+ int d=0;
+ for(int j=0; j<numcaids; j++) if(caids[j]>d && caids[j]<c) d=caids[j];
+ tmp[i]=d; c=d;
+ }
+ memcpy(caids,tmp,sizeof(caids));
+}
+
+void cChannelCaids::Del(caid_t caid)
+{
+ for(int i=0; i<numcaids; i++)
+ if(caids[i]==caid) {
+ numcaids--; caids[i]=caids[numcaids];
+ if(numcaids>0) Sort();
+ caids[numcaids]=0;
+ break;
+ }
+}
+
+bool cChannelCaids::HasCaid(caid_t caid)
+{
+ for(int i=0; i<numcaids; i++) if(caids[i]==caid) return true;
+ return false;
+}
+
+bool cChannelCaids::Same(cChannelCaids *ch, bool full)
+{
+ if(full && (source!=ch->source || transponder!=ch->transponder)) return false;
+ if(numcaids!=ch->numcaids) return false;
+ return memcmp(caids,ch->caids,numcaids*sizeof(caid_t))==0;
+}
+
+void cChannelCaids::HistAdd(unsigned short *hist)
+{
+ for(int i=numcaids-1; i>=0; i--) hist[caids[i]]++;
+}
+
+void cChannelCaids::Dump(const char *devId)
+{
+ LBSTART(L_CORE_CAIDS);
+ LBPUT("%s: channel %d/%x/%x",devId,prg,source,transponder);
+ for(const caid_t *ids=Caids(); *ids; ids++) LBPUT(" %04x",*ids);
+ LBEND();
+}
+
+// --- cChannelList ------------------------------------------------------------
+
+class cChannelList : public cSimpleList<cChannelCaids> {
+private:
+ const char *devId;
+public:
+ cChannelList(const char *DevId);
+ void Unique(bool full);
+ void CheckIgnore(void);
+ int Histo(void);
+ void Purge(int caid, bool fullch);
+ };
+
+cChannelList::cChannelList(const char *DevId)
+{
+ devId=DevId;
+}
+
+void cChannelList::CheckIgnore(void)
+{
+ char *cache=MALLOC(char,0x10000);
+ if(!cache) return;
+ memset(cache,0,sizeof(char)*0x10000);
+ int cTotal=0, cHits=0;
+ for(cChannelCaids *ch=First(); ch; ch=Next(ch)) {
+ const caid_t *ids=ch->Caids();
+ while(*ids) {
+ int pri=0;
+ if(overrides.Ignore(ch->Source(),ch->Transponder(),*ids))
+ ch->Del(*ids);
+ else {
+ char c=cache[*ids];
+ if(c==0) cache[*ids]=c=(cSystems::FindIdentBySysId(*ids,false,pri) ? 1 : -1);
+ else cHits++;
+ cTotal++;
+ if(c<0) {
+ for(cChannelCaids *ch2=Next(ch); ch2; ch2=Next(ch2)) ch2->Del(*ids);
+ ch->Del(*ids);
+ }
+ else ids++;
+ }
+ }
+ }
+ free(cache);
+ PRINTF(L_CORE_CAIDS,"%s: after check",devId);
+ for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId);
+ PRINTF(L_CORE_CAIDS,"%s: check cache usage: %d requests, %d hits, %d%% hits",devId,cTotal,cHits,(cTotal>0)?(cHits*100/cTotal):0);
+}
+
+void cChannelList::Unique(bool full)
+{
+ for(cChannelCaids *ch1=First(); ch1; ch1=Next(ch1)) {
+ for(cChannelCaids *ch2=Next(ch1); ch2;) {
+ if(ch1->Same(ch2,full) || ch2->NumCaids()<1) {
+ cChannelCaids *t=Next(ch2);
+ Del(ch2);
+ ch2=t;
+ }
+ else ch2=Next(ch2);
+ }
+ }
+ if(Count()==1 && First() && First()->NumCaids()<1) Del(First());
+ PRINTF(L_CORE_CAIDS,"%s: after unique (%d)",devId,full);
+ for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId);
+}
+
+int cChannelList::Histo(void)
+{
+ int h=-1;
+ unsigned short *hist=MALLOC(unsigned short,0x10000);
+ if(hist) {
+ memset(hist,0,sizeof(unsigned short)*0x10000);
+ for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->HistAdd(hist);
+ int c=0;
+ for(int i=0; i<0x10000; i++)
+ if(hist[i]>c) { h=i; c=hist[i]; }
+ free(hist);
+ }
+ else PRINTF(L_GEN_ERROR,"malloc failed in cChannelList::Histo");
+ return h;
+}
+
+void cChannelList::Purge(int caid, bool fullch)
+{
+ for(cChannelCaids *ch=First(); ch;) {
+ if(!fullch) ch->Del(caid);
+ if(ch->NumCaids()<=0 || (fullch && ch->HasCaid(caid))) {
+ cChannelCaids *t=Next(ch);
+ Del(ch);
+ ch=t;
+ }
+ else ch=Next(ch);
+ }
+ if(Count()>0) {
+ PRINTF(L_CORE_CAIDS,"%s: still left",devId);
+ for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId);
+ }
+}
+
+// -- cCiFrame -----------------------------------------------------------------
+
+#define LEN_OFF 2
+
+cCiFrame::cCiFrame(void)
+{
+ rb=0; mem=0; len=alen=glen=0;
+}
+
+cCiFrame::~cCiFrame()
+{
+ free(mem);
+}
+
+unsigned char *cCiFrame::GetBuff(int l)
+{
+ if(!mem || l>alen) {
+ free(mem); mem=0; alen=0;
+ mem=MALLOC(unsigned char,l+LEN_OFF);
+ if(mem) alen=l;
+ }
+ len=l;
+ if(!mem) {
+ PRINTF(L_GEN_DEBUG,"internal: ci-frame alloc failed");
+ return 0;
+ }
+ return mem+LEN_OFF;
+}
+
+void cCiFrame::Put(void)
+{
+ if(rb && mem) {
+ *((short *)mem)=len;
+ rb->Put(mem,len+LEN_OFF);
+ }
+}
+
+unsigned char *cCiFrame::Get(int &l)
+{
+ if(rb) {
+ int c;
+ unsigned char *data=rb->Get(c);
+ if(data) {
+ if(c>LEN_OFF) {
+ int s=*((short *)data);
+ if(c>=s+LEN_OFF) {
+ l=glen=s;
+ return data+LEN_OFF;
+ }
+ }
+ LDUMP(L_GEN_DEBUG,data,c,"internal: ci rb frame sync got=%d avail=%d -",c,rb->Available());
+ rb->Clear();
+ }
+ }
+ return 0;
+}
+
+int cCiFrame::Avail(void)
+{
+ return rb ? rb->Available() : 0;
+}
+
+void cCiFrame::Del(void)
+{
+ if(rb && glen) {
+ rb->Del(glen+LEN_OFF);
+ glen=0;
+ }
+}
+
+// -- cScCamSlot ---------------------------------------------------------------
+
+#define TDPU_SIZE_INDICATOR 0x80
+
+#define CAID_TIME 300000 // time between caid scans
+#define TRIGGER_TIME 10000 // min. time between caid scan trigger
+#define SLOT_CAID_CHECK 10000
+#define SLOT_RESET_TIME 600
+
+class cScCamSlot : public cCamSlot {
+private:
+ cCam *cam;
+ unsigned short caids[MAX_CI_SLOT_CAIDS+1];
+ int slot, version;
+ const char *devId;
+ cTimeMs checkTimer;
+ bool reset, doReply;
+ cTimeMs resetTimer;
+ eModuleStatus lastStatus;
+ cRingBufferLinear rb;
+ cCiFrame frame;
+ //
+ int GetLength(const unsigned char * &data);
+ int LengthSize(int n);
+ void SetSize(int n, unsigned char * &p);
+ void CaInfo(int tcid, int cid);
+ bool Check(void);
+public:
+ cScCamSlot(cCam *Cam, const char *DevId, int Slot);
+ void Process(const unsigned char *data, int len);
+ eModuleStatus Status(void);
+ bool Reset(bool log=true);
+ cCiFrame *Frame(void) { return &frame; }
+ };
+
+cScCamSlot::cScCamSlot(cCam *Cam, const char *DevId, int Slot)
+:cCamSlot(Cam)
+,checkTimer(-SLOT_CAID_CHECK-1000)
+,rb(KILOBYTE(4),5+LEN_OFF,false,"SC-CI slot answer")
+{
+ cam=Cam; devId=DevId; slot=Slot;
+ version=0; caids[0]=0; doReply=false; lastStatus=msReset;
+ frame.SetRb(&rb);
+ Reset(false);
+}
+
+eModuleStatus cScCamSlot::Status(void)
+{
+ eModuleStatus status;
+ if(reset) {
+ status=msReset;
+ if(resetTimer.TimedOut()) reset=false;
+ }
+ else if(caids[0]) status=msReady;
+ else {
+ status=msPresent; //msNone;
+ Check();
+ }
+ if(status!=lastStatus) {
+ static const char *stext[] = { "none","reset","present","ready" };
+ PRINTF(L_CORE_CI,"%s.%d: status '%s'",devId,slot,stext[status]);
+ lastStatus=status;
+ }
+ return status;
+}
+
+bool cScCamSlot::Reset(bool log)
+{
+ reset=true; resetTimer.Set(SLOT_RESET_TIME);
+ rb.Clear();
+ if(log) PRINTF(L_CORE_CI,"%s.%d: reset",devId,slot);
+ return true;
+}
+
+bool cScCamSlot::Check(void)
+{
+ bool res=false;
+ bool dr=cam->IsSoftCSA(false) || ScSetup.ConcurrentFF>0;
+ if(dr!=doReply && !IsDecrypting()) {
+ PRINTF(L_CORE_CI,"%s.%d: doReply changed, reset triggered",devId,slot);
+ Reset(false);
+ doReply=dr;
+ }
+ if(checkTimer.TimedOut()) {
+ if(version!=cam->GetCaids(slot,0,0)) {
+ version=cam->GetCaids(slot,caids,MAX_CI_SLOT_CAIDS);
+ PRINTF(L_CORE_CI,"%s.%d: now using CAIDs version %d",devId,slot,version);
+ res=true;
+ }
+ checkTimer.Set(SLOT_CAID_CHECK);
+ }
+ return res;
+}
+
+int cScCamSlot::GetLength(const unsigned char * &data)
+{
+ int len=*data++;
+ if(len&TDPU_SIZE_INDICATOR) {
+ int i;
+ for(i=len&~TDPU_SIZE_INDICATOR, len=0; i>0; i--) len=(len<<8) + *data++;
+ }
+ return len;
+}
+
+int cScCamSlot::LengthSize(int n)
+{
+ return n<TDPU_SIZE_INDICATOR?1:3;
+}
+
+void cScCamSlot::SetSize(int n, unsigned char * &p)
+{
+ if(n<TDPU_SIZE_INDICATOR) *p++=n;
+ else { *p++=2|TDPU_SIZE_INDICATOR; *p++=n>>8; *p++=n&0xFF; }
+}
+
+void cScCamSlot::CaInfo(int tcid, int cid)
+{
+ int cn=0;
+ for(int i=0; caids[i]; i++) cn+=2;
+ int n=cn+8+LengthSize(cn);
+ unsigned char *p;
+ if(!(p=frame.GetBuff(n+1+LengthSize(n)))) return;
+ *p++=0xa0;
+ SetSize(n,p);
+ *p++=tcid;
+ *p++=0x90;
+ *p++=0x02; *p++=cid>>8; *p++=cid&0xff;
+ *p++=0x9f; *p++=0x80; *p++=0x31; // AOT_CA_INFO
+ SetSize(cn,p);
+ for(int i=0; caids[i]; i++) { *p++=caids[i]>>8; *p++=caids[i]&0xff; }
+ frame.Put();
+ PRINTF(L_CORE_CI,"%s.%d sending CA info",devId,slot);
+}
+
+void cScCamSlot::Process(const unsigned char *data, int len)
+{
+ const unsigned char *save=data;
+ data+=3;
+ int dlen=GetLength(data);
+ if(dlen>len-(data-save)) {
+ PRINTF(L_CORE_CI,"%s.%d TDPU length exceeds data length",devId,slot);
+ dlen=len-(data-save);
+ }
+ int tcid=data[0];
+
+ if(Check()) CaInfo(tcid,0x01);
+
+ if(dlen<8 || data[1]!=0x90) return;
+ int cid=(data[3]<<8)+data[4];
+ int tag=(data[5]<<16)+(data[6]<<8)+data[7];
+ data+=8;
+ dlen=GetLength(data);
+ if(dlen>len-(data-save)) {
+ PRINTF(L_CORE_CI,"%s.%d tag length exceeds data length",devId,slot);
+ dlen=len-(data-save);
+ }
+ switch(tag) {
+ case 0x9f8030: // AOT_CA_INFO_ENQ
+ CaInfo(tcid,cid);
+ break;
+
+ case 0x9f8032: // AOT_CA_PMT
+ if(dlen>=6) {
+ int ca_lm=data[0];
+ int ci_cmd=-1;
+ cPrg *prg=new cPrg((data[1]<<8)+data[2],ca_lm==5);
+ int ilen=(data[4]<<8)+data[5];
+ LBSTARTF(L_CORE_CI);
+ 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);
+ data+=6; dlen-=6;
+ LBPUT("/%x",dlen);
+ if(ilen>0 && dlen>=ilen) {
+ ci_cmd=data[0];
+ if(ilen>1)
+ prg->caDescr.Set(&data[1],ilen-1);
+ LBPUT(" ci_cmd(G)=%02x",ci_cmd);
+ }
+ data+=ilen; dlen-=ilen;
+ while(dlen>=5) {
+ cPrgPid *pid=new cPrgPid(data[0],(data[1]<<8)+data[2]);
+ prg->pids.Add(pid);
+ ilen=(data[3]<<8)+data[4];
+ LBPUT(" pid=%d,%x len=%x",data[0],(data[1]<<8)+data[2],ilen);
+ data+=5; dlen-=5;
+ LBPUT("/%x",dlen);
+ if(ilen>0 && dlen>=ilen) {
+ ci_cmd=data[0];
+ if(ilen>1) {
+ pid->caDescr.Set(&data[1],ilen-1);
+ prg->SetPidCaDescr(true);
+ }
+ LBPUT(" ci_cmd(S)=%x",ci_cmd);
+ }
+ data+=ilen; dlen-=ilen;
+ }
+ LBEND();
+ PRINTF(L_CORE_CI,"%s.%d got CA pmt ciCmd=%d caLm=%d",devId,slot,ci_cmd,ca_lm);
+ if(doReply && (ci_cmd==0x03 || (ci_cmd==0x01 && ca_lm==0x03))) {
+ unsigned char *b;
+ if((b=frame.GetBuff(4+11))) {
+ b[0]=0xa0; b[2]=tcid;
+ b[3]=0x90;
+ b[4]=0x02; b[5]=cid<<8; b[6]=cid&0xff;
+ b[7]=0x9f; b[8]=0x80; b[9]=0x33; // AOT_CA_PMT_REPLY
+ b[11]=prg->sid<<8;
+ b[12]=prg->sid&0xff;
+ b[13]=0x00;
+ b[14]=0x81; // CA_ENABLE
+ b[10]=4; b[1]=4+9;
+ frame.Put();
+ PRINTF(L_CORE_CI,"%s.%d answer to query",devId,slot);
+ }
+ }
+ if(prg->sid!=0) {
+ if(ci_cmd==0x04) {
+ PRINTF(L_CORE_CI,"%s.%d stop decrypt",devId,slot);
+ cam->Stop();
+ }
+ if(ci_cmd==0x01 || (ci_cmd==-1 && (ca_lm==0x04 || ca_lm==0x05))) {
+ PRINTF(L_CORE_CI,"%s.%d set CAM decrypt (prg %d)",devId,slot,prg->sid);
+ cam->AddPrg(prg);
+ }
+ }
+ delete prg;
+ }
+ break;
+ }
+}
+
+#endif //SASC
+
+// -- cCams --------------------------------------------------------------------
+
+class cCams : public cSimpleList<cCam> {
+public:
+ cMutex listMutex;
+ //
+ void Register(cCam *cam);
+ void Unregister(cCam *cam);
+ };
+
+static cCams cams;
+
+void cCams::Register(cCam *cam)
+{
+ cMutexLock lock(&listMutex);
+ Add(cam);
+}
-cCam::cCam(cScDevice *dev, int CardNum)
+void cCams::Unregister(cCam *cam)
{
- device=dev; cardNum=CardNum;
+ cMutexLock lock(&listMutex);
+ Del(cam,false);
+}
+
+// -- cGlobal ------------------------------------------------------------------
+
+char *cGlobal::CurrKeyStr(int camindex, int num, const char **id)
+{
+ cMutexLock lock(&cams.listMutex);
+ char *str=0;
+ cCam *c;
+ for(c=cams.First(); c && camindex>0; c=cams.Next(c), camindex--);
+ if(c) {
+ str=c->CurrentKeyStr(num,id);
+ if(!str && num==0) str=strdup(tr("(none)"));
+ }
+ return str;
+}
+
+void cGlobal::HouseKeeping(void)
+{
+ cMutexLock lock(&cams.listMutex);
+ for(cCam *c=cams.First(); c; c=cams.Next(c)) c->HouseKeeping();
+}
+
+bool cGlobal::Active(bool log)
+{
+ cMutexLock lock(&cams.listMutex);
+ for(cCam *c=cams.First(); c; c=cams.Next(c)) if(c->Active(log)) return true;
+ return false;
+}
+
+void cGlobal::CaidsChanged(void)
+{
+ cMutexLock lock(&cams.listMutex);
+ PRINTF(L_CORE_CAIDS,"caid list rebuild triggered");
+ for(cCam *c=cams.First(); c; c=cams.Next(c)) c->CaidsChanged();
+}
+
+// -- cCam ---------------------------------------------------------------
+
+struct TPDU {
+ unsigned char slot;
+ unsigned char tcid;
+ unsigned char tag;
+ unsigned char len;
+ unsigned char data[1];
+ };
+
+cCam::cCam(cDevice *Device, int Adapter, int Frontend, const char *DevId, int Cafd, bool SoftCSA, bool FullTS)
+{
+ device=Device; adapter=Adapter; frontend=Frontend; devId=DevId; cafd=Cafd;
+ softcsa=SoftCSA; fullts=FullTS;
+ tcid=0; rebuildcaids=false;
+ memset(version,0,sizeof(version));
+ memset(slots,0,sizeof(slots));
+ SetDescription("SC-CI adapter on device %s",devId);
+ rb=new cRingBufferLinear(KILOBYTE(8),6+LEN_OFF,false,"SC-CI adapter read");
+ if(rb) {
+ rb->SetTimeouts(0,CAM_READ_TIMEOUT);
+ frame.SetRb(rb);
+ BuildCaids(true);
+ slots[0]=new cScCamSlot(this,devId,0);
+ Start();
+ }
+ else PRINTF(L_GEN_ERROR,"failed to create ringbuffer for SC-CI adapter %s.",devId);
+
+ decsa=new cDeCSA(devId);
+
source=transponder=-1; liveVpid=liveApid=0; logger=0; hookman=0;
memset(lastCW,0,sizeof(lastCW));
memset(indexMap,0,sizeof(indexMap));
memset(splitSid,0,sizeof(splitSid));
+ cams.Register(this);
}
cCam::~cCam()
{
+ cams.Unregister(this);
handlerList.Clear();
delete hookman;
delete logger;
+ Cancel(3);
+ ciMutex.Lock();
+ delete rb; rb=0;
+ ciMutex.Unlock();
+ delete decsa; decsa=0;
+}
+
+bool cCam::OwnSlot(const cCamSlot *slot) const
+{
+ if(slots[0]==slot) return true;
+ //for(int i=0; i<MAX_CI_SLOTS; i++) if(slots[i]==slot) return true;
+ return false;
+}
+
+int cCam::GetCaids(int slot, unsigned short *Caids, int max)
+{
+ BuildCaids(false);
+ cMutexLock lock(&ciMutex);
+ if(Caids) {
+ int i;
+ for(i=0; i<MAX_CI_SLOT_CAIDS && i<max && caids[i]; i++) Caids[i]=caids[slot][i];
+ Caids[i]=0;
+ }
+ return version[slot];
+}
+
+void cCam::CaidsChanged(void)
+{
+ rebuildcaids=true;
+}
+
+void cCam::BuildCaids(bool force)
+{
+ if(caidTimer.TimedOut() || force || (rebuildcaids && triggerTimer.TimedOut())) {
+ PRINTF(L_CORE_CAIDS,"%s: building caid lists",devId);
+ cChannelList list(devId);
+ Channels.Lock(false);
+ for(cChannel *channel=Channels.First(); channel; channel=Channels.Next(channel)) {
+ if(!channel->GroupSep() && channel->Ca()>=CA_ENCRYPTED_MIN && device->ProvidesTransponder(channel)) {
+ cChannelCaids *ch=new cChannelCaids(channel);
+ if(ch) list.Add(ch);
+ }
+ }
+ Channels.Unlock();
+ list.Unique(true);
+ list.CheckIgnore();
+ list.Unique(false);
+
+ int n=0, h;
+ caid_t c[MAX_CI_SLOT_CAIDS+1];
+ memset(c,0,sizeof(c));
+ do {
+ if((h=list.Histo())<0) break;
+ c[n++]=h;
+ LBSTART(L_CORE_CAIDS);
+ LBPUT("%s: added %04x caids now",devId,h); for(int i=0; i<n; i++) LBPUT(" %04x",c[i]);
+ LBEND();
+ list.Purge(h,false);
+ } while(n<MAX_CI_SLOT_CAIDS && list.Count()>0);
+ c[n]=0;
+ if(n==0) PRINTF(L_CORE_CI,"%s: no active CAIDs",devId);
+ else if(list.Count()>0) PRINTF(L_GEN_ERROR,"too many CAIDs. You should ignore some CAIDs.");
+
+ ciMutex.Lock();
+ if((version[0]==0 && c[0]!=0) || memcmp(caids[0],c,sizeof(caids[0]))) {
+ memcpy(caids[0],c,sizeof(caids[0]));
+ version[0]++;
+ if(version[0]>0) {
+ LBSTART(L_CORE_CI);
+ LBPUT("card %s, slot %d (v=%2d) caids:",devId,0,version[0]);
+ for(int i=0; caids[0][i]; i++) LBPUT(" %04x",caids[0][i]);
+ LBEND();
+ }
+ }
+ ciMutex.Unlock();
+
+ caidTimer.Set(CAID_TIME);
+ triggerTimer.Set(TRIGGER_TIME);
+ rebuildcaids=false;
+ }
+}
+
+int cCam::Read(unsigned char *Buffer, int MaxLength)
+{
+ cMutexLock lock(&ciMutex);
+ if(rb && Buffer && MaxLength>0) {
+ int s;
+ unsigned char *data=frame.Get(s);
+ if(data) {
+ if(s<=MaxLength) memcpy(Buffer,data,s);
+ else PRINTF(L_GEN_DEBUG,"internal: sc-ci %s rb frame size exceeded %d",devId,s);
+ frame.Del();
+ if(Buffer[2]!=0x80 || LOG(L_CORE_CIFULL)) {
+ LDUMP(L_CORE_CI,Buffer,s,"%s.%d <-",devId,Buffer[0]);
+ readTimer.Set();
+ }
+ return s;
+ }
+ }
+ else cCondWait::SleepMs(CAM_READ_TIMEOUT);
+ if(LOG(L_CORE_CIFULL) && readTimer.Elapsed()>2000) {
+ PRINTF(L_CORE_CIFULL,"%s: read heartbeat",devId);
+ readTimer.Set();
+ }
+ return 0;
+}
+
+#define TPDU(data,slot) do { unsigned char *_d=(data); _d[0]=(slot); _d[1]=tcid; } while(0)
+#define TAG(data,tag,len) do { unsigned char *_d=(data); _d[0]=(tag); _d[1]=(len); } while(0)
+#define SB_TAG(data,sb) do { unsigned char *_d=(data); _d[0]=0x80; _d[1]=0x02; _d[2]=tcid; _d[3]=(sb); } while(0)
+
+void cCam::Write(const unsigned char *buff, int len)
+{
+ cMutexLock lock(&ciMutex);
+ if(buff && len>=5) {
+ struct TPDU *tpdu=(struct TPDU *)buff;
+ int slot=tpdu->slot;
+ cCiFrame *slotframe=slots[slot]->Frame();
+ if(buff[2]!=0xA0 || buff[3]>0x01 || LOG(L_CORE_CIFULL))
+ LDUMP(L_CORE_CI,buff,len,"%s.%d ->",devId,slot);
+ if(slots[slot]) {
+ switch(tpdu->tag) {
+ case 0x81: // T_RCV
+ {
+ int s;
+ unsigned char *d=slotframe->Get(s);
+ if(d) {
+ unsigned char *b;
+ if((b=frame.GetBuff(s+6))) {
+ TPDU(b,slot);
+ memcpy(b+2,d,s);
+ slotframe->Del(); // delete from rb before Avail()
+ SB_TAG(b+2+s,slotframe->Avail()>0 ? 0x80:0x00);
+ frame.Put();
+ }
+ else slotframe->Del();
+ }
+ break;
+ }
+ case 0x82: // T_CREATE_TC
+ {
+ tcid=tpdu->data[0];
+ unsigned char *b;
+ static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 };
+ if((b=slotframe->GetBuff(sizeof(reqCAS)))) {
+ memcpy(b,reqCAS,sizeof(reqCAS));
+ b[2]=tcid;
+ slotframe->Put();
+ }
+ if((b=frame.GetBuff(9))) {
+ TPDU(b,slot);
+ TAG(&b[2],0x83,0x01); b[4]=tcid;
+ SB_TAG(&b[5],slotframe->Avail()>0 ? 0x80:0x00);
+ frame.Put();
+ }
+ break;
+ }
+ case 0xA0: // T_DATA_LAST
+ {
+ slots[slot]->Process(buff,len);
+ unsigned char *b;
+ if((b=frame.GetBuff(6))) {
+ TPDU(b,slot);
+ SB_TAG(&b[2],slotframe->Avail()>0 ? 0x80:0x00);
+ frame.Put();
+ }
+ break;
+ }
+ }
+ }
+ }
+ else PRINTF(L_CORE_CIFULL,"%s: short write (buff=%d len=%d)",devId,buff!=0,len);
+}
+
+bool cCam::Reset(int Slot)
+{
+ cMutexLock lock(&ciMutex);
+ PRINTF(L_CORE_CI,"%s: reset of slot %d requested",devId,Slot);
+ return slots[Slot] ? slots[Slot]->Reset():false;
+}
+
+eModuleStatus cCam::ModuleStatus(int Slot)
+{
+ cMutexLock lock(&ciMutex);
+ bool enable=ScSetup.CapCheck(device->CardIndex());
+ if(!enable) Stop();
+ return (enable && slots[Slot]) ? slots[Slot]->Status():msNone;
+}
+
+bool cCam::Assign(cDevice *Device, bool Query)
+{
+ return Device ? (Device==device) : true;
}
bool cCam::IsSoftCSA(bool live)
{
- return device->SoftCSA(live);
+ return softcsa && (!fullts || !live);
}
void cCam::Tune(const cChannel *channel)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
if(source!=channel->Source() || transponder!=channel->Transponder()) {
source=channel->Source(); transponder=channel->Transponder();
- PRINTF(L_CORE_PIDS,"%d: now tuned to source %x(%s) transponder %x",cardNum,source,*cSource::ToString(source),transponder);
+ PRINTF(L_CORE_PIDS,"%s: now tuned to source %x(%s) transponder %x",devId,source,*cSource::ToString(source),transponder);
Stop();
}
- else PRINTF(L_CORE_PIDS,"%d: tune to same source/transponder",cardNum);
+ else PRINTF(L_CORE_PIDS,"%s: tune to same source/transponder",devId);
}
void cCam::PostTune(void)
void cCam::SetPid(int type, int pid, bool on)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
int oldA=liveApid, oldV=liveVpid;
if(type==1) liveVpid=on ? pid:0;
else if(type==0) liveApid=on ? pid:0;
else if(liveVpid==pid && on) liveVpid=0;
else if(liveApid==pid && on) liveApid=0;
if(oldA!=liveApid || oldV!=liveVpid)
- PRINTF(L_CORE_PIDS,"%d: livepids video=%04x audio=%04x",cardNum,liveVpid,liveApid);
+ PRINTF(L_CORE_PIDS,"%s: livepids video=%04x audio=%04x",devId,liveVpid,liveApid);
}
void cCam::Stop(void)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler))
handler->Stop();
if(logger) logger->Down();
void cCam::AddPrg(cPrg *prg)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
bool islive=false;
for(cPrgPid *pid=prg->pids.First(); pid; pid=prg->pids.Next(pid))
if(pid->pid==liveVpid || pid->pid==liveApid) {
}
bool needZero=!IsSoftCSA(islive) && (islive || !ScSetup.ConcurrentFF);
bool noshift=IsSoftCSA(true) || (prg->IsUpdate() && prg->pids.Count()==0);
- PRINTF(L_CORE_PIDS,"%d: %s SID %d (zero=%d noshift=%d)",cardNum,prg->IsUpdate()?"update":"add",prg->sid,needZero,noshift);
+ PRINTF(L_CORE_PIDS,"%s: %s SID %d (zero=%d noshift=%d)",devId,prg->IsUpdate()?"update":"add",prg->sid,needZero,noshift);
if(prg->pids.Count()>0) {
LBSTART(L_CORE_PIDS);
- LBPUT("%d: pids",cardNum);
+ LBPUT("%s: pids",devId);
for(cPrgPid *pid=prg->pids.First(); pid; pid=prg->pids.Next(pid))
LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid);
LBEND();
if(!isSplit) {
cEcmHandler *handler=GetHandler(prg->sid,needZero,noshift);
if(handler) {
- PRINTF(L_CORE_PIDS,"%d: found handler for SID %d (%s idle=%d idx=%d)",cardNum,prg->sid,handler->Id(),handler->IsIdle(),handler->CwIndex());
+ PRINTF(L_CORE_PIDS,"%s: found handler for SID %d (%s idle=%d idx=%d)",devId,prg->sid,handler->Id(),handler->IsIdle(),handler->CwIndex());
prg->source=source;
prg->transponder=transponder;
handler->SetPrg(prg);
}
}
else {
- PRINTF(L_CORE_PIDS,"%d: SID %d is handled as splitted",cardNum,prg->sid);
+ PRINTF(L_CORE_PIDS,"%s: SID %d is handled as splitted",devId,prg->sid);
// first update the splitSid list
if(prg->pids.Count()==0) { // delete
for(int i=0; splitSid[i]; i++)
memmove(&splitSid[i],&splitSid[i+1],sizeof(splitSid[0])*(MAX_SPLIT_SID-i));
break;
}
- PRINTF(L_CORE_PIDS,"%d: deleted from list",cardNum);
+ PRINTF(L_CORE_PIDS,"%s: deleted from list",devId);
}
else { // add
bool has=false;
if(i<MAX_SPLIT_SID) {
splitSid[i]=prg->sid;
splitSid[i+1]=0;
- PRINTF(L_CORE_PIDS,"%d: added to list",cardNum);
+ PRINTF(L_CORE_PIDS,"%s: added to list",devId);
}
- else PRINTF(L_CORE_PIDS,"%d: split SID list overflow",cardNum);
+ else PRINTF(L_CORE_PIDS,"%s: split SID list overflow",devId);
}
}
LBSTART(L_CORE_PIDS);
- LBPUT("%d: split SID list now:",cardNum);
+ LBPUT("%s: split SID list now:",devId);
for(int i=0; i<=MAX_SPLIT_SID; i++) LBPUT(" %d",splitSid[i]);
LBEND();
// prepare an empty prg head
cPrgPid *first;
while((first=prg->pids.First())) {
LBSTARTF(L_CORE_PIDS);
- LBPUT("%d: group %d pids",cardNum,group);
+ LBPUT("%s: group %d pids",devId,group);
prg->pids.Del(first,false);
work.caDescr.Set(&first->caDescr);
first->caDescr.Clear();
// otherwise get the group-sid handler
if(!handler) handler=GetHandler(grsid,needZero,noshift);
if(handler) {
- PRINTF(L_CORE_PIDS,"%d: found handler for group-SID %d (%s idle=%d idx=%d)",cardNum,grsid,handler->Id(),handler->IsIdle(),handler->CwIndex());
+ PRINTF(L_CORE_PIDS,"%s: found handler for group-SID %d (%s idle=%d idx=%d)",devId,grsid,handler->Id(),handler->IsIdle(),handler->CwIndex());
work.sid=grsid;
handler->SetPrg(&work);
}
int gr=sid/SIDGRP_SHIFT;
sid%=SIDGRP_SHIFT;
if(sid==prg->sid && gr>=group) {
- PRINTF(L_CORE_PIDS,"%d: idle group handler %s idx=%d",cardNum,handler->Id(),handler->CwIndex());
+ PRINTF(L_CORE_PIDS,"%s: idle group handler %s idx=%d",devId,handler->Id(),handler->CwIndex());
work.sid=handler->Sid();
handler->SetPrg(&work);
}
bool cCam::HasPrg(int prg)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler))
if(!handler->IsIdle() && handler->Sid()==prg)
return true;
return false;
}
-char *cCam::CurrentKeyStr(int num)
+char *cCam::CurrentKeyStr(int num, const char **id)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
+ if(id) *id=devId;
cEcmHandler *handler;
for(handler=handlerList.First(); handler; handler=handlerList.Next(handler))
if(--num<0) return handler->CurrentKeyStr();
bool cCam::Active(bool log)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler))
if(!handler->IsIdle()) {
- if(log) PRINTF(L_GEN_INFO,"handler %s on card %d is not idle",handler->Id(),cardNum);
+ if(log) PRINTF(L_GEN_INFO,"handler %s on card %s is not idle",handler->Id(),devId);
return true;
}
return false;
void cCam::HouseKeeping(void)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
for(cEcmHandler *handler=handlerList.First(); handler;) {
cEcmHandler *next=handlerList.Next(handler);
if(handler->IsRemoveable()) RemHandler(handler);
void cCam::LogStartup(void)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
if(!logger && ScSetup.AutoUpdate) {
- logger=new cLogger(cardNum,IsSoftCSA(false));
+ logger=new cLogger(this,device,devId,IsSoftCSA(false));
LogStatsUp();
}
}
void cCam::LogEcmStatus(const cEcmInfo *ecm, bool on)
{
- cMutexLock lock(this);
+ cMutexLock lock(&camMutex);
if(on) LogStartup();
if(logger) logger->EcmStatus(ecm,on);
}
void cCam::AddHook(cLogHook *hook)
{
- cMutexLock lock(this);
- if(!hookman) hookman=new cHookManager(cardNum);
+ cMutexLock lock(&camMutex);
+ if(!hookman) hookman=new cHookManager(device,devId);
if(hookman) hookman->AddHook(hook);
}
ca_pid_t ca_pid;
ca_pid.pid=pid;
ca_pid.index=index;
- PRINTF(L_CORE_PIDS,"%d: descrambling pid %04x on index %x",cardNum,pid,index);
- if(!device->SetCaPid(&ca_pid))
+ PRINTF(L_CORE_PIDS,"%s: descrambling pid %04x on index %x",devId,pid,index);
+ if(!SetCaPid(&ca_pid))
if(index>0) {
PRINTF(L_GEN_ERROR,"CA_SET_PID failed (%s). Expect a black screen/bad recording. Do you use the patched DVB driver?",strerror(errno));
PRINTF(L_GEN_WARN,"Adjusting 'Concurrent FF streams' to NO");
memcpy(&last[0],&cw[0],8);
ca_descr.parity=0;
memcpy(ca_descr.cw,&cw[0],8);
- if(!device->SetCaDescr(&ca_descr,force))
+ if(!SetCaDescr(&ca_descr,force))
PRINTF(L_GEN_ERROR,"CA_SET_DESCR failed (%s). Expect a black screen.",strerror(errno));
}
memcpy(&last[8],&cw[8],8);
ca_descr.parity=1;
memcpy(ca_descr.cw,&cw[8],8);
- if(!device->SetCaDescr(&ca_descr,force))
+ if(!SetCaDescr(&ca_descr,force))
PRINTF(L_GEN_ERROR,"CA_SET_DESCR failed (%s). Expect a black screen.",strerror(errno));
}
}
}
+bool cCam::SetCaDescr(ca_descr_t *ca_descr, bool initial)
+{
+#ifndef SASC
+ if(!softcsa || (fullts && ca_descr->index==0)) {
+ cMutexLock lock(&cafdMutex);
+ return ioctl(cafd,CA_SET_DESCR,ca_descr)>=0;
+ }
+ else if(decsa) return decsa->SetDescr(ca_descr,initial);
+#endif // !SASC
+ return false;
+}
+
+bool cCam::SetCaPid(ca_pid_t *ca_pid)
+{
+#ifndef SASC
+ if(!softcsa || (fullts && ca_pid->index==0)) {
+ cMutexLock lock(&cafdMutex);
+ return ioctl(cafd,CA_SET_PID,ca_pid)>=0;
+ }
+ else if(decsa) return decsa->SetCaPid(ca_pid);
+#endif // !SASC
+ return false;
+}
+
+#ifndef SASC
+static unsigned int av7110_read(int fd, unsigned int addr)
+{
+ ca_pid_t arg;
+ arg.pid=addr;
+ ioctl(fd,CA_GET_MSG,&arg);
+ return arg.index;
+}
+#endif // !SASC
+
+#if 0
+static void av7110_write(int fd, unsigned int addr, unsigned int val)
+{
+ ca_pid_t arg;
+ arg.pid=addr;
+ arg.index=val;
+ ioctl(fd,CA_SEND_MSG,&arg);
+}
+#endif
+
void cCam::DumpAV7110(void)
{
- device->DumpAV7110();
+#ifndef SASC
+ if(LOG(L_CORE_AV7110)) {
+#define CODEBASE (0x2e000404+0x1ce00)
+ cMutexLock lock(&cafdMutex);
+ if(device->HasDecoder() && lastDump.Elapsed()>20000) {
+ lastDump.Set();
+ static unsigned int handles=0, hw_handles=0;
+ static const unsigned int code[] = {
+ 0xb5100040,0x4a095a12,0x48094282,0xd00b4b09,0x20000044,
+ 0x5b1c4294,0xd0033001,0x281cdbf8,0xe001f7fe,0xfd14bc10
+ };
+ static const unsigned int mask[] = {
+ 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+ 0xffffffff,0xffffffff,0xffffffff,0xfffff800,0xf800ffff
+ };
+ if(!handles) {
+ handles=1;
+ PRINTF(L_CORE_AV7110,"searching handle tables");
+ for(int i=0; i<0x2000; i+=4) {
+ int j;
+ for(j=0; j<20; j+=4) {
+ int r=av7110_read(cafd,CODEBASE+i+j);
+ if((r&mask[j/4])!=(code[j/4]&mask[j/4])) break;
+ }
+ if(j==20) {
+ handles=av7110_read(cafd,CODEBASE+i+44);
+ hw_handles=av7110_read(cafd,CODEBASE+i+52);
+ PRINTF(L_CORE_AV7110,"found handles=%08x hw_handles=%08x at 0x%08x",handles,hw_handles,CODEBASE+i);
+ if((handles>>16)!=0x2e08 || (hw_handles>>16)!=0x2e08) {
+ PRINTF(L_CORE_AV7110,"seems to be invalid");
+ }
+ break;
+ }
+ }
+ }
+
+ unsigned int hdl=0, hwhdl=0;
+ PRINTF(L_CORE_AV7110," : 64000080 64000400");
+ for(int i=0; i<=31; i++) {
+ unsigned int off80 =av7110_read(cafd,0x64000080+i*4);
+ unsigned int off400=av7110_read(cafd,0x64000400+i*8);
+ LBSTART(L_CORE_AV7110);
+ LBPUT("handle %2d: %08x %08x %s pid=%04x idx=%d",
+ i,off80,off400,off80&0x2000?"ACT":"---",off80&0x1fff,(off400&0x1e)>>1);
+ if(handles>1 && i<=27) {
+ if((i&1)==0) {
+ hdl=av7110_read(cafd,handles+i*2);
+ hwhdl=av7110_read(cafd,hw_handles+i*2);
+ }
+ unsigned int s=((~i)&1)<<4;
+ LBPUT(" | %02d hdl=%04x hwfilt=%04x",i,(hdl>>s)&0xffff,(hwhdl>>s)&0xffff);
+ }
+ LBEND();
+ }
+ }
+ }
+#endif // !SASC
}
int cCam::GetFreeIndex(void)
idlehandler=handler;
}
LBSTART(L_CORE_PIDS);
- LBPUT("%d: SID=%d zero=%d |",cardNum,sid,needZero);
+ LBPUT("%s: SID=%d zero=%d |",devId,sid,needZero);
if(sidhandler) LBPUT(" sid=%d/%d/%d",sidhandler->CwIndex(),sidhandler->Sid(),sidhandler->IsIdle());
else LBPUT(" sid=-/-/-");
if(zerohandler) LBPUT(" zero=%d/%d/%d",zerohandler->CwIndex(),zerohandler->Sid(),zerohandler->IsIdle());
if(sidhandler) {
if(needZero && sidhandler->CwIndex()!=0 && !noshift) {
if(!sidhandler->IsIdle())
- PRINTF(L_CORE_ECM,"%d: shifting cwindex on non-idle handler.",cardNum);
+ PRINTF(L_CORE_ECM,"%s: shifting cwindex on non-idle handler.",devId);
if(zerohandler) {
if(!zerohandler->IsIdle())
- PRINTF(L_CORE_ECM,"%d: shifting non-idle zero handler. This shouldn't happen!",cardNum);
+ PRINTF(L_CORE_ECM,"%s: shifting non-idle zero handler. This shouldn't happen!",devId);
zerohandler->ShiftCwIndex(sidhandler->CwIndex());
sidhandler->ShiftCwIndex(0);
}
indexMap[sidhandler->CwIndex()]=0;
sidhandler->ShiftCwIndex(0);
}
- else PRINTF(L_CORE_ECM,"%d: zero index not free.",cardNum);
+ else PRINTF(L_CORE_ECM,"%s: zero index not free.",devId);
}
if(!needZero && sidhandler->CwIndex()==0 && !noshift) {
if(!sidhandler->IsIdle())
- PRINTF(L_CORE_ECM,"%d: shifting cwindex on non-idle handler.",cardNum);
+ PRINTF(L_CORE_ECM,"%s: shifting cwindex on non-idle handler.",devId);
int idx=GetFreeIndex();
if(idx>=0) {
indexMap[idx]=1;
sidhandler->ShiftCwIndex(idx);
indexMap[0]=0;
}
- else PRINTF(L_CORE_ECM,"%d: no free cwindex. Can't free zero index.",cardNum);
+ else PRINTF(L_CORE_ECM,"%s: no free cwindex. Can't free zero index.",devId);
}
return sidhandler;
if(needZero && zerohandler) {
if(!zerohandler->IsIdle())
- PRINTF(L_CORE_ECM,"%d: changing SID on non-idle zero handler. This shouldn't happen!",cardNum);
+ PRINTF(L_CORE_ECM,"%s: changing SID on non-idle zero handler. This shouldn't happen!",devId);
return zerohandler;
}
indexMap[idlehandler->CwIndex()]=0;
idlehandler->ShiftCwIndex(0);
}
- else PRINTF(L_CORE_ECM,"%d: zero index not free. (2)",cardNum);
+ else PRINTF(L_CORE_ECM,"%s: zero index not free. (2)",devId);
}
if(!needZero && idlehandler->CwIndex()==0 && !noshift) {
int idx=GetFreeIndex();
idlehandler->ShiftCwIndex(idx);
indexMap[0]=0;
}
- else PRINTF(L_CORE_ECM,"%d: no free cwindex. Can't free zero index. (2)",cardNum);
+ else PRINTF(L_CORE_ECM,"%s: no free cwindex. Can't free zero index. (2)",devId);
}
if((needZero ^ (idlehandler->CwIndex()==0)))
- PRINTF(L_CORE_ECM,"%d: idlehandler index doesn't match needZero",cardNum);
+ PRINTF(L_CORE_ECM,"%s: idlehandler index doesn't match needZero",devId);
return idlehandler;
}
indexMap[0]=0;
if(idx<0) {
idx=0;
- PRINTF(L_CORE_ECM,"%d: can't respect !needZero for new handler",cardNum);
+ PRINTF(L_CORE_ECM,"%s: can't respect !needZero for new handler",devId);
}
}
if(idx<0) {
- PRINTF(L_CORE_ECM,"%d: no free cwindex",cardNum);
+ PRINTF(L_CORE_ECM,"%s: no free cwindex",devId);
return 0;
}
indexMap[idx]=1;
- idlehandler=new cEcmHandler(this,cardNum,idx);
+ idlehandler=new cEcmHandler(this,device,devId,idx);
handlerList.Add(idlehandler);
return idlehandler;
}
void cCam::RemHandler(cEcmHandler *handler)
{
int idx=handler->CwIndex();
- PRINTF(L_CORE_PIDS,"%d: removing %s on cw index %d",cardNum,handler->Id(),idx);
+ PRINTF(L_CORE_PIDS,"%s: removing %s on cw index %d",devId,handler->Id(),idx);
handlerList.Del(handler);
indexMap[idx]=0;
}
+
+// -- cDeCSA -------------------------------------------------------------------
+
+#define MAX_STALL_MS 70
+
+#define MAX_REL_WAIT 100 // time to wait if key in used on set
+#define MAX_KEY_WAIT 500 // time to wait if key not ready on change
+
+#define FL_EVEN_GOOD 1
+#define FL_ODD_GOOD 2
+#define FL_ACTIVITY 4
+
+
+cDeCSA::cDeCSA(const char *DevId)
+:stall(MAX_STALL_MS)
+{
+ devId=DevId;
+ cs=get_suggested_cluster_size();
+ PRINTF(L_CORE_CSA,"%s: clustersize=%d rangesize=%d",devId,cs,cs*2+5);
+ range=MALLOC(unsigned char *,(cs*2+5));
+ memset(keys,0,sizeof(keys));
+ memset(pidmap,0,sizeof(pidmap));
+ ResetState();
+}
+
+cDeCSA::~cDeCSA()
+{
+ for(int i=0; i<MAX_CSA_IDX; i++)
+ if(keys[i]) free_key_struct(keys[i]);
+ free(range);
+}
+
+void cDeCSA::ResetState(void)
+{
+ PRINTF(L_CORE_CSA,"%s: reset state",devId);
+ memset(even_odd,0,sizeof(even_odd));
+ memset(flags,0,sizeof(flags));
+ lastData=0;
+}
+
+void cDeCSA::SetActive(bool on)
+{
+ if(!on && active) ResetState();
+ active=on;
+ PRINTF(L_CORE_CSA,"%s: set active %s",devId,active?"on":"off");
+}
+
+bool cDeCSA::GetKeyStruct(int idx)
+{
+ if(!keys[idx]) keys[idx]=get_key_struct();
+ return keys[idx]!=0;
+}
+
+bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
+{
+ cMutexLock lock(&mutex);
+ int idx=ca_descr->index;
+ if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) {
+ if(!initial && active && ca_descr->parity==(even_odd[idx]&0x40)>>6) {
+ if(flags[idx] & (ca_descr->parity?FL_ODD_GOOD:FL_EVEN_GOOD)) {
+ PRINTF(L_CORE_CSA,"%s.%d: %s key in use (%d ms)",devId,idx,ca_descr->parity?"odd":"even",MAX_REL_WAIT);
+ if(wait.TimedWait(mutex,MAX_REL_WAIT)) PRINTF(L_CORE_CSA,"%s.%d: successfully waited for release",devId,idx);
+ else PRINTF(L_CORE_CSA,"%s.%d: timed out. setting anyways",devId,idx);
+ }
+ else PRINTF(L_CORE_CSA,"%s.%d: late key set...",devId,idx);
+ }
+ LDUMP(L_CORE_CSA,ca_descr->cw,8,"%s.%d: %4s key set",devId,idx,ca_descr->parity?"odd":"even");
+ if(ca_descr->parity==0) {
+ set_even_control_word(keys[idx],ca_descr->cw);
+ if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_EVEN_GOOD|FL_ACTIVITY;
+ else PRINTF(L_CORE_CSA,"%s.%d: zero even CW",devId,idx);
+ wait.Broadcast();
+ }
+ else {
+ set_odd_control_word(keys[idx],ca_descr->cw);
+ if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_ODD_GOOD|FL_ACTIVITY;
+ else PRINTF(L_CORE_CSA,"%s.%d: zero odd CW",devId,idx);
+ wait.Broadcast();
+ }
+ }
+ return true;
+}
+
+bool cDeCSA::SetCaPid(ca_pid_t *ca_pid)
+{
+ cMutexLock lock(&mutex);
+ if(ca_pid->index<MAX_CSA_IDX && ca_pid->pid<MAX_CSA_PIDS) {
+ pidmap[ca_pid->pid]=ca_pid->index;
+ PRINTF(L_CORE_CSA,"%s.%d: set pid %04x",devId,ca_pid->index,ca_pid->pid);
+ }
+ return true;
+}
+
+bool cDeCSA::Decrypt(unsigned char *data, int len, bool force)
+{
+ cMutexLock lock(&mutex);
+ int r=-2, ccs=0, currIdx=-1;
+ bool newRange=true;
+ range[0]=0;
+ len-=(TS_SIZE-1);
+ int l;
+ for(l=0; l<len; l+=TS_SIZE) {
+ if(data[l]!=TS_SYNC_BYTE) { // let higher level cope with that
+ PRINTF(L_CORE_CSA,"%s: garbage in TS buffer",devId);
+ if(ccs) force=true; // prevent buffer stall
+ break;
+ }
+ unsigned int ev_od=data[l+3]&0xC0;
+ if(ev_od==0x80 || ev_od==0xC0) { // encrypted
+ int idx=pidmap[((data[l+1]<<8)+data[l+2])&(MAX_CSA_PIDS-1)];
+ if(currIdx<0 || idx==currIdx) { // same or no index
+ currIdx=idx;
+ if(ccs==0 && ev_od!=even_odd[idx]) {
+ even_odd[idx]=ev_od;
+ wait.Broadcast();
+ PRINTF(L_CORE_CSA,"%s.%d: change to %s key",devId,idx,(ev_od&0x40)?"odd":"even");
+ bool doWait=false;
+ if(ev_od&0x40) {
+ flags[idx]&=~FL_EVEN_GOOD;
+ if(!(flags[idx]&FL_ODD_GOOD)) doWait=true;
+ }
+ else {
+ flags[idx]&=~FL_ODD_GOOD;
+ if(!(flags[idx]&FL_EVEN_GOOD)) doWait=true;
+ }
+ if(doWait) {
+ PRINTF(L_CORE_CSA,"%s.%d: %s key not ready (%d ms)",devId,idx,(ev_od&0x40)?"odd":"even",MAX_KEY_WAIT);
+ if(flags[idx]&FL_ACTIVITY) {
+ flags[idx]&=~FL_ACTIVITY;
+ if(wait.TimedWait(mutex,MAX_KEY_WAIT)) PRINTF(L_CORE_CSA,"%s.%d: successfully waited for key",devId,idx);
+ else PRINTF(L_CORE_CSA,"%s.%d: timed out. proceeding anyways",devId,idx);
+ }
+ else PRINTF(L_CORE_CSA,"%s.%d: not active. wait skipped",devId,idx);
+ }
+ }
+ if(newRange) {
+ r+=2; newRange=false;
+ range[r]=&data[l];
+ range[r+2]=0;
+ }
+ range[r+1]=&data[l+TS_SIZE];
+ if(++ccs>=cs) break;
+ }
+ else newRange=true; // other index, create hole
+ }
+ else { // unencrypted
+ // nothing, we don't create holes for unencrypted packets
+ }
+ }
+ int scanTS=l/TS_SIZE;
+ int stallP=ccs*100/scanTS;
+
+ LBSTART(L_CORE_CSAVERB);
+ LBPUT("%s: %s-%d-%d : %d-%d-%d stall=%d :: ",
+ devId,data==lastData?"SAME":"MOVE",(len+(TS_SIZE-1))/TS_SIZE,force,
+ currIdx,ccs,scanTS,stallP);
+ for(int l=0; l<len; l+=TS_SIZE) {
+ if(data[l]!=TS_SYNC_BYTE) break;
+ unsigned int ev_od=data[l+3]&0xC0;
+ if(ev_od&0x80) {
+ int pid=(data[l+1]<<8)+data[l+2];
+ int idx=pidmap[pid&(MAX_CSA_PIDS-1)];
+ LBPUT("%s/%x/%d ",(ev_od&0x40)?"o":"e",pid,idx);
+ }
+ else {
+ LBPUT("*/%x ",(data[l+1]<<8)+data[l+2]);
+ }
+ }
+ LBEND();
+
+ if(r>=0 && ccs<cs && !force) {
+ if(lastData==data && stall.TimedOut()) {
+ PRINTF(L_CORE_CSAVERB,"%s: stall timeout -> forced",devId);
+ force=true;
+ }
+ else if(stallP<=10 && scanTS>=cs) {
+ PRINTF(L_CORE_CSAVERB,"%s: flow factor stall -> forced",devId);
+ force=true;
+ }
+ }
+ lastData=data;
+
+ if(r>=0) { // we have some range
+ if(ccs>=cs || force) {
+ if(GetKeyStruct(currIdx)) {
+ int n=decrypt_packets(keys[currIdx],range);
+ PRINTF(L_CORE_CSAVERB,"%s.%d: decrypting ccs=%3d cs=%3d %s -> %3d decrypted",devId,currIdx,ccs,cs,ccs>=cs?"OK ":"INC",n);
+ if(n>0) {
+ stall.Set(MAX_STALL_MS);
+ return true;
+ }
+ }
+ }
+ else PRINTF(L_CORE_CSAVERB,"%s.%d: incomplete ccs=%3d cs=%3d",devId,currIdx,ccs,cs);
+ }
+ return false;
+}
#ifndef ___CAM_H
#define ___CAM_H
+#include <linux/dvb/ca.h>
+#include <vdr/ci.h>
#include <vdr/thread.h>
#include "data.h"
#include "misc.h"
class cChannel;
+class cRingBufferLinear;
+class cDevice;
class cEcmHandler;
class cEcmData;
class cLogger;
class cHookManager;
class cLogHook;
-class cScDevice;
+class cScCamSlot;
+class cCiFrame;
+class cDeCSA;
class cPrg;
// ----------------------------------------------------------------
// ----------------------------------------------------------------
+class cCiFrame {
+private:
+ cRingBufferLinear *rb;
+ unsigned char *mem;
+ int len, alen, glen;
+public:
+ cCiFrame(void);
+ ~cCiFrame();
+ void SetRb(cRingBufferLinear *Rb) { rb=Rb; }
+ unsigned char *GetBuff(int l);
+ void Put(void);
+ unsigned char *Get(int &l);
+ void Del(void);
+ int Avail(void);
+ };
+
+// ----------------------------------------------------------------
+
+typedef int caid_t;
+
+#define MAX_CI_SLOTS 8
+#ifdef VDR_MAXCAID
+#define MAX_CI_SLOT_CAIDS VDR_MAXCAID
+#else
+#define MAX_CI_SLOT_CAIDS 16
+#endif
+
#define MAX_CW_IDX 16
#define MAX_SPLIT_SID 16
-class cCam : private cMutex {
+class cCam : public cCiAdapter, public cSimpleItem {
private:
- int cardNum;
- cScDevice *device;
+ cDevice *device;
+ cMutex ciMutex;
+ const char *devId;
+ int adapter, frontend;
+ cRingBufferLinear *rb;
+ cScCamSlot *slots[MAX_CI_SLOTS];
+ cCiFrame frame;
+ //
+ cDeCSA *decsa;
+ int cafd;
+ cMutex cafdMutex;
+ bool softcsa, fullts;
+ //
+ cTimeMs caidTimer, triggerTimer;
+ int version[MAX_CI_SLOTS];
+ caid_t caids[MAX_CI_SLOTS][MAX_CI_SLOT_CAIDS+1];
+ int tcid;
+ bool rebuildcaids;
+ //
+ cTimeMs readTimer, writeTimer;
+ cTimeMs lastDump;
+ //
+ cMutex camMutex;
cSimpleList<cEcmHandler> handlerList;
cLogger *logger;
cHookManager *hookman;
int splitSid[MAX_SPLIT_SID+1];
unsigned char indexMap[MAX_CW_IDX], lastCW[MAX_CW_IDX][2*8];
//
+ void BuildCaids(bool force);
cEcmHandler *GetHandler(int sid, bool needZero, bool noshift);
void RemHandler(cEcmHandler *handler);
int GetFreeIndex(void);
void LogStartup(void);
+protected:
+ virtual int Read(unsigned char *Buffer, int MaxLength);
+ virtual void Write(const unsigned char *Buffer, int Length);
+ virtual bool Reset(int Slot);
+ virtual eModuleStatus ModuleStatus(int Slot);
+ virtual bool Assign(cDevice *Device, bool Query=false);
public:
- cCam(cScDevice *dev, int CardNum);
+ cCam(cDevice *Device, int Adapter, int Frontend, const char *DevId, int Cafd, bool SoftCSA, bool FullTS);
virtual ~cCam();
+ // CI adapter API
+ int GetCaids(int slot, unsigned short *Caids, int max);
+ void CaidsChanged(void);
+ virtual bool SetCaDescr(ca_descr_t *ca_descr, bool initial);
+ virtual bool SetCaPid(ca_pid_t *ca_pid);
+ void Stop(void);
+ void AddPrg(cPrg *prg);
+ bool HasPrg(int prg);
// EcmHandler API
void WriteCW(int index, unsigned char *cw, bool force);
void SetCWIndex(int pid, int index);
void DumpAV7110(void);
+ bool IsSoftCSA(bool live);
+ int Adapter(void) { return adapter; }
+ int Frontend(void) { return frontend; }
+ // System API
void LogEcmStatus(const cEcmInfo *ecm, bool on);
void AddHook(cLogHook *hook);
bool TriggerHook(int id);
void Tune(const cChannel *channel);
void PostTune(void);
void SetPid(int type, int pid, bool on);
- void Stop(void);
- void AddPrg(cPrg *prg);
- bool HasPrg(int prg);
- char *CurrentKeyStr(int num);
- //
- bool IsSoftCSA(bool live);
+ char *CurrentKeyStr(int num, const char **id);
+ bool OwnSlot(const cCamSlot *slot) const;
+ cDeCSA *DeCSA(void) const { return decsa; }
};
void LogStatsDown(void);
+// ----------------------------------------------------------------
+
+#define MAX_CSA_PIDS 8192
+#define MAX_CSA_IDX 16
+
+class cDeCSA {
+private:
+ int cs;
+ unsigned char **range, *lastData;
+ unsigned char pidmap[MAX_CSA_PIDS];
+ void *keys[MAX_CSA_IDX];
+ unsigned int even_odd[MAX_CSA_IDX], flags[MAX_CSA_IDX];
+ cMutex mutex;
+ cCondVar wait;
+ cTimeMs stall;
+ bool active;
+ const char *devId;
+ //
+ bool GetKeyStruct(int idx);
+ void ResetState(void);
+public:
+ cDeCSA(const char *DevId);
+ ~cDeCSA();
+ bool Decrypt(unsigned char *data, int len, bool force);
+ bool SetDescr(ca_descr_t *ca_descr, bool initial);
+ bool SetCaPid(ca_pid_t *ca_pid);
+ void SetActive(bool on);
+ };
+
#endif // ___CAM_H
// -- cPid ---------------------------------------------------------------------
-cPid::cPid(int Pid, int Section, int Mask, int Mode)
+cPid::cPid(int Pid, int Section, int Mask)
{
pid=Pid;
sct=Section;
mask=Mask;
- mode=Mode;
filter=0;
}
// -- cPids --------------------------------------------------------------------
-void cPids::AddPid(int Pid, int Section, int Mask, int Mode)
+void cPids::AddPid(int Pid, int Section, int Mask)
{
- if(!HasPid(Pid,Section,Mask,Mode)) {
- cPid *pid=new cPid(Pid,Section,Mask,Mode);
+ if(!HasPid(Pid,Section,Mask)) {
+ cPid *pid=new cPid(Pid,Section,Mask);
Add(pid);
}
}
-bool cPids::HasPid(int Pid, int Section, int Mask, int Mode)
+bool cPids::HasPid(int Pid, int Section, int Mask)
{
for(cPid *pid=First(); pid; pid=Next(pid))
- if(pid->pid==Pid && pid->sct==Section && pid->mask==Mask && pid->mode==Mode)
+ if(pid->pid==Pid && pid->sct==Section && pid->mask==Mask)
return true;
return false;
}
transponder=e->transponder;
rewriterId=e->rewriterId;
SetRewriter();
+ dvbAdapter=e->dvbAdapter; dvbFrontend=e->dvbFrontend;
}
cEcmInfo::cEcmInfo(const char *Name, int Pid, int CaId, int ProvId)
prgId=grPrgId=source=transponder=-1;
ecm_table=0x80; emmCaId=0;
rewriter=0; rewriterId=0;
+ dvbAdapter=dvbFrontend=-1;
}
bool cEcmInfo::Compare(const cEcmInfo *e)
caId==e->caId && ecm_pid==e->ecm_pid && provId==e->provId;
}
+void cEcmInfo::SetDvb(int DvbAdapter, int DvbFrontend)
+{
+ dvbAdapter=DvbAdapter; dvbFrontend=DvbFrontend;
+}
+
void cEcmInfo::SetSource(int GrPrgId, int Source, int Transponder)
{
grPrgId=GrPrgId; prgId=grPrgId%SIDGRP_SHIFT;
class cPid : public cSimpleItem {
public:
- int pid, sct, mask, mode;
+ int pid, sct, mask;
cPidFilter *filter;
//
- cPid(int Pid, int Section, int Mask, int Mode);
+ cPid(int Pid, int Section, int Mask);
};
// ----------------------------------------------------------------
class cPids : public cSimpleList<cPid> {
public:
- void AddPid(int Pid, int Section, int Mask, int Mode=0);
- bool HasPid(int Pid, int Section, int Mask, int Mode=0);
+ void AddPid(int Pid, int Section, int Mask);
+ bool HasPid(int Pid, int Section, int Mask);
};
// ----------------------------------------------------------------
int prgId, grPrgId, source, transponder;
cRewriter *rewriter;
int rewriterId;
+ int dvbAdapter, dvbFrontend;
//
cEcmInfo(void);
cEcmInfo(const cEcmInfo *e);
~cEcmInfo();
virtual cString ToString(bool hide=false) { return ""; }
bool Compare(const cEcmInfo *e);
+ void SetDvb(int DvbAdapter, int DvbFrontend);
void SetSource(int GrPrgId, int Source, int Transponder);
void SetName(const char *Name);
void SetDataIdx(int idx);
#include <sys/time.h>
#include <dlfcn.h>
-#include <linux/dvb/ca.h>
#include <vdr/channels.h>
#include <vdr/ci.h>
#include <vdr/dvbdevice.h>
#include "misc.h"
#include "log-core.h"
-#define MAX_CI_SLOTS 8
-
-#ifdef VDR_MAXCAID
-#define MAX_CI_SLOT_CAIDS VDR_MAXCAID
-#else
-#define MAX_CI_SLOT_CAIDS 16
-#endif
-
-// -- cCaDescr -----------------------------------------------------------------
-
-cCaDescr::cCaDescr(void)
-{
- descr=0; len=0;
-}
-
-cCaDescr::cCaDescr(const cCaDescr &cd)
-{
- descr=0; len=0;
- Set(cd.descr,cd.len);
-}
-
-cCaDescr::~cCaDescr()
-{
- Clear();
-}
-
-const unsigned char *cCaDescr::Get(int &l) const
-{
- l=len;
- return descr;
-}
-
-void cCaDescr::Set(const cCaDescr *d)
-{
- Set(d->descr,d->len);
-}
-
-void cCaDescr::Set(const unsigned char *de, int l)
-{
- Clear();
- if(l) {
- descr=MALLOC(unsigned char,l);
- if(descr) {
- memcpy(descr,de,l);
- len=l;
- }
- }
-}
-
-void cCaDescr::Clear(void)
-{
- free(descr); descr=0; len=0;
-}
-
-void cCaDescr::Join(const cCaDescr *cd, bool rev)
-{
- if(cd->descr) {
- int l=len+cd->len;
- unsigned char *m=MALLOC(unsigned char,l);
- if(m) {
- if(!rev) {
- if(descr) memcpy(m,descr,len);
- memcpy(m+len,cd->descr,cd->len);
- }
- else {
- memcpy(m,cd->descr,cd->len);
- if(descr) memcpy(m+cd->len,descr,len);
- }
- Clear();
- descr=m; len=l;
- }
- }
-}
-
-bool cCaDescr::operator== (const cCaDescr &cd) const
-{
- return len==cd.len && (len==0 || memcmp(descr,cd.descr,len)==0);
-}
-
-cString cCaDescr::ToString(void)
-{
- if(!descr) return "<empty>";
- char *str=AUTOARRAY(char,len*3+8);
- int q=sprintf(str,"%02X",descr[0]);
- for(int i=1; i<len; i++) q+=sprintf(str+q," %02X",descr[i]);
- return str;
-}
-
-// -- cPrg ---------------------------------------------------------------------
-
-cPrg::cPrg(void)
-{
- Setup();
-}
-
-cPrg::cPrg(int Sid, bool IsUpdate)
-{
- Setup();
- sid=Sid; isUpdate=IsUpdate;
-}
-
-void cPrg::Setup(void)
-{
- sid=-1; source=-1; transponder=-1;
- isUpdate=pidCaDescr=false;
-}
-
-void cPrg::DumpCaDescr(int c)
-{
- PRINTF(c,"prgca: %s",*caDescr.ToString());
- for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
- PRINTF(c,"pidca %04x: %s",pid->pid,*pid->caDescr.ToString());
-}
-
-bool cPrg::SimplifyCaDescr(void)
-{
-//XXX
-PRINTF(L_CORE_PIDS,"SimplyCa entry pidCa=%d",HasPidCaDescr());
-DumpCaDescr(L_CORE_PIDS);
-//XXX
-
- if(HasPidCaDescr()) {
- bool equal=true;
- if(pids.Count()>1) {
- cPrgPid *pid0=pids.First();
- for(cPrgPid *pid1=pids.Next(pid0); pid1; pid1=pids.Next(pid1))
- if(!(pid0->caDescr==pid1->caDescr)) { equal=false; break; }
- }
- if(equal) {
- cPrgPid *pid=pids.First();
- caDescr.Join(&pid->caDescr);
- for(; pid; pid=pids.Next(pid)) pid->caDescr.Clear();
- SetPidCaDescr(false);
- }
- }
- if(HasPidCaDescr()) {
- for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
- pid->caDescr.Join(&caDescr,true);
- caDescr.Clear();
- }
-
-//XXX
-PRINTF(L_CORE_PIDS,"SimplyCa exit pidCa=%d",HasPidCaDescr());
-DumpCaDescr(L_CORE_PIDS);
-//XXX
-
- return HasPidCaDescr();
-}
-
-// --- cChannelCaids -----------------------------------------------------------
-
-#ifndef SASC
-
-class cChannelCaids : public cSimpleItem {
-private:
- int prg, source, transponder;
- int numcaids;
- caid_t caids[MAX_CI_SLOT_CAIDS+1];
-public:
- cChannelCaids(cChannel *channel);
- bool IsChannel(cChannel *channel);
- void Sort(void);
- void Del(caid_t caid);
- bool HasCaid(caid_t caid);
- bool Same(cChannelCaids *ch, bool full);
- void HistAdd(unsigned short *hist);
- void Dump(int n);
- const caid_t *Caids(void) { caids[numcaids]=0; return caids; }
- int NumCaids(void) { return numcaids; }
- int Source(void) const { return source; }
- int Transponder(void) const { return transponder; }
- };
-
-cChannelCaids::cChannelCaids(cChannel *channel)
-{
- prg=channel->Sid(); source=channel->Source(); transponder=channel->Transponder();
- numcaids=0;
- for(const caid_t *ids=channel->Caids(); *ids; ids++)
- if(numcaids<MAX_CI_SLOT_CAIDS) caids[numcaids++]=*ids;
- Sort();
-}
-
-bool cChannelCaids::IsChannel(cChannel *channel)
-{
- return prg==channel->Sid() && source==channel->Source() && transponder==channel->Transponder();
-}
-
-void cChannelCaids::Sort(void)
-{
- caid_t tmp[MAX_CI_SLOT_CAIDS];
- int c=0xFFFF;
- for(int i=0; i<numcaids; i++) {
- int d=0;
- for(int j=0; j<numcaids; j++) if(caids[j]>d && caids[j]<c) d=caids[j];
- tmp[i]=d; c=d;
- }
- memcpy(caids,tmp,sizeof(caids));
-}
-
-void cChannelCaids::Del(caid_t caid)
-{
- for(int i=0; i<numcaids; i++)
- if(caids[i]==caid) {
- numcaids--; caids[i]=caids[numcaids];
- if(numcaids>0) Sort();
- caids[numcaids]=0;
- break;
- }
-}
-
-bool cChannelCaids::HasCaid(caid_t caid)
-{
- for(int i=0; i<numcaids; i++) if(caids[i]==caid) return true;
- return false;
-}
-
-bool cChannelCaids::Same(cChannelCaids *ch, bool full)
-{
- if(full && (source!=ch->source || transponder!=ch->transponder)) return false;
- if(numcaids!=ch->numcaids) return false;
- return memcmp(caids,ch->caids,numcaids*sizeof(caid_t))==0;
-}
-
-void cChannelCaids::HistAdd(unsigned short *hist)
-{
- for(int i=numcaids-1; i>=0; i--) hist[caids[i]]++;
-}
-
-void cChannelCaids::Dump(int n)
-{
- LBSTART(L_CORE_CAIDS);
- LBPUT("%d: channel %d/%x/%x",n,prg,source,transponder);
- for(const caid_t *ids=Caids(); *ids; ids++) LBPUT(" %04x",*ids);
- LBEND();
-}
-
-// --- cChannelList ------------------------------------------------------------
-
-class cChannelList : public cSimpleList<cChannelCaids> {
-private:
- int n;
-public:
- cChannelList(int N);
- void Unique(bool full);
- void CheckIgnore(void);
- int Histo(void);
- void Purge(int caid, bool fullch);
- };
-
-cChannelList::cChannelList(int N)
-{
- n=N;
-}
-
-void cChannelList::CheckIgnore(void)
-{
- char *cache=MALLOC(char,0x10000);
- if(!cache) return;
- memset(cache,0,sizeof(char)*0x10000);
- int cTotal=0, cHits=0;
- for(cChannelCaids *ch=First(); ch; ch=Next(ch)) {
- const caid_t *ids=ch->Caids();
- while(*ids) {
- int pri=0;
- if(overrides.Ignore(ch->Source(),ch->Transponder(),*ids))
- ch->Del(*ids);
- else {
- char c=cache[*ids];
- if(c==0) cache[*ids]=c=(cSystems::FindIdentBySysId(*ids,false,pri) ? 1 : -1);
- else cHits++;
- cTotal++;
- if(c<0) {
- for(cChannelCaids *ch2=Next(ch); ch2; ch2=Next(ch2)) ch2->Del(*ids);
- ch->Del(*ids);
- }
- else ids++;
- }
- }
- }
- free(cache);
- PRINTF(L_CORE_CAIDS,"%d: after check",n);
- for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(n);
- PRINTF(L_CORE_CAIDS,"%d: check cache usage: %d requests, %d hits, %d%% hits",n,cTotal,cHits,(cTotal>0)?(cHits*100/cTotal):0);
-}
-
-void cChannelList::Unique(bool full)
-{
- for(cChannelCaids *ch1=First(); ch1; ch1=Next(ch1)) {
- for(cChannelCaids *ch2=Next(ch1); ch2;) {
- if(ch1->Same(ch2,full) || ch2->NumCaids()<1) {
- cChannelCaids *t=Next(ch2);
- Del(ch2);
- ch2=t;
- }
- else ch2=Next(ch2);
- }
- }
- if(Count()==1 && First() && First()->NumCaids()<1) Del(First());
- PRINTF(L_CORE_CAIDS,"%d: after unique (%d)",n,full);
- for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(n);
-}
-
-int cChannelList::Histo(void)
-{
- int h=-1;
- unsigned short *hist=MALLOC(unsigned short,0x10000);
- if(hist) {
- memset(hist,0,sizeof(unsigned short)*0x10000);
- for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->HistAdd(hist);
- int c=0;
- for(int i=0; i<0x10000; i++)
- if(hist[i]>c) { h=i; c=hist[i]; }
- free(hist);
- }
- else PRINTF(L_GEN_ERROR,"malloc failed in cChannelList::Histo");
- return h;
-}
-
-void cChannelList::Purge(int caid, bool fullch)
-{
- for(cChannelCaids *ch=First(); ch;) {
- if(!fullch) ch->Del(caid);
- if(ch->NumCaids()<=0 || (fullch && ch->HasCaid(caid))) {
- cChannelCaids *t=Next(ch);
- Del(ch);
- ch=t;
- }
- else ch=Next(ch);
- }
- if(Count()>0) {
- PRINTF(L_CORE_CAIDS,"%d: still left",n);
- for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(n);
- }
-}
-
-// -- cCiFrame -----------------------------------------------------------------
-
-#define LEN_OFF 2
-
-class cCiFrame {
-private:
- cRingBufferLinear *rb;
- unsigned char *mem;
- int len, alen, glen;
-public:
- cCiFrame(void);
- ~cCiFrame();
- void SetRb(cRingBufferLinear *Rb) { rb=Rb; }
- unsigned char *GetBuff(int l);
- void Put(void);
- unsigned char *Get(int &l);
- void Del(void);
- int Avail(void);
- };
-
-cCiFrame::cCiFrame(void)
-{
- rb=0; mem=0; len=alen=glen=0;
-}
-
-cCiFrame::~cCiFrame()
-{
- free(mem);
-}
-
-unsigned char *cCiFrame::GetBuff(int l)
-{
- if(!mem || l>alen) {
- free(mem); mem=0; alen=0;
- mem=MALLOC(unsigned char,l+LEN_OFF);
- if(mem) alen=l;
- }
- len=l;
- if(!mem) {
- PRINTF(L_GEN_DEBUG,"internal: ci-frame alloc failed");
- return 0;
- }
- return mem+LEN_OFF;
-}
-
-void cCiFrame::Put(void)
-{
- if(rb && mem) {
- *((short *)mem)=len;
- rb->Put(mem,len+LEN_OFF);
- }
-}
-
-unsigned char *cCiFrame::Get(int &l)
-{
- if(rb) {
- int c;
- unsigned char *data=rb->Get(c);
- if(data) {
- if(c>LEN_OFF) {
- int s=*((short *)data);
- if(c>=s+LEN_OFF) {
- l=glen=s;
- return data+LEN_OFF;
- }
- }
- LDUMP(L_GEN_DEBUG,data,c,"internal: ci rb frame sync got=%d avail=%d -",c,rb->Available());
- rb->Clear();
- }
- }
- return 0;
-}
-
-int cCiFrame::Avail(void)
-{
- return rb ? rb->Available() : 0;
-}
-
-void cCiFrame::Del(void)
-{
- if(rb && glen) {
- rb->Del(glen+LEN_OFF);
- glen=0;
- }
-}
-
-// -- cScCiAdapter -------------------------------------------------------------
-
-#define CAID_TIME 300000 // time between caid scans
-#define TRIGGER_TIME 10000 // min. time between caid scan trigger
-
-#define TDPU_SIZE_INDICATOR 0x80
-
-struct TPDU {
- unsigned char slot;
- unsigned char tcid;
- unsigned char tag;
- unsigned char len;
- unsigned char data[1];
- };
-
-class cScCamSlot;
-
-class cScCiAdapter : public cCiAdapter {
-private:
- cDevice *device;
- cCam *cam;
- cMutex ciMutex;
- int cardIndex;
- cRingBufferLinear *rb;
- cScCamSlot *slots[MAX_CI_SLOTS];
- cCiFrame frame;
- //
- cTimeMs caidTimer, triggerTimer;
- int version[MAX_CI_SLOTS];
- caid_t caids[MAX_CI_SLOTS][MAX_CI_SLOT_CAIDS+1];
- int tcid;
- bool rebuildcaids;
- //
- cTimeMs readTimer, writeTimer;
- //
- void BuildCaids(bool force);
-protected:
- virtual int Read(unsigned char *Buffer, int MaxLength);
- virtual void Write(const unsigned char *Buffer, int Length);
- virtual bool Reset(int Slot);
- virtual eModuleStatus ModuleStatus(int Slot);
- virtual bool Assign(cDevice *Device, bool Query=false);
-public:
- cScCiAdapter(cDevice *Device, int CardIndex, cCam *Cam);
- ~cScCiAdapter();
- void CamStop(void);
- void CamAddPrg(cPrg *prg);
- bool CamSoftCSA(void);
- int GetCaids(int slot, unsigned short *Caids, int max);
- void CaidsChanged(void);
- };
-
-// -- cScCamSlot ---------------------------------------------------------------
-
-#define SLOT_CAID_CHECK 10000
-#define SLOT_RESET_TIME 600
-
-class cScCamSlot : public cCamSlot {
-private:
- cScCiAdapter *ciadapter;
- unsigned short caids[MAX_CI_SLOT_CAIDS+1];
- int slot, cardIndex, version;
- cTimeMs checkTimer;
- bool reset, doReply;
- cTimeMs resetTimer;
- eModuleStatus lastStatus;
- cRingBufferLinear rb;
- cCiFrame frame;
- //
- int GetLength(const unsigned char * &data);
- int LengthSize(int n);
- void SetSize(int n, unsigned char * &p);
- void CaInfo(int tcid, int cid);
- bool Check(void);
-public:
- cScCamSlot(cScCiAdapter *ca, int CardIndex, int Slot);
- void Process(const unsigned char *data, int len);
- eModuleStatus Status(void);
- bool Reset(bool log=true);
- cCiFrame *Frame(void) { return &frame; }
- };
-
-cScCamSlot::cScCamSlot(cScCiAdapter *ca, int CardIndex, int Slot)
-:cCamSlot(ca)
-,checkTimer(-SLOT_CAID_CHECK-1000)
-,rb(KILOBYTE(4),5+LEN_OFF,false,"SC-CI slot answer")
-{
- ciadapter=ca; cardIndex=CardIndex; slot=Slot;
- version=0; caids[0]=0; doReply=false; lastStatus=msReset;
- frame.SetRb(&rb);
- Reset(false);
-}
-
-eModuleStatus cScCamSlot::Status(void)
-{
- eModuleStatus status;
- if(reset) {
- status=msReset;
- if(resetTimer.TimedOut()) reset=false;
- }
- else if(caids[0]) status=msReady;
- else {
- status=msPresent; //msNone;
- Check();
- }
- if(status!=lastStatus) {
- static const char *stext[] = { "none","reset","present","ready" };
- PRINTF(L_CORE_CI,"%d.%d: status '%s'",cardIndex,slot,stext[status]);
- lastStatus=status;
- }
- return status;
-}
-
-bool cScCamSlot::Reset(bool log)
-{
- reset=true; resetTimer.Set(SLOT_RESET_TIME);
- rb.Clear();
- if(log) PRINTF(L_CORE_CI,"%d.%d: reset",cardIndex,slot);
- return true;
-}
-
-bool cScCamSlot::Check(void)
-{
- bool res=false;
- bool dr=ciadapter->CamSoftCSA() || ScSetup.ConcurrentFF>0;
- if(dr!=doReply && !IsDecrypting()) {
- PRINTF(L_CORE_CI,"%d.%d: doReply changed, reset triggered",cardIndex,slot);
- Reset(false);
- doReply=dr;
- }
- if(checkTimer.TimedOut()) {
- if(version!=ciadapter->GetCaids(slot,0,0)) {
- version=ciadapter->GetCaids(slot,caids,MAX_CI_SLOT_CAIDS);
- PRINTF(L_CORE_CI,"%d.%d: now using CAIDs version %d",cardIndex,slot,version);
- res=true;
- }
- checkTimer.Set(SLOT_CAID_CHECK);
- }
- return res;
-}
-
-int cScCamSlot::GetLength(const unsigned char * &data)
-{
- int len=*data++;
- if(len&TDPU_SIZE_INDICATOR) {
- int i;
- for(i=len&~TDPU_SIZE_INDICATOR, len=0; i>0; i--) len=(len<<8) + *data++;
- }
- return len;
-}
-
-int cScCamSlot::LengthSize(int n)
-{
- return n<TDPU_SIZE_INDICATOR?1:3;
-}
-
-void cScCamSlot::SetSize(int n, unsigned char * &p)
-{
- if(n<TDPU_SIZE_INDICATOR) *p++=n;
- else { *p++=2|TDPU_SIZE_INDICATOR; *p++=n>>8; *p++=n&0xFF; }
-}
-
-void cScCamSlot::CaInfo(int tcid, int cid)
-{
- int cn=0;
- for(int i=0; caids[i]; i++) cn+=2;
- int n=cn+8+LengthSize(cn);
- unsigned char *p;
- if(!(p=frame.GetBuff(n+1+LengthSize(n)))) return;
- *p++=0xa0;
- SetSize(n,p);
- *p++=tcid;
- *p++=0x90;
- *p++=0x02; *p++=cid>>8; *p++=cid&0xff;
- *p++=0x9f; *p++=0x80; *p++=0x31; // AOT_CA_INFO
- SetSize(cn,p);
- for(int i=0; caids[i]; i++) { *p++=caids[i]>>8; *p++=caids[i]&0xff; }
- frame.Put();
- PRINTF(L_CORE_CI,"%d.%d sending CA info",cardIndex,slot);
-}
-
-void cScCamSlot::Process(const unsigned char *data, int len)
-{
- const unsigned char *save=data;
- data+=3;
- int dlen=GetLength(data);
- if(dlen>len-(data-save)) {
- PRINTF(L_CORE_CI,"%d.%d TDPU length exceeds data length",cardIndex,slot);
- dlen=len-(data-save);
- }
- int tcid=data[0];
-
- if(Check()) CaInfo(tcid,0x01);
-
- if(dlen<8 || data[1]!=0x90) return;
- int cid=(data[3]<<8)+data[4];
- int tag=(data[5]<<16)+(data[6]<<8)+data[7];
- data+=8;
- dlen=GetLength(data);
- if(dlen>len-(data-save)) {
- PRINTF(L_CORE_CI,"%d.%d tag length exceeds data length",cardIndex,slot);
- dlen=len-(data-save);
- }
- switch(tag) {
- case 0x9f8030: // AOT_CA_INFO_ENQ
- CaInfo(tcid,cid);
- break;
-
- case 0x9f8032: // AOT_CA_PMT
- if(dlen>=6) {
- int ca_lm=data[0];
- int ci_cmd=-1;
- cPrg *prg=new cPrg((data[1]<<8)+data[2],ca_lm==5);
- int ilen=(data[4]<<8)+data[5];
- LBSTARTF(L_CORE_CI);
- LBPUT("%d.%d CA_PMT decoding len=%x lm=%x prg=%d len=%x",cardIndex,slot,dlen,ca_lm,(data[1]<<8)+data[2],ilen);
- data+=6; dlen-=6;
- LBPUT("/%x",dlen);
- if(ilen>0 && dlen>=ilen) {
- ci_cmd=data[0];
- if(ilen>1)
- prg->caDescr.Set(&data[1],ilen-1);
- LBPUT(" ci_cmd(G)=%02x",ci_cmd);
- }
- data+=ilen; dlen-=ilen;
- while(dlen>=5) {
- cPrgPid *pid=new cPrgPid(data[0],(data[1]<<8)+data[2]);
- prg->pids.Add(pid);
- ilen=(data[3]<<8)+data[4];
- LBPUT(" pid=%d,%x len=%x",data[0],(data[1]<<8)+data[2],ilen);
- data+=5; dlen-=5;
- LBPUT("/%x",dlen);
- if(ilen>0 && dlen>=ilen) {
- ci_cmd=data[0];
- if(ilen>1) {
- pid->caDescr.Set(&data[1],ilen-1);
- prg->SetPidCaDescr(true);
- }
- LBPUT(" ci_cmd(S)=%x",ci_cmd);
- }
- data+=ilen; dlen-=ilen;
- }
- LBEND();
- PRINTF(L_CORE_CI,"%d.%d got CA pmt ciCmd=%d caLm=%d",cardIndex,slot,ci_cmd,ca_lm);
- if(doReply && (ci_cmd==0x03 || (ci_cmd==0x01 && ca_lm==0x03))) {
- unsigned char *b;
- if((b=frame.GetBuff(4+11))) {
- b[0]=0xa0; b[2]=tcid;
- b[3]=0x90;
- b[4]=0x02; b[5]=cid<<8; b[6]=cid&0xff;
- b[7]=0x9f; b[8]=0x80; b[9]=0x33; // AOT_CA_PMT_REPLY
- b[11]=prg->sid<<8;
- b[12]=prg->sid&0xff;
- b[13]=0x00;
- b[14]=0x81; // CA_ENABLE
- b[10]=4; b[1]=4+9;
- frame.Put();
- PRINTF(L_CORE_CI,"%d.%d answer to query",cardIndex,slot);
- }
- }
- if(prg->sid!=0) {
- if(ci_cmd==0x04) {
- PRINTF(L_CORE_CI,"%d.%d stop decrypt",cardIndex,slot);
- ciadapter->CamStop();
- }
- if(ci_cmd==0x01 || (ci_cmd==-1 && (ca_lm==0x04 || ca_lm==0x05))) {
- PRINTF(L_CORE_CI,"%d.%d set CAM decrypt (prg %d)",cardIndex,slot,prg->sid);
- ciadapter->CamAddPrg(prg);
- }
- }
- delete prg;
- }
- break;
- }
-}
-
-// -- cScCiAdapter -------------------------------------------------------------
-
-cScCiAdapter::cScCiAdapter(cDevice *Device, int CardIndex, cCam *Cam)
-{
- device=Device; cardIndex=CardIndex; cam=Cam;
- tcid=0; rebuildcaids=false;
- memset(version,0,sizeof(version));
- memset(slots,0,sizeof(slots));
- SetDescription("SC-CI adapter on device %d",cardIndex);
- rb=new cRingBufferLinear(KILOBYTE(8),6+LEN_OFF,false,"SC-CI adapter read");
- if(rb) {
- rb->SetTimeouts(0,CAM_READ_TIMEOUT);
- frame.SetRb(rb);
-/*
- bool spare=true;
- for(int i=0; i<MAX_CI_SLOTS; i++) {
- if(GetCaids(i,0,0)<=0) {
- if(!spare) break;
- spare=false;
- }
- slots[i]=new cScCamSlot(this,cardIndex,i);
- }
-*/
- BuildCaids(true);
- slots[0]=new cScCamSlot(this,cardIndex,0);
- Start();
- }
- else PRINTF(L_GEN_ERROR,"failed to create ringbuffer for SC-CI adapter %d.",cardIndex);
-}
-
-cScCiAdapter::~cScCiAdapter()
-{
- Cancel(3);
- ciMutex.Lock();
- delete rb; rb=0;
- ciMutex.Unlock();
-}
-
-void cScCiAdapter::CamStop(void)
-{
- if(cam) cam->Stop();
-}
-
-void cScCiAdapter::CamAddPrg(cPrg *prg)
-{
- if(cam) cam->AddPrg(prg);
-}
-
-bool cScCiAdapter::CamSoftCSA(void)
-{
- return cam && cam->IsSoftCSA(false);
-}
-
-int cScCiAdapter::GetCaids(int slot, unsigned short *Caids, int max)
-{
- BuildCaids(false);
- cMutexLock lock(&ciMutex);
- if(Caids) {
- int i;
- for(i=0; i<MAX_CI_SLOT_CAIDS && i<max && caids[i]; i++) Caids[i]=caids[slot][i];
- Caids[i]=0;
- }
- return version[slot];
-}
-
-void cScCiAdapter::CaidsChanged(void)
-{
- rebuildcaids=true;
-}
-
-void cScCiAdapter::BuildCaids(bool force)
-{
- if(caidTimer.TimedOut() || force || (rebuildcaids && triggerTimer.TimedOut())) {
- PRINTF(L_CORE_CAIDS,"%d: building caid lists",cardIndex);
- cChannelList list(cardIndex);
- Channels.Lock(false);
- for(cChannel *channel=Channels.First(); channel; channel=Channels.Next(channel)) {
- if(!channel->GroupSep() && channel->Ca()>=CA_ENCRYPTED_MIN && device->ProvidesTransponder(channel)) {
- cChannelCaids *ch=new cChannelCaids(channel);
- if(ch) list.Add(ch);
- }
- }
- Channels.Unlock();
- list.Unique(true);
- list.CheckIgnore();
- list.Unique(false);
-
- int n=0, h;
- caid_t c[MAX_CI_SLOT_CAIDS+1];
- memset(c,0,sizeof(c));
- do {
- if((h=list.Histo())<0) break;
- c[n++]=h;
- LBSTART(L_CORE_CAIDS);
- LBPUT("%d: added %04x caids now",cardIndex,h); for(int i=0; i<n; i++) LBPUT(" %04x",c[i]);
- LBEND();
- list.Purge(h,false);
- } while(n<MAX_CI_SLOT_CAIDS && list.Count()>0);
- c[n]=0;
- if(n==0) PRINTF(L_CORE_CI,"no active CAIDs");
- else if(list.Count()>0) PRINTF(L_GEN_ERROR,"too many CAIDs. You should ignore some CAIDs.");
-
- ciMutex.Lock();
- if((version[0]==0 && c[0]!=0) || memcmp(caids[0],c,sizeof(caids[0]))) {
- memcpy(caids[0],c,sizeof(caids[0]));
- version[0]++;
- if(version[0]>0) {
- LBSTART(L_CORE_CI);
- LBPUT("card %d, slot %d (v=%2d) caids:",cardIndex,0,version[0]);
- for(int i=0; caids[0][i]; i++) LBPUT(" %04x",caids[0][i]);
- LBEND();
- }
- }
- ciMutex.Unlock();
-
- caidTimer.Set(CAID_TIME);
- triggerTimer.Set(TRIGGER_TIME);
- rebuildcaids=false;
- }
-}
-
-int cScCiAdapter::Read(unsigned char *Buffer, int MaxLength)
-{
- cMutexLock lock(&ciMutex);
- if(cam && rb && Buffer && MaxLength>0) {
- int s;
- unsigned char *data=frame.Get(s);
- if(data) {
- if(s<=MaxLength) memcpy(Buffer,data,s);
- else PRINTF(L_GEN_DEBUG,"internal: sc-ci %d rb frame size exceeded %d",cardIndex,s);
- frame.Del();
- if(Buffer[2]!=0x80 || LOG(L_CORE_CIFULL)) {
- LDUMP(L_CORE_CI,Buffer,s,"%d.%d <-",cardIndex,Buffer[0]);
- readTimer.Set();
- }
- return s;
- }
- }
- else cCondWait::SleepMs(CAM_READ_TIMEOUT);
- if(LOG(L_CORE_CIFULL) && readTimer.Elapsed()>2000) {
- PRINTF(L_CORE_CIFULL,"%d: read heartbeat",cardIndex);
- readTimer.Set();
- }
- return 0;
-}
-
-#define TPDU(data,slot) do { unsigned char *_d=(data); _d[0]=(slot); _d[1]=tcid; } while(0)
-#define TAG(data,tag,len) do { unsigned char *_d=(data); _d[0]=(tag); _d[1]=(len); } while(0)
-#define SB_TAG(data,sb) do { unsigned char *_d=(data); _d[0]=0x80; _d[1]=0x02; _d[2]=tcid; _d[3]=(sb); } while(0)
-
-void cScCiAdapter::Write(const unsigned char *buff, int len)
-{
- cMutexLock lock(&ciMutex);
- if(cam && buff && len>=5) {
- struct TPDU *tpdu=(struct TPDU *)buff;
- int slot=tpdu->slot;
- cCiFrame *slotframe=slots[slot]->Frame();
- if(buff[2]!=0xA0 || buff[3]>0x01 || LOG(L_CORE_CIFULL))
- LDUMP(L_CORE_CI,buff,len,"%d.%d ->",cardIndex,slot);
- if(slots[slot]) {
- switch(tpdu->tag) {
- case 0x81: // T_RCV
- {
- int s;
- unsigned char *d=slotframe->Get(s);
- if(d) {
- unsigned char *b;
- if((b=frame.GetBuff(s+6))) {
- TPDU(b,slot);
- memcpy(b+2,d,s);
- slotframe->Del(); // delete from rb before Avail()
- SB_TAG(b+2+s,slotframe->Avail()>0 ? 0x80:0x00);
- frame.Put();
- }
- else slotframe->Del();
- }
- break;
- }
- case 0x82: // T_CREATE_TC
- {
- tcid=tpdu->data[0];
- unsigned char *b;
- static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 };
- if((b=slotframe->GetBuff(sizeof(reqCAS)))) {
- memcpy(b,reqCAS,sizeof(reqCAS));
- b[2]=tcid;
- slotframe->Put();
- }
- if((b=frame.GetBuff(9))) {
- TPDU(b,slot);
- TAG(&b[2],0x83,0x01); b[4]=tcid;
- SB_TAG(&b[5],slotframe->Avail()>0 ? 0x80:0x00);
- frame.Put();
- }
- break;
- }
- case 0xA0: // T_DATA_LAST
- {
- slots[slot]->Process(buff,len);
- unsigned char *b;
- if((b=frame.GetBuff(6))) {
- TPDU(b,slot);
- SB_TAG(&b[2],slotframe->Avail()>0 ? 0x80:0x00);
- frame.Put();
- }
- break;
- }
- }
- }
- }
- else PRINTF(L_CORE_CIFULL,"%d: short write (cam=%d buff=%d len=%d)",cardIndex,cam!=0,buff!=0,len);
-}
-
-bool cScCiAdapter::Reset(int Slot)
-{
- cMutexLock lock(&ciMutex);
- PRINTF(L_CORE_CI,"%d: reset of slot %d requested",cardIndex,Slot);
- return slots[Slot] ? slots[Slot]->Reset():false;
-}
-
-eModuleStatus cScCiAdapter::ModuleStatus(int Slot)
-{
- cMutexLock lock(&ciMutex);
- bool enable=ScSetup.CapCheck(cardIndex);
- if(!enable) CamStop();
- return (enable && cam && slots[Slot]) ? slots[Slot]->Status():msNone;
-}
-
-bool cScCiAdapter::Assign(cDevice *Device, bool Query)
-{
- return Device ? (Device==device) : true;
-}
-
-// -- cDeCSA -------------------------------------------------------------------
-
-#define MAX_CSA_PIDS 8192
-#define MAX_CSA_IDX 16
-#define MAX_STALL_MS 70
-
-#define MAX_REL_WAIT 100 // time to wait if key in used on set
-#define MAX_KEY_WAIT 500 // time to wait if key not ready on change
-
-#define FL_EVEN_GOOD 1
-#define FL_ODD_GOOD 2
-#define FL_ACTIVITY 4
-
-class cDeCSA {
-private:
- int cs;
- unsigned char **range, *lastData;
- unsigned char pidmap[MAX_CSA_PIDS];
- void *keys[MAX_CSA_IDX];
- unsigned int even_odd[MAX_CSA_IDX], flags[MAX_CSA_IDX];
- cMutex mutex;
- cCondVar wait;
- cTimeMs stall;
- bool active;
- int cardindex;
- //
- bool GetKeyStruct(int idx);
- void ResetState(void);
-public:
- cDeCSA(int CardIndex);
- ~cDeCSA();
- bool Decrypt(unsigned char *data, int len, bool force);
- bool SetDescr(ca_descr_t *ca_descr, bool initial);
- bool SetCaPid(ca_pid_t *ca_pid);
- void SetActive(bool on);
- };
-
-cDeCSA::cDeCSA(int CardIndex)
-:stall(MAX_STALL_MS)
-{
- cardindex=CardIndex;
- cs=get_suggested_cluster_size();
- PRINTF(L_CORE_CSA,"%d: clustersize=%d rangesize=%d",cardindex,cs,cs*2+5);
- range=MALLOC(unsigned char *,(cs*2+5));
- memset(keys,0,sizeof(keys));
- memset(pidmap,0,sizeof(pidmap));
- ResetState();
-}
-
-cDeCSA::~cDeCSA()
-{
- for(int i=0; i<MAX_CSA_IDX; i++)
- if(keys[i]) free_key_struct(keys[i]);
- free(range);
-}
-
-void cDeCSA::ResetState(void)
-{
- PRINTF(L_CORE_CSA,"%d: reset state",cardindex);
- memset(even_odd,0,sizeof(even_odd));
- memset(flags,0,sizeof(flags));
- lastData=0;
-}
-
-void cDeCSA::SetActive(bool on)
-{
- if(!on && active) ResetState();
- active=on;
- PRINTF(L_CORE_CSA,"%d: set active %s",cardindex,active?"on":"off");
-}
-
-bool cDeCSA::GetKeyStruct(int idx)
-{
- if(!keys[idx]) keys[idx]=get_key_struct();
- return keys[idx]!=0;
-}
-
-bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
-{
- cMutexLock lock(&mutex);
- int idx=ca_descr->index;
- if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) {
- if(!initial && active && ca_descr->parity==(even_odd[idx]&0x40)>>6) {
- if(flags[idx] & (ca_descr->parity?FL_ODD_GOOD:FL_EVEN_GOOD)) {
- PRINTF(L_CORE_CSA,"%d.%d: %s key in use (%d ms)",cardindex,idx,ca_descr->parity?"odd":"even",MAX_REL_WAIT);
- if(wait.TimedWait(mutex,MAX_REL_WAIT)) PRINTF(L_CORE_CSA,"%d.%d: successfully waited for release",cardindex,idx);
- else PRINTF(L_CORE_CSA,"%d.%d: timed out. setting anyways",cardindex,idx);
- }
- else PRINTF(L_CORE_CSA,"%d.%d: late key set...",cardindex,idx);
- }
- LDUMP(L_CORE_CSA,ca_descr->cw,8,"%d.%d: %4s key set",cardindex,idx,ca_descr->parity?"odd":"even");
- if(ca_descr->parity==0) {
- set_even_control_word(keys[idx],ca_descr->cw);
- if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_EVEN_GOOD|FL_ACTIVITY;
- else PRINTF(L_CORE_CSA,"%d.%d: zero even CW",cardindex,idx);
- wait.Broadcast();
- }
- else {
- set_odd_control_word(keys[idx],ca_descr->cw);
- if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_ODD_GOOD|FL_ACTIVITY;
- else PRINTF(L_CORE_CSA,"%d.%d: zero odd CW",cardindex,idx);
- wait.Broadcast();
- }
- }
- return true;
-}
-
-bool cDeCSA::SetCaPid(ca_pid_t *ca_pid)
-{
- cMutexLock lock(&mutex);
- if(ca_pid->index<MAX_CSA_IDX && ca_pid->pid<MAX_CSA_PIDS) {
- pidmap[ca_pid->pid]=ca_pid->index;
- PRINTF(L_CORE_CSA,"%d.%d: set pid %04x",cardindex,ca_pid->index,ca_pid->pid);
- }
- return true;
-}
-
-bool cDeCSA::Decrypt(unsigned char *data, int len, bool force)
-{
- cMutexLock lock(&mutex);
- int r=-2, ccs=0, currIdx=-1;
- bool newRange=true;
- range[0]=0;
- len-=(TS_SIZE-1);
- int l;
- for(l=0; l<len; l+=TS_SIZE) {
- if(data[l]!=TS_SYNC_BYTE) { // let higher level cope with that
- PRINTF(L_CORE_CSA,"%d: garbage in TS buffer",cardindex);
- if(ccs) force=true; // prevent buffer stall
- break;
- }
- unsigned int ev_od=data[l+3]&0xC0;
- if(ev_od==0x80 || ev_od==0xC0) { // encrypted
- int idx=pidmap[((data[l+1]<<8)+data[l+2])&(MAX_CSA_PIDS-1)];
- if(currIdx<0 || idx==currIdx) { // same or no index
- currIdx=idx;
- if(ccs==0 && ev_od!=even_odd[idx]) {
- even_odd[idx]=ev_od;
- wait.Broadcast();
- PRINTF(L_CORE_CSA,"%d.%d: change to %s key",cardindex,idx,(ev_od&0x40)?"odd":"even");
- bool doWait=false;
- if(ev_od&0x40) {
- flags[idx]&=~FL_EVEN_GOOD;
- if(!(flags[idx]&FL_ODD_GOOD)) doWait=true;
- }
- else {
- flags[idx]&=~FL_ODD_GOOD;
- if(!(flags[idx]&FL_EVEN_GOOD)) doWait=true;
- }
- if(doWait) {
- PRINTF(L_CORE_CSA,"%d.%d: %s key not ready (%d ms)",cardindex,idx,(ev_od&0x40)?"odd":"even",MAX_KEY_WAIT);
- if(flags[idx]&FL_ACTIVITY) {
- flags[idx]&=~FL_ACTIVITY;
- if(wait.TimedWait(mutex,MAX_KEY_WAIT)) PRINTF(L_CORE_CSA,"%d.%d: successfully waited for key",cardindex,idx);
- else PRINTF(L_CORE_CSA,"%d.%d: timed out. proceeding anyways",cardindex,idx);
- }
- else PRINTF(L_CORE_CSA,"%d.%d: not active. wait skipped",cardindex,idx);
- }
- }
- if(newRange) {
- r+=2; newRange=false;
- range[r]=&data[l];
- range[r+2]=0;
- }
- range[r+1]=&data[l+TS_SIZE];
- if(++ccs>=cs) break;
- }
- else newRange=true; // other index, create hole
- }
- else { // unencrypted
- // nothing, we don't create holes for unencrypted packets
- }
- }
- int scanTS=l/TS_SIZE;
- int stallP=ccs*100/scanTS;
-
- LBSTART(L_CORE_CSAVERB);
- LBPUT("%d: %s-%d-%d : %d-%d-%d stall=%d :: ",
- cardindex,data==lastData?"SAME":"MOVE",(len+(TS_SIZE-1))/TS_SIZE,force,
- currIdx,ccs,scanTS,stallP);
- for(int l=0; l<len; l+=TS_SIZE) {
- if(data[l]!=TS_SYNC_BYTE) break;
- unsigned int ev_od=data[l+3]&0xC0;
- if(ev_od&0x80) {
- int pid=(data[l+1]<<8)+data[l+2];
- int idx=pidmap[pid&(MAX_CSA_PIDS-1)];
- LBPUT("%s/%x/%d ",(ev_od&0x40)?"o":"e",pid,idx);
- }
- else {
- LBPUT("*/%x ",(data[l+1]<<8)+data[l+2]);
- }
- }
- LBEND();
-
- if(r>=0 && ccs<cs && !force) {
- if(lastData==data && stall.TimedOut()) {
- PRINTF(L_CORE_CSAVERB,"%d: stall timeout -> forced",cardindex);
- force=true;
- }
- else if(stallP<=10 && scanTS>=cs) {
- PRINTF(L_CORE_CSAVERB,"%d: flow factor stall -> forced",cardindex);
- force=true;
- }
- }
- lastData=data;
-
- if(r>=0) { // we have some range
- if(ccs>=cs || force) {
- if(GetKeyStruct(currIdx)) {
- int n=decrypt_packets(keys[currIdx],range);
- PRINTF(L_CORE_CSAVERB,"%d.%d: decrypting ccs=%3d cs=%3d %s -> %3d decrypted",cardindex,currIdx,ccs,cs,ccs>=cs?"OK ":"INC",n);
- if(n>0) {
- stall.Set(MAX_STALL_MS);
- return true;
- }
- }
- }
- else PRINTF(L_CORE_CSAVERB,"%d.%d: incomplete ccs=%3d cs=%3d",cardindex,currIdx,ccs,cs);
- }
- return false;
-}
-
// -- cDeCsaTSBuffer -----------------------------------------------------------
class cDeCsaTSBuffer : public cThread {
return NULL;
}
-#endif //SASC
-
// --- cScDeviceProbe ----------------------------------------------------------
#define DEV_DVB_ADAPTER "/dev/dvb/adapter"
void cScDevices::OnPluginLoad(void)
{
#if APIVERSNUM >= 10711
+ PRINTF(L_GEN_DEBUG,"using new 1.7.11+ capture code");
cScDeviceProbe::Install();
#else
+ PRINTF(L_GEN_DEBUG,"using old pre1.7.11 capture code");
/*
This is an extremly ugly hack to access VDRs device scan parameters, which are
protected in this context. Heavily dependant on the actual symbol names
:cDvbDevice(Adapter)
#endif
{
-#ifndef SASC
- decsa=0; tsBuffer=0; cam=0; fullts=false;
- ciadapter=0; hwciadapter=0;
+ tsBuffer=0; softcsa=fullts=false;
+ cam=0; hwciadapter=0;
fd_ca=cafd; fd_ca2=dup(fd_ca); fd_dvr=-1;
- softcsa=(fd_ca<0);
-#else
- softcsa=fullts=false;
+#ifdef SASC
cam=new cCam(this,Adapter);
#endif // !SASC
+#if APIVERSNUM >= 10711
+ snprintf(devId,sizeof(devId),"%d/%d",Adapter,FrontEnd);
+#else
+ snprintf(devId,sizeof(devId),"%d",Adapter);
+#endif
}
cScDevice::~cScDevice()
DetachAllReceivers();
Cancel(3);
EarlyShutdown();
- delete decsa;
if(fd_ca>=0) close(fd_ca);
if(fd_ca2>=0) close(fd_ca2);
#else
void cScDevice::EarlyShutdown(void)
{
SetCamSlot(0);
- delete ciadapter; ciadapter=0;
- delete hwciadapter; hwciadapter=0;
- if(cam) cam->Stop();
delete cam; cam=0;
+ delete hwciadapter; hwciadapter=0;
}
void cScDevice::LateInit(void)
int n=CardIndex();
if(DeviceNumber()!=n)
PRINTF(L_GEN_ERROR,"CardIndex - DeviceNumber mismatch! Put SC plugin first on VDR commandline!");
+ softcsa=(fd_ca<0);
if(softcsa) {
- if(HasDecoder()) PRINTF(L_GEN_ERROR,"Card %d is a full-featured card but no ca device found!",n);
+ if(HasDecoder()) PRINTF(L_GEN_ERROR,"Card %s is a full-featured card but no ca device found!",devId);
}
else if(cScDevices::ForceBudget(n)) {
- PRINTF(L_GEN_INFO,"Budget mode forced on card %d",n);
+ PRINTF(L_GEN_INFO,"Budget mode forced on card %s",devId);
softcsa=true;
}
-
- if(fd_ca2>=0) hwciadapter=cDvbCiAdapter::CreateCiAdapter(this,fd_ca2);
- cam=new cCam(this,n);
- ciadapter=new cScCiAdapter(this,n,cam);
if(softcsa) {
- decsa=new cDeCSA(n);
if(IsPrimaryDevice() && HasDecoder()) {
- PRINTF(L_GEN_INFO,"Enabling hybrid full-ts mode on card %d",n);
+ PRINTF(L_GEN_INFO,"Enabling hybrid full-ts mode on card %s",devId);
fullts=true;
}
- else PRINTF(L_GEN_INFO,"Using software decryption on card %d",n);
+ else PRINTF(L_GEN_INFO,"Using software decryption on card %s",devId);
}
+ if(fd_ca2>=0) hwciadapter=cDvbCiAdapter::CreateCiAdapter(this,fd_ca2);
+ cam=new cCam(this,DVB_DEV_SPEC,devId,fd_ca,softcsa,fullts);
}
bool cScDevice::HasCi(void)
{
- return ciadapter || hwciadapter;
+ return cam || hwciadapter;
}
bool cScDevice::Ready(void)
{
- return (ciadapter ? ciadapter->Ready():true) &&
+ return (cam ? cam->Ready():true) &&
(hwciadapter ? hwciadapter->Ready():true);
}
bool cScDevice::ScActive(void)
{
- return dynamic_cast<cScCamSlot *>(CamSlot())!=0;
+ return cam && cam->OwnSlot(CamSlot());
}
bool cScDevice::OpenDvr(void)
CloseDvr();
fd_dvr=cScDevices::DvbOpen(DEV_DVB_DVR,DVB_DEV_SPEC,O_RDONLY|O_NONBLOCK,true);
if(fd_dvr>=0) {
+ cDeCSA *decsa=cam ? cam->DeCSA() : 0;
tsMutex.Lock();
tsBuffer=new cDeCsaTSBuffer(fd_dvr,MEGABYTE(ScSetup.DeCsaTsBuffSize),CardIndex()+1,decsa,ScActive());
tsMutex.Unlock();
}
#endif // !SASC
-
-bool cScDevice::SoftCSA(bool live)
-{
- return softcsa && (!fullts || !live);
-}
-
-void cScDevice::CaidsChanged(void)
-{
-#ifndef SASC
- if(ciadapter) ciadapter->CaidsChanged();
- PRINTF(L_CORE_CAIDS,"caid list rebuild triggered");
-#endif // !SASC
-}
-
-bool cScDevice::SetCaDescr(ca_descr_t *ca_descr, bool initial)
-{
-#ifndef SASC
- if(!softcsa || (fullts && ca_descr->index==0)) {
- cMutexLock lock(&cafdMutex);
- return ioctl(fd_ca,CA_SET_DESCR,ca_descr)>=0;
- }
- else if(decsa) return decsa->SetDescr(ca_descr,initial);
-#endif // !SASC
- return false;
-}
-
-bool cScDevice::SetCaPid(ca_pid_t *ca_pid)
-{
-#ifndef SASC
- if(!softcsa || (fullts && ca_pid->index==0)) {
- cMutexLock lock(&cafdMutex);
- return ioctl(fd_ca,CA_SET_PID,ca_pid)>=0;
- }
- else if(decsa) return decsa->SetCaPid(ca_pid);
-#endif // !SASC
- return false;
-}
-
-int cScDevice::FilterHandle(void)
-{
- return cScDevices::DvbOpen(DEV_DVB_DEMUX,DVB_DEV_SPEC,O_RDWR|O_NONBLOCK);
-}
-
-#ifndef SASC
-static unsigned int av7110_read(int fd, unsigned int addr)
-{
- ca_pid_t arg;
- arg.pid=addr;
- ioctl(fd,CA_GET_MSG,&arg);
- return arg.index;
-}
-#endif // !SASC
-
-#if 0
-static void av7110_write(int fd, unsigned int addr, unsigned int val)
-{
- ca_pid_t arg;
- arg.pid=addr;
- arg.index=val;
- ioctl(fd,CA_SEND_MSG,&arg);
-}
-#endif
-
-void cScDevice::DumpAV7110(void)
-{
-#ifndef SASC
- if(LOG(L_CORE_AV7110)) {
-#define CODEBASE (0x2e000404+0x1ce00)
- cMutexLock lock(&cafdMutex);
- if(HasDecoder() && lastDump.Elapsed()>20000) {
- lastDump.Set();
- static unsigned int handles=0, hw_handles=0;
- static const unsigned int code[] = {
- 0xb5100040,0x4a095a12,0x48094282,0xd00b4b09,0x20000044,
- 0x5b1c4294,0xd0033001,0x281cdbf8,0xe001f7fe,0xfd14bc10
- };
- static const unsigned int mask[] = {
- 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
- 0xffffffff,0xffffffff,0xffffffff,0xfffff800,0xf800ffff
- };
- if(!handles) {
- handles=1;
- PRINTF(L_CORE_AV7110,"searching handle tables");
- for(int i=0; i<0x2000; i+=4) {
- int j;
- for(j=0; j<20; j+=4) {
- int r=av7110_read(fd_ca,CODEBASE+i+j);
- if((r&mask[j/4])!=(code[j/4]&mask[j/4])) break;
- }
- if(j==20) {
- handles=av7110_read(fd_ca,CODEBASE+i+44);
- hw_handles=av7110_read(fd_ca,CODEBASE+i+52);
- PRINTF(L_CORE_AV7110,"found handles=%08x hw_handles=%08x at 0x%08x",handles,hw_handles,CODEBASE+i);
- if((handles>>16)!=0x2e08 || (hw_handles>>16)!=0x2e08) {
- PRINTF(L_CORE_AV7110,"seems to be invalid");
- }
- break;
- }
- }
- }
-
- unsigned int hdl=0, hwhdl=0;
- PRINTF(L_CORE_AV7110," : 64000080 64000400");
- for(int i=0; i<=31; i++) {
- unsigned int off80 =av7110_read(fd_ca,0x64000080+i*4);
- unsigned int off400=av7110_read(fd_ca,0x64000400+i*8);
- LBSTART(L_CORE_AV7110);
- LBPUT("handle %2d: %08x %08x %s pid=%04x idx=%d",
- i,off80,off400,off80&0x2000?"ACT":"---",off80&0x1fff,(off400&0x1e)>>1);
- if(handles>1 && i<=27) {
- if((i&1)==0) {
- hdl=av7110_read(fd_ca,handles+i*2);
- hwhdl=av7110_read(fd_ca,hw_handles+i*2);
- }
- unsigned int s=((~i)&1)<<4;
- LBPUT(" | %02d hdl=%04x hwfilt=%04x",i,(hdl>>s)&0xffff,(hwhdl>>s)&0xffff);
- }
- LBEND();
- }
- }
- }
-#endif // !SASC
-}
#ifndef ___DEVICE_H
#define ___DEVICE_H
-#include <linux/dvb/ca.h>
#include <vdr/dvbdevice.h>
#include <vdr/thread.h>
-#include "misc.h"
-
-typedef int caid_t;
class cCam;
class cDeCSA;
// ----------------------------------------------------------------
-class cCaDescr {
-private:
- unsigned char *descr;
- int len;
-public:
- cCaDescr(void);
- cCaDescr(const cCaDescr &arg);
- ~cCaDescr();
- const unsigned char *Get(int &l) const;
- void Set(const cCaDescr *d);
- void Set(const unsigned char *de, int l);
- void Clear(void);
- bool operator== (const cCaDescr &arg) const;
- void Join(const cCaDescr *cd, bool rev=false);
- cString ToString(void);
- };
-
-// ----------------------------------------------------------------
-
-class cPrgPid : public cSimpleItem {
-private:
- bool proc;
-public:
- int type, pid;
- cCaDescr caDescr;
- //
- cPrgPid(int Type, int Pid) { type=Type; pid=Pid; proc=false; }
- bool Proc(void) const { return proc; }
- void Proc(bool is) { proc=is; };
- };
-
-// ----------------------------------------------------------------
-
-class cPrg : public cSimpleItem {
-private:
- bool isUpdate, pidCaDescr;
- //
- void Setup(void);
-public:
- int sid, source, transponder;
- cSimpleList<cPrgPid> pids;
- cCaDescr caDescr;
- //
- cPrg(void);
- cPrg(int Sid, bool IsUpdate);
- bool IsUpdate(void) const { return isUpdate; }
- bool HasPidCaDescr(void) const { return pidCaDescr; }
- void SetPidCaDescr(bool val) { pidCaDescr=val; }
- bool SimplifyCaDescr(void);
- void DumpCaDescr(int c);
- };
-
-// ----------------------------------------------------------------
-
class cScDevices : public cDvbDevice {
private:
static int budget;
class cScDevice : public cDvbDevice {
friend class cScDevices;
private:
- cDeCSA *decsa;
cDeCsaTSBuffer *tsBuffer;
cMutex tsMutex;
- cScCiAdapter *ciadapter;
- cCiAdapter *hwciadapter;
cCam *cam;
+ cCiAdapter *hwciadapter;
int fd_dvr, fd_ca, fd_ca2;
bool softcsa, fullts;
- cMutex cafdMutex;
- cTimeMs lastDump;
+ char devId[8];
//
#ifndef SASC
void LateInit(void);
#ifndef SASC
virtual bool HasCi(void);
#endif //SASC
- virtual bool SetCaDescr(ca_descr_t *ca_descr, bool initial);
- virtual bool SetCaPid(ca_pid_t *ca_pid);
- int FilterHandle(void);
- void DumpAV7110(void);
- cCam *Cam(void) { return cam; }
- bool SoftCSA(bool live);
- void CaidsChanged(void);
};
#endif // ___DEVICE_H
#include <linux/dvb/dmx.h>
+#include <vdr/device.h>
#include <vdr/tools.h>
#include "filter.h"
-#include "sc.h"
#include "misc.h"
#include "log-core.h"
// -- cPidFilter ------------------------------------------------------------------
-cPidFilter::cPidFilter(const char *Id, int Num, int DvbNum, unsigned int IdleTime)
+cPidFilter::cPidFilter(const char *Id, int Num, cDevice *Device, unsigned int IdleTime)
{
- dvbNum=DvbNum;
+ device=Device;
idleTime=IdleTime;
- id=0; fd=-1; active=false; forceRun=false; userData=0;
+ id=0; fd=-1; forceRun=false; userData=0;
id=bprintf("%s/%d",Id,Num);
- PRINTF(L_CORE_ACTION,"new filter '%s' on card %d (%d ms)",id,dvbNum,idleTime);
+ PRINTF(L_CORE_ACTION,"new filter '%s' (%d ms)",id,idleTime);
}
cPidFilter::~cPidFilter()
{
cMutexLock lock(this);
- if(fd>=0) {
- Stop();
- close(fd);
- }
- PRINTF(L_CORE_ACTION,"filter '%s' on card %d removed",id,dvbNum);
+ Stop();
+ PRINTF(L_CORE_ACTION,"filter '%s' removed",id);
free(id);
}
-bool cPidFilter::Open(void)
-{
- cMutexLock lock(this);
- if(fd<0) {
- fd=cSoftCAM::FilterHandle(dvbNum);
- if(fd>=0) return true;
- }
- return false;
-}
-
void cPidFilter::Flush(void)
{
cMutexLock lock(this);
}
}
-void cPidFilter::Start(int Pid, int Section, int Mask, int Mode, bool Crc)
+void cPidFilter::Start(int Pid, int Section, int Mask)
{
cMutexLock lock(this);
+ Stop();
+ fd=device->OpenFilter(Pid,Section,Mask);
if(fd>=0) {
- Stop();
- struct dmx_sct_filter_params FilterParams;
- memset(&FilterParams,0,sizeof(FilterParams));
- FilterParams.filter.filter[0]=Section;
- FilterParams.filter.mask[0]=Mask;
- FilterParams.filter.mode[0]=Mode;
- FilterParams.flags=DMX_IMMEDIATE_START;
- if(Crc) FilterParams.flags|=DMX_CHECK_CRC;
- FilterParams.pid=Pid;
- if(ioctl(fd,DMX_SET_FILTER,&FilterParams)<0) {
- PRINTF(L_GEN_ERROR,"filter '%s': DMX_SET_FILTER failed: %s",id,strerror(errno));
- return;
- }
pid=Pid;
- active=true;
LBSTART(L_CORE_ACTION);
- LBPUT("filter '%s' -> pid=0x%04x sct=0x%02x/0x%02x/0x%02x crc=%d matching",id,Pid,Section,Mask,Mode,Crc);
+ LBPUT("filter '%s' -> pid=0x%04x sct=0x%02x/0x%02x matching",id,Pid,Section,Mask);
+ int Mode=0;
int mam =Mask & (~Mode);
int manm=Mask & ~(~Mode);
for(int i=0; i<256; i++) {
void cPidFilter::Stop(void)
{
cMutexLock lock(this);
- if(fd>=0) {
- CHECK(ioctl(fd,DMX_STOP));
- active=false;
- }
+ if(fd>=0) { device->CloseFilter(fd); fd=-1; }
}
void cPidFilter::SetBuffSize(int BuffSize)
int cPidFilter::Pid(void)
{
- return active ? pid : -1;
+ return Active() ? pid : -1;
}
// -- cAction ------------------------------------------------------------------
-cAction::cAction(const char *Id, int DvbNum)
+cAction::cAction(const char *Id, cDevice *Device, const char *DevId)
{
- id=bprintf("%s %d",Id,DvbNum);
- dvbNum=DvbNum;
+ device=Device; devId=DevId;
+ id=bprintf("%s %s",Id,DevId);
unique=0; pri=-1;
SetDescription("%s filter",id);
}
free(id);
}
-cPidFilter *cAction::CreateFilter(const char *Id, int Num, int DvbNum, int IdleTime)
+cPidFilter *cAction::CreateFilter(int Num, int IdleTime)
{
- return new cPidFilter(Id,Num,DvbNum,IdleTime);
+ return new cPidFilter(id,Num,device,IdleTime);
}
cPidFilter *cAction::NewFilter(int IdleTime)
{
Lock();
- cPidFilter *filter=CreateFilter(id,unique++,dvbNum,IdleTime);
- if(filter && filter->Open()) {
+ cPidFilter *filter=CreateFilter(unique++,IdleTime);
+ if(filter) {
if(!Active()) {
Start();
PRINTF(L_CORE_ACTION,"%s: started",id);
}
filters.Add(filter);
}
- else {
- PRINTF(L_CORE_ACTION,"%s: filter '%s' failed to open",id,filter?filter->id:"XxX");
- delete filter;
- filter=0;
- }
+ else
+ PRINTF(L_CORE_ACTION,"%s: failed to create filter",id);
Unlock();
return filter;
}
}
int num=0;
cPidFilter *filter;
- for(filter=filters.First(); filter; filter=filters.Next(filter)) {
- memset(&pfd[num],0,sizeof(struct pollfd));
- pfd[num].fd=filter->fd;
- pfd[num].events=POLLIN;
- num++;
- }
+ for(filter=filters.First(); filter; filter=filters.Next(filter))
+ if(filter->Active()) {
+ memset(&pfd[num],0,sizeof(struct pollfd));
+ pfd[num].fd=filter->fd;
+ pfd[num].events=POLLIN;
+ num++;
+ }
Unlock();
// now poll for data
unsigned char buff[MAX_SECT_SIZE];
int n=read(filter->fd,buff,sizeof(buff));
if(n<0 && errno!=EAGAIN) {
- if(errno==EOVERFLOW) PRINTF(L_GEN_ERROR,"action %s read: Buffer overflow",filter->id);
+ if(errno==EOVERFLOW) {
+ filter->Flush();
+ //PRINTF(L_GEN_ERROR,"action %s read: Buffer overflow",filter->id);
+ }
else PRINTF(L_GEN_ERROR,"action %s read: %s",filter->id,strerror(errno));
}
if(n>0) {
#include <vdr/thread.h>
#include "misc.h"
+class cDevice;
class cPidFilter;
// ----------------------------------------------------------------
class cAction : protected cThread {
private:
- char *id;
- int dvbNum, unique, pri;
+ const char *devId;
+ int unique, pri;
cSimpleList<cPidFilter> filters;
protected:
+ cDevice *device;
+ char *id;
+ //
virtual void Process(cPidFilter *filter, unsigned char *data, int len)=0;
virtual void Action(void);
- virtual cPidFilter *CreateFilter(const char *Id, int Num, int DvbNum, int IdleTime);
+ virtual cPidFilter *CreateFilter(int Num, int IdleTime);
//
cPidFilter *NewFilter(int IdleTime);
cPidFilter *IdleFilter(void);
void DelAllFilter(void);
void Priority(int Pri);
public:
- cAction(const char *Id, int DvbNum);
+ cAction(const char *Id, cDevice *Device, const char *DevId);
virtual ~cAction();
};
class cPidFilter : public cSimpleItem, private cMutex {
friend class cAction;
private:
- int dvbNum;
+ cDevice *device;
unsigned int idleTime;
cTimeMs lastTime;
bool forceRun;
- //
- bool Open(void);
protected:
char *id;
int fd;
int pid;
- bool active;
public:
void *userData;
//
- cPidFilter(const char *Id, int Num, int DvbNum, unsigned int IdleTime);
+ cPidFilter(const char *Id, int Num, cDevice *Device, unsigned int IdleTime);
virtual ~cPidFilter();
void Flush(void);
- virtual void Start(int Pid, int Section, int Mask, int Mode, bool Crc);
+ virtual void Start(int Pid, int Section, int Mask);
void Stop(void);
- void Wakeup(void);
void SetBuffSize(int BuffSize);
+ void Wakeup(void);
int SetIdleTime(unsigned int IdleTime);
int Pid(void);
- bool Active(void) { return active; }
+ bool Active(void) { return fd>=0; }
};
#endif //___FILTER_H
--- /dev/null
+/*
+ * Softcam plugin to VDR (C++)
+ *
+ * This code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef ___GLOBAL_H
+#define ___GLOBAL_H
+
+// ----------------------------------------------------------------
+
+class cGlobal {
+public:
+ static bool Active(bool log);
+ static void HouseKeeping(void);
+ static char *CurrKeyStr(int cardindex, int num, const char **id);
+ static void CaidsChanged(void);
+ };
+
+#endif // ___GLOBAL_H
#include <vdr/sources.h>
#include "override.h"
-#include "sc.h"
+#include "global.h"
#include "misc.h"
#include "log-core.h"
void cOverrides::PostLoad(void)
{
- if(caidTrigger) cSoftCAM::CaidsChanged();
+ if(caidTrigger) cGlobal::CaidsChanged();
}
cOverride *cOverrides::ParseLine(char *line)
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2007-08-27 12:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(keiner)"
+
msgid "Key update"
msgstr "Key Update"
msgid "Active! Can't reload files now"
msgstr "Aktiv! Kann Dateien jetzt nicht neu laden"
-msgid "(none)"
-msgstr "(keiner)"
-
msgid "active CAIDs"
msgstr "aktive CAIDs"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2008-11-19 13:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(ei)"
+
msgid "Key update"
msgstr "Avaimen päivitys"
msgid "Active! Can't reload files now"
msgstr "Aktiivinen! Uudelleen lataus ei onnistu"
-msgid "(none)"
-msgstr "(ei)"
-
msgid "active CAIDs"
msgstr "aktiiviset CAID:t"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2007-08-27 12:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(aucune)"
+
msgid "Key update"
msgstr "Mise à jour des clés"
msgid "Active! Can't reload files now"
msgstr "Actif! Impossible de recharger les fichiers"
-msgid "(none)"
-msgstr "(aucune)"
-
msgid "active CAIDs"
msgstr "CAIDs actifs"
msgstr ""
"Project-Id-Version: VDR 1.5.11\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2009-05-17 11:09+0800\n"
"Last-Translator: jv\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(nincs)"
+
msgid "Key update"
msgstr ""
msgid "Active! Can't reload files now"
msgstr "SC aktív! Nem tud újraolvasni."
-msgid "(none)"
-msgstr "(nincs)"
-
msgid "active CAIDs"
msgstr "aktív CAIDok"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2008-11-19 12:23+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(nessuna)"
+
msgid "Key update"
msgstr "Aggiornamento chiavi"
msgid "Active! Can't reload files now"
msgstr "Chiave in uso! Impossibile ricaricare adesso"
-msgid "(none)"
-msgstr "(nessuna)"
-
msgid "active CAIDs"
msgstr "CAIDs attivi"
msgstr ""
"Project-Id-Version: VDR 1.7.10\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2007-08-27 12:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(nėra)"
+
msgid "Key update"
msgstr "Raktų atnaujinimas"
msgid "Active! Can't reload files now"
msgstr "Servisas aktyvus! Dabar negali perkrauti failų"
-msgid "(none)"
-msgstr "(nėra)"
-
msgid "active CAIDs"
msgstr "aktyvūs CAIDai"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2007-08-27 12:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-15\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(geen)"
+
msgid "Key update"
msgstr ""
msgid "Active! Can't reload files now"
msgstr "Actief! Kan bestanden niet herladen"
-msgid "(none)"
-msgstr "(geen)"
-
msgid "active CAIDs"
msgstr "actieve CAIDS"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2007-08-27 12:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(brak)"
+
msgid "Key update"
msgstr ""
msgid "Active! Can't reload files now"
msgstr "Aktywny! Nie mo¿na teraz prze³adowaæ plików."
-msgid "(none)"
-msgstr "(brak)"
-
msgid "active CAIDs"
msgstr "aktywne CAID"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2009-05-14 19:33+0100\n"
"Last-Translator: somebody\n"
"Language-Team: ru\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
+msgid "(none)"
+msgstr "(ÝÕâ)"
+
msgid "Key update"
msgstr "¾ÑÝÞÒÛÕÝØÕ ÚÛîçÐ"
msgid "Active! Can't reload files now"
msgstr "·ÐÝïâ! ½Õ ÜÞÓã ßÕàÕ×ÐÓàãרâì äÐÙÛë"
-msgid "(none)"
-msgstr "(ÝÕâ)"
-
msgid "active CAIDs"
msgstr "ÐÚâØÒÝëÕ CAID"
msgstr ""
"Project-Id-Version: VDR 1.5.9\n"
"Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
"PO-Revision-Date: 2007-08-27 12:45+0200\n"
"Last-Translator: somebody\n"
"Language-Team: somebody\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "(none)"
+msgstr "(ingen)"
+
msgid "Key update"
msgstr ""
msgid "Active! Can't reload files now"
msgstr "Aktiv! Kan inte ladda om filer nu"
-msgid "(none)"
-msgstr "(ingen)"
-
msgid "active CAIDs"
msgstr "aktiva CAID"
#include <vdr/tools.h>
#include <vdr/config.h>
-#include "sc.h"
#include "scsetup.h"
#include "filter.h"
#include "system.h"
#include "cam.h"
+#include "global.h"
#include "device.h"
#include "smartcard.h"
#include "data.h"
}
}
+// --- cSoftCAM ---------------------------------------------------------------
+
+class cSoftCAM {
+public:
+ static bool Load(const char *cfgdir);
+ static void Shutdown(void);
+ };
+
+bool cSoftCAM::Load(const char *cfgdir)
+{
+ if(!Feature.KeyFile()) keys.Disable();
+ if(!Feature.SmartCard()) smartcards.Disable();
+ cStructLoaders::Load(false);
+ if(Feature.KeyFile() && keys.Count()<1)
+ PRINTF(L_GEN_ERROR,"no keys loaded for softcam!");
+ if(!cSystems::Init(cfgdir)) return false;
+ srand(time(0));
+ return true;
+}
+
+void cSoftCAM::Shutdown(void)
+{
+ cStructLoaders::Save(true);
+ cSystems::Clean();
+ smartcards.Shutdown();
+ keys.SafeClear();
+}
+
// --- cMenuInfoSc -------------------------------------------------------------
class cMenuInfoSc : public cOsdMenu {
:cOsdMenu(tr("SoftCAM"),25)
{
Add(new cScInfoItem(tr("Current keys:")));
- for(int d=0; d<MAXDVBDEVICES; d++) {
- int n=0;
+ int d=0, n;
+ do {
+ n=0;
char *ks;
do {
- if((ks=cSoftCAM::CurrKeyStr(d,n))) {
+ const char *id;
+ if((ks=cGlobal::CurrKeyStr(d,n,&id))) {
char buffer[32];
- snprintf(buffer,sizeof(buffer)," [%s %d:%d]","DVB",d+1,n+1);
+ snprintf(buffer,sizeof(buffer)," [%s.%d]",id,n);
Add(new cScInfoItem(buffer,ks));
free(ks);
+ n++;
}
- n++;
} while(ks);
- }
+ d++;
+ } while(n>0);
if(Feature.KeyFile()) {
Add(new cScInfoItem(tr("Key update status:")));
int fk, nk;
case osUser9:
state=osContinue;
- if(!cSoftCAM::Active(true)) {
+ if(!cGlobal::Active(true)) {
if(Interface->Confirm(tr("Really reload files?"))) {
Store();
cSoftCAM::Load(cfgdir);
return false;
}
-// --- cSoftCAM ---------------------------------------------------------------
-
-bool cSoftCAM::Load(const char *cfgdir)
-{
- if(!Feature.KeyFile()) keys.Disable();
- if(!Feature.SmartCard()) smartcards.Disable();
- cStructLoaders::Load(false);
- if(Feature.KeyFile() && keys.Count()<1)
- PRINTF(L_GEN_ERROR,"no keys loaded for softcam!");
- if(!cSystems::Init(cfgdir)) return false;
- srand(time(0));
- return true;
-}
-
-void cSoftCAM::Shutdown(void)
-{
- cStructLoaders::Save(true);
- cSystems::Clean();
- smartcards.Shutdown();
- keys.SafeClear();
-}
-
-char *cSoftCAM::CurrKeyStr(int CardNum, int num)
-{
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
- char *str=0;
- if(dev) {
- if(dev->Cam()) str=dev->Cam()->CurrentKeyStr(num);
- if(!str && num==0 && ScSetup.CapCheck(CardNum)) str=strdup(tr("(none)"));
- }
- return str;
-}
-
-bool cSoftCAM::Active(bool log)
-{
- for(int n=cDevice::NumDevices(); --n>=0;) {
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
- if(dev && dev->Cam() && dev->Cam()->Active(log)) return true;
- }
- return false;
-}
-
-void cSoftCAM::SetLogStatus(int CardNum, const cEcmInfo *ecm, bool on)
-{
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
- if(dev && dev->Cam()) dev->Cam()->LogEcmStatus(ecm,on);
-}
-
-void cSoftCAM::AddHook(int CardNum, cLogHook *hook)
-{
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
- if(dev && dev->Cam()) dev->Cam()->AddHook(hook);
-}
-
-bool cSoftCAM::TriggerHook(int CardNum, int id)
-{
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
- return dev && dev->Cam() && dev->Cam()->TriggerHook(id);
-}
-
-void cSoftCAM::CaidsChanged(void)
-{
- for(int n=cDevice::NumDevices(); --n>=0;) {
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
- if(dev) dev->CaidsChanged();
- }
-}
-
-int cSoftCAM::FilterHandle(int CardNum)
-{
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
- return dev ? dev->FilterHandle() : -1;
-}
-
// --- cScHousekeeper ----------------------------------------------------------
class cScHousekeeper : public cThread {
while(Running()) {
if(++c==20) {
c=0;
- for(int n=cDevice::NumDevices(); --n>=0;) {
- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
- if(dev && dev->Cam()) dev->Cam()->HouseKeeping();
- }
+ cGlobal::HouseKeeping();
}
-
if(Feature.KeyFile()) keys.HouseKeeping();
- if(!cSoftCAM::Active(false)) cStructLoaders::Purge();
+ if(!cGlobal::Active(false)) cStructLoaders::Purge();
cStructLoaders::Load(true);
cStructLoaders::Save();
-
cCondWait::SleepMs(987);
}
}
cString cScPlugin::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
{
if(!strcasecmp(Command,"RELOAD")) {
- if(cSoftCAM::Active(true)) {
+ if(cGlobal::Active(true)) {
ReplyCode=550;
return "Softcam active. Can't reload files now";
}
+++ /dev/null
-/*
- * Softcam plugin to VDR (C++)
- *
- * This code is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef ___SC_H
-#define ___SC_H
-
-class cEcmInfo;
-class cLogHook;
-
-// ----------------------------------------------------------------
-
-class cSoftCAM {
-public:
- static bool Load(const char *cfgdir);
- static void Shutdown(void);
- //
- static bool Active(bool log);
- static char *CurrKeyStr(int CardNum, int num);
- static void SetLogStatus(int CardNum, const cEcmInfo *ecm, bool on);
- static void AddHook(int CardNum, cLogHook *hook);
- static bool TriggerHook(int CardNum, int id);
- static void CaidsChanged(void);
- static int FilterHandle(int CardNum);
- };
-
-#endif // ___SC_H
#include <vdr/thread.h>
#include "smartcard.h"
-#include "sc.h"
+#include "global.h"
#include "misc.h"
#include "log-core.h"
void cSmartCard::CaidsChanged(void)
{
- cSoftCAM::CaidsChanged();
+ cGlobal::CaidsChanged();
}
// -- cSmartCardLink -----------------------------------------------------------
#include <openssl/md5.h>
-#include "sc.h"
#include "system.h"
+#include "cam.h"
+#include "global.h"
#include "data.h"
#include "override.h"
#include "opts.h"
cSystem::cSystem(const char *Name, int Pri)
{
name=Name; pri=Pri;
- currentKeyStr[0]=0; doLog=true; cardNum=-1; logecm=0;
+ currentKeyStr[0]=0; doLog=true; cam=0; logecm=0;
check=new struct EcmCheck;
memset(check,0,sizeof(struct EcmCheck));
memset(cw,0,sizeof(cw));
cSystem::~cSystem()
{
delete check;
- if(logecm) cSoftCAM::SetLogStatus(cardNum,logecm,false);
+ if(logecm && cam) cam->LogEcmStatus(logecm,false);
delete logecm;
}
void cSystem::StartLog(const cEcmInfo *ecm, int caid)
{
if(!logecm || logecm->caId!=caid) {
- if(logecm) cSoftCAM::SetLogStatus(cardNum,logecm,false);
+ if(logecm && cam) cam->LogEcmStatus(logecm,false);
delete logecm;
logecm=new cEcmInfo(ecm);
logecm->caId=caid; logecm->emmCaId=0;
- cSoftCAM::SetLogStatus(cardNum,logecm,true);
+ if(cam) cam->LogEcmStatus(logecm,true);
}
}
+void cSystem::AddHook(cLogHook *hook)
+{
+ if(cam) cam->AddHook(hook);
+}
+
+bool cSystem::TriggerHook(int id)
+{
+ return cam && cam->TriggerHook(id);
+}
+
+void cSystem::CaidsChanged(void)
+{
+ cGlobal::CaidsChanged();
+}
+
void cSystem::ParseCADescriptor(cSimpleList<cEcmInfo> *ecms, unsigned short sysId, int source, const unsigned char *data, int len)
{
const int pid=WORD(data,2,0x1FFF);
}
break;
case 0x05: // Viaccess style (88/8c/8d/8e)
- pids->AddPid(pid,0x8B,0xFE,0x07); // mismatching 89/8f
+ pids->AddPid(pid,0x88,0xF9); // mismatching 8a
+ pids->AddPid(pid,0x8D,0xFF);
break;
case 0x0d: // Cryptoworks style (82/84/86/88/89)
- pids->AddPid(pid,0x80,0xFF,0x06);
+ pids->AddPid(pid,0x82,0xF9); // mismatching 80
pids->AddPid(pid,0x88,0xFE);
break;
case 0x18: // Nagra style (82/83)
class cLogger;
class cOpts;
class cHookManager;
+class cCam;
// ----------------------------------------------------------------
class cLogHook : public cSimpleItem {
friend class cHookManager;
private:
- int cardNum, id;
+// int cardNum, id;
+ int id;
const char *name;
cTimeMs delay;
bool bailOut;
friend class cKeySnoop;
private:
static int foundKeys, newKeys;
- int pri, cardNum;
+ int pri;
cLastKey lastkey;
char *lastTxt;
char currentKeyStr[48];
struct EcmCheck *check;
cEcmInfo *logecm;
+ cCam *cam;
protected:
const char *name;
unsigned char cw[16];
public:
cSystem(const char *Name, int Pri);
virtual ~cSystem();
+ void SetOwner(cCam *Cam) { cam=Cam; }
+ static void CaidsChanged(void);
+ //
virtual int CheckECM(const cEcmInfo *ecm, const unsigned char *data, bool sync);
virtual void CheckECMResult(const cEcmInfo *ecm, const unsigned char *data, bool result);
virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *buffer)=0;
virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer) {};
virtual void ParseCADescriptor(cSimpleList<cEcmInfo> *ecms, unsigned short sysId, int source, const unsigned char *data, int len);
virtual void ParseCAT(cPids *pids, const unsigned char *buffer, int source, int transponder);
+ //
+ void AddHook(cLogHook *hook);
+ bool TriggerHook(int id);
+ //
unsigned char *CW(void) { return cw; }
void DoLog(bool Log) { doLog=Log; }
int Pri(void) { return pri; }
const char *CurrentKeyStr(void) { return currentKeyStr; }
const char *Name(void) { return name; }
- int CardNum(void) { return cardNum; }
- void CardNum(int CardNum) { cardNum=CardNum; }
int MaxEcmTry(void) { return maxEcmTry; }
bool HasLogger(void) { return hasLogger; }
bool NeedsLogger(void) { return needsLogger; }
bool Local(void) { return local; }
bool NeedsData(void) { return needsDescrData; }
bool Constant(void) { return constant; }
+ //
static void FoundKey(void) { foundKeys++; }
static void NewKey(void) { newKeys++; }
static void KeyStats(int &fk, int &nk) { fk=foundKeys; nk=newKeys; }
cCardClientAroureos(const char *Name);
virtual bool Init(const char *config);
virtual bool Login(void);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
virtual bool ProcessEMM(int caSys, const unsigned char *source);
};
return false;
}
-bool cCardClientAroureos::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum)
+bool cCardClientAroureos::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
{
cMutexLock lock(this);
so.Flush();
virtual bool Init(const char *config);
virtual bool Login(void);
virtual bool Immediate(void);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
virtual bool ProcessEMM(int caSys, const unsigned char *source);
};
return false;
}
-bool cCardClientCommon::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum)
+bool cCardClientCommon::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
{
Lock();
bool res=false;
cCardClientCamd35(const char *Name);
virtual bool Init(const char *config);
virtual bool Login(void);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw);
virtual bool ProcessEMM(int caSys, const unsigned char *data);
};
return false;
}
-bool cCardClientCamd35::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+bool cCardClientCamd35::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
{
bool res=false;
const int length=SCT_LEN(data);
#include "system.h"
#include "cc.h"
-#include "sc.h"
#include "misc.h"
#include "opts.h"
#include "log-core.h"
void cCardClient::CaidsChanged(void)
{
- cSoftCAM::CaidsChanged();
+ cSystem::CaidsChanged();
}
bool cCardClient::ParseStdConfig(const char *config, int *num)
if(cc) {
cTimeMs start;
int id=cc->msECM.Get(data,SCT_LEN(data),cw);
- if(id==0 || (id>0 && cc->ProcessECM(ecm,data,cw,CardNum()))) {
+ if(id==0 || (id>0 && cc->ProcessECM(ecm,data,cw))) {
int dur=start.Elapsed();
if(dur>2000) {
char bb[32];
virtual bool Login(void)=0;
virtual bool Immediate(void);
virtual bool CanHandle(unsigned short SysId);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)=0;
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)=0;
virtual bool ProcessEMM(int caSys, const unsigned char *data) { return false; }
const char *Name(void) { return name; }
};
~cCardClientCCcam();\r
virtual bool Init(const char *CfgDir);\r
virtual bool Login(void);\r
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);\r
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);\r
};\r
\r
static cCardClientLinkReg<cCardClientCCcam> __ncd("cccam");\r
return true;\r
}\r
\r
-bool cCardClientCCcam::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)\r
+bool cCardClientCCcam::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)\r
{\r
cMutexLock lock(this);\r
if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;\r
\r
+ if(ecm->dvbAdapter<0 || ecm->dvbFrontend!=0) {\r
+ PRINTF(L_CC_CCCAM,"cannot handle DVB adapter %d, frontend %d",ecm->dvbAdapter,ecm->dvbFrontend);\r
+ return false;\r
+ }\r
+ int cardnum=ecm->dvbAdapter;\r
+\r
cCCcamCard *c=&card[cardnum];\r
int timeout=3000;\r
if(ecm->ecm_pid!=c->Pid() || !c->Connected()) { // channel change\r
virtual bool Init(const char *CfgDir);
virtual bool Login(void);
virtual bool CanHandle(unsigned short SysId);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
virtual bool ProcessEMM(int caSys, const unsigned char *data);
};
return true;
}
-bool cCardClientCCcam2::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum)
+bool cCardClientCCcam2::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw)
{
cMutexLock lock(this);
if(!so.Connected() && !Login()) { Logout(); return false; }
if(!CanHandle(ecm->caId)) return false;
- PRINTF(L_CC_CCCAM2,"%d: ECM caid %04x prov %04x sid %d pid %04x",cardnum,ecm->caId,ecm->provId,ecm->prgId,ecm->ecm_pid);
+ PRINTF(L_CC_CCCAM2,"ECM caid %04x prov %04x sid %d pid %04x",ecm->caId,ecm->provId,ecm->prgId,ecm->ecm_pid);
int sctlen=SCT_LEN(data);
if(sctlen>=256) {
PRINTF(L_CC_CCCAM2,"ECM data length >=256 not supported by CCcam");
cCardClientGbox(const char *Name);
virtual bool Init(const char *CfgDir);
virtual bool Login(void);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
};
static cCardClientLinkReg<cCardClientGbox> __ncd("gbox");
return n;
}
-bool cCardClientGbox::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+bool cCardClientGbox::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
{
cMutexLock lock(this);
if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
virtual bool Init(const char *CfgDir);
virtual bool Login(void);
virtual bool CanHandle(unsigned short SysId);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
virtual bool ProcessEMM(int caSys, const unsigned char *data);
};
return true;
}
-bool cCardClientNewCamd::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+bool cCardClientNewCamd::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
{
cMutexLock lock(this);
if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
virtual bool Init(const char *config);
virtual bool Login(void);
virtual bool CanHandle(unsigned short SysId);
- virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum);
+ virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
virtual bool ProcessEMM(int caSys, const unsigned char *data);
};
return true;
}
-bool cCardClientRadegast::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum)
+bool cCardClientRadegast::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
{
cMutexLock lock(this);
if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
int slen=buffer[index-1]-5; // save packet length, 5 signature bytes
int maxIndex=index+slen;
if(maxIndex>n-5) {
- PRINTF(L_SYS_EMM,"%d: bad packet length (%d > %d)",CardNum(),maxIndex,n-5);
+ PRINTF(L_SYS_EMM,"bad packet length (%d > %d)",maxIndex,n-5);
maxIndex=n-5;
}
bool badnano=false;
break;
default:
- PRINTF(L_SYS_EMM,"%d: unhandled nano 0x%02x",CardNum(),nano);
+ PRINTF(L_SYS_EMM,"unhandled nano 0x%02x",nano);
break;
}
index+=nlen+2;
}
if(badnano || index!=maxIndex) {
- PRINTF(L_SYS_EMM,"%d: bad nano/bad paket",CardNum());
+ PRINTF(L_SYS_EMM,"bad nano/bad paket");
return;
}
const int id=buffer[10]*256+buffer[11];
static const unsigned char tester[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x4B };
if(memcmp(&buffer[3],tester,sizeof(tester)) || SCT_LEN(buffer)<(12+9+64)) {
- PRINTF(L_SYS_EMM,"%d: not a valid EMM structure",CardNum());
+ PRINTF(L_SYS_EMM,"not a valid EMM structure");
return;
}
const int pkey=(buffer[12]&3);
const int romNr=emmdata[i]&0x0F;
if(!emu || !emu->Matches(romNr,id)) {
delete emu; emu=0;
- PRINTF(L_SYS_EMM,"%d: setting defaults for ROM %d",CardNum(),romNr);
+ PRINTF(L_SYS_EMM,"setting defaults for ROM %d",romNr);
switch(romNr) {
case 3: emu=new cEmuRom3; break;
case 7: emu=new cEmuRom7; break;
case 10: emu=new cEmuRom10; break;
case 11: emu=new cEmuRom11; break;
- default: PRINTF(L_SYS_EMM,"%d: unsupported ROM",CardNum()); return;
+ default: PRINTF(L_SYS_EMM,"unsupported ROM"); return;
}
if(!emu || !emu->Init(romNr,id)) {
delete emu; emu=0;
- PRINTF(L_SYS_EMM,"%d: initialization failed for ROM %d",CardNum(),romNr);
+ PRINTF(L_SYS_EMM,"initialization failed for ROM %d",romNr);
return;
}
}
unsigned char ki[2];
if((gotKeys=emu->GetOpKeys(emmdata,ki,key0,key1))) {
keyId=(ki[0]<<8)+ki[1];
- PRINTF(L_SYS_EMM,"%d: got keys for %04X (ROM %d)",CardNum(),keyId,romNr);
+ PRINTF(L_SYS_EMM,"got keys for %04X (ROM %d)",keyId,romNr);
}
unsigned char select[3], pkset[3][15];
select[0]=(keyId>>8)|0x01; // always high id for ECM RSA keys
select[2]=0; // type 0
if(emu->GetPkKeys(&select[0],&pkset[0][0])) {
int pkKeyId=((select[0]<<8)+select[1]);
- PRINTF(L_SYS_EMM,"%d: got PK keys for %04X (ROM %d)",CardNum(),pkKeyId,romNr);
+ PRINTF(L_SYS_EMM,"got PK keys for %04X (ROM %d)",pkKeyId,romNr);
for(int i=0; i<3; i++) {
CreateRSAPair(pkset[i],0,e1,n1);
FoundKey();
i+=10;
if(++nrKeys==2) {
gotKeys=true;
- PRINTF(L_SYS_EMM,"%d: got keys for %04X (plain)",CardNum(),keyId);
+ PRINTF(L_SYS_EMM,"got keys for %04X (plain)",keyId);
break;
}
}
else {
- PRINTF(L_SYS_EMM,"%d: ignored nano %02x",CardNum(),emmdata[i]);
+ PRINTF(L_SYS_EMM,"ignored nano %02x",emmdata[i]);
break;
}
}
};
ADD_MODULE(L_SYS,lm_sys)
-// evil hack, but it's not worth to put much effort in a dead system ...
+// This system is dead.
+// Not worth to invest time to keep it compilig....
+
+#if 0
+
static cTimeMs __time;
#define time_ms() ((int)__time.Elapsed())
SysId&=0xFFF0;
return SYSTEM_CAN_HANDLE(SysId);
}
+
+#endif //#if 0
#include "opentv.h"
#include "st20.h"
-#include "sc.h"
+#include "global.h"
#include "scsetup.h"
#include "system-common.h"
#include "filter.h"
:cLogHook(HOOK_SATTIME,"sattime")
{
ttime=Ttime;
- pids.AddPid(0x14,0x71,0xff,0x03);
+ pids.AddPid(0x14,0x70,0xfc);
ttime->SetHasHandler(true);
}
static cMutex mutex;
static cSimpleList<cTransponderTime> list;
//
- int cardNum;
cTransponderTime *ttime;
//
void CheckHandler(void);
public:
- cSatTime(int CardNum, int Source, int Transponder);
- time_t Now(void);
+ cSatTime(int Source, int Transponder);
+ time_t Now(cSystem *sys);
};
cMutex cSatTime::mutex;
cSimpleList<cTransponderTime> cSatTime::list;
-cSatTime::cSatTime(int CardNum, int Source, int Transponder)
+cSatTime::cSatTime(int Source, int Transponder)
{
- cardNum=CardNum;
cMutexLock lock(&mutex);
for(ttime=list.First(); ttime; ttime=list.Next(ttime))
if(ttime->Is(Source,Transponder)) break;
PRINTF(L_SYS_TIME,"%x:%x: created new transpondertime",Source,Transponder);
}
else PRINTF(L_SYS_TIME,"%x:%x: using existing transpondertime",Source,Transponder);
- CheckHandler();
-}
-
-time_t cSatTime::Now(void)
-{
- CheckHandler();
- return ttime ? ttime->Now() : -1;
}
-void cSatTime::CheckHandler(void)
+time_t cSatTime::Now(cSystem *sys)
{
if(ttime) {
- if(!cSoftCAM::TriggerHook(cardNum,HOOK_SATTIME) && !ttime->HasHandler()) {
+ if(!sys->TriggerHook(HOOK_SATTIME) && !ttime->HasHandler()) {
cSatTimeHook *hook=new cSatTimeHook(ttime);
- cSoftCAM::AddHook(cardNum,hook);
+ sys->AddHook(hook);
PRINTF(L_SYS_TIME,"added hook");
}
+ return ttime->Now();
}
+ return -1;
}
// -- cOpenTVModule ------------------------------------------------------------
return 0;
}
-void cTpsKeys::Check(time_t now, int cardnum)
+void cTpsKeys::Check(time_t now, cSystem *sys)
{
checkMutex.Lock();
if(first==0 && last==0 && Count()>0)
if(tpsAuMode==AU_STREAM && lastAu.Elapsed()>(nokey ? TPSAU_TIME/60 : TPSAU_TIME)) {
if(ScSetup.AutoUpdate>0) {
PRINTF(L_SYS_TPSAU,"TPS AU triggered");
- if(!cSoftCAM::TriggerHook(cardnum,HOOK_TPSAU)) {
+ if(!sys->TriggerHook(HOOK_TPSAU)) {
cTpsAuHook *hook=new cTpsAuHook;
- cSoftCAM::AddHook(cardnum,hook);
+ sys->AddHook(hook);
PRINTF(L_SYS_TPSAU,"TPS AU hook added");
}
}
PRINTF(L_SYS_TPSAU,"got PMT pid %04x for SID %04x",pmtpid,AUSID);
cPid *pid=pids.First();
if(pid && pid->filter) {
- pid->filter->Start(pmtpid,0x02,0xFF,0x00,false);
+ pid->filter->Start(pmtpid,0x02,0xFF);
pid->filter->Flush();
}
else PRINTF(L_GEN_DEBUG,"internal: no pid/filter in cTpsAuHook/pat");
PRINTF(L_SYS_TPSAU,"got AU pid %04x",aupid);
cPid *pid=pids.First();
if(pid && pid->filter) {
- pid->filter->Start(aupid,0x87,0xFF,0x00,false);
+ pid->filter->Start(aupid,0x87,0xFF);
pid->filter->Flush();
}
else PRINTF(L_GEN_DEBUG,"internal: no pid/filter in cTpsAuHook/pmt");
delete sattime;
}
-int cTPS::Decrypt(int cardNum, int Source, int Transponder, unsigned char *data, int len)
+int cTPS::Decrypt(cSystem *sys, int Source, int Transponder, unsigned char *data, int len)
{
if(!sattime) {
- sattime=new cSatTime(cardNum,Source,Transponder);
+ sattime=new cSatTime(Source,Transponder);
if(!sattime) {
PRINTF(L_SYS_TPS,"failed to create time class");
return -1;
}
}
- time_t now=sattime->Now();
- tpskeys.Check(now,cardNum);
+ time_t now=sattime->Now(sys);
+ tpskeys.Check(now,sys);
if(now<0) return -1;
const cTpsKey *k=tpskeys.GetKey(now);
#include "data.h"
#include "crypto.h"
+class cSystem;
class cSatTime;
class cTpsAuHook;
class cOpenTVModule;
public:
cTPS(void);
~cTPS();
- int Decrypt(int cardNum, int Source, int Transponder, unsigned char *data, int len);
+ int Decrypt(cSystem *sys, int Source, int Transponder, unsigned char *data, int len);
void PostProc(unsigned char *cw);
};
~cTpsKeys();
const cTpsKey *GetKey(time_t t);
const cTpsKey *GetV2Key(int id);
- void Check(time_t now, int cardnum);
+ void Check(time_t now, cSystem *sys);
};
extern cTpsKeys tpskeys;
if(ecm->provId==0x007c00) { // TPS
maxEcmTry=4;
mayHaveTps=true;
- int num=tps.Decrypt(CardNum(),ecm->source,ecm->transponder,nanos,len);
+ int num=tps.Decrypt(this,ecm->source,ecm->transponder,nanos,len);
if(num<0) return false;
nanos+=num; len-=num;
}
numKeys++;
}
else {
- PRINTF(L_SYS_EMM,"%d: key length mismatch %d!=%d",CardNum(),plen,(int)sizeof(newKey[0]));
+ PRINTF(L_SYS_EMM,"key length mismatch %d!=%d",plen,(int)sizeof(newKey[0]));
cnt=scanlen;
}
break;
printf("\n");
max=5;
- for(mode=0; mode<256; mode++) {
+ int mode=0;
+ //for(mode=0; mode<256; mode++) {
for(mask=0; mask<256; mask++) {
mam =mask & (~mode);
manm=mask & ~(~mode);
}
}
}
- }
+ //}
printf("no exact settings found\n");
exit(1);
}
extern const char *ScVersion;
// SC API version number for loading shared libraries
-#define SCAPIVERS 29
+#define SCAPIVERS 30
#ifndef STATICBUILD
#define SCAPIVERSTAG() int ScLibApiVersion=SCAPIVERS
#else