📄 cam.c
字号:
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); 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&0x80) { int i; for(i=len&~0x80, len=0; i>0; i--) len=(len<<8) + *data++; } return len;}void cScCamSlot::CaInfo(unsigned char *b, int tcid, int cid){ 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]=0x31; // AOT_CA_INFO int l=0; for(int i=0; caids[i]; i++) { b[l+11]=caids[i]>>8; b[l+12]=caids[i]&0xff; l+=2; } b[10]=l; b[1]=l+9; b[-1]=l+11; Put(b-1,l+12); 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]; unsigned char a[128], *b=&a[1]; if(Check()) CaInfo(b,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(b,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]; 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]; 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))) { 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->Prg()<<8; b[12]=prg->Prg()&0xff; b[13]=0x00; b[14]=0x81; // CA_ENABLE b[10]=4; b[1]=4+9; a[0]=4+11; Put(a,4+12); PRINTF(L_CORE_CI,"%d.%d answer to query",cardIndex,slot); } if(prg->Prg()!=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->Prg()); ciadapter->CamAddPrg(prg); } } delete prg; } break; }}// -- cScCiAdapter -------------------------------------------------------------cScCiAdapter::cScCiAdapter(cDevice *Device, int CardIndex, cCam *Cam){ device=Device; cardIndex=CardIndex; cam=Cam; tcid=0; memset(version,0,sizeof(version)); memset(slots,0,sizeof(slots)); SetDescription("SC-CI adapter on device %d",cardIndex); rb=new cRingBufferLinear(KILOBYTE(5),6+1,false,"SC-CI adapter read"); if(rb) { rb->SetTimeouts(0,CAM_READ_TIMEOUT);/* 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();}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::BuildCaids(bool force){ if(caidTimer.TimedOut() || force) { 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(); list.CheckIgnore(); list.Unique(); 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); } 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); }}int cScCiAdapter::Read(unsigned char *Buffer, int MaxLength){ cMutexLock lock(&ciMutex); if(cam && rb && Buffer && MaxLength>0) { int c; unsigned char *data=rb->Get(c); if(data) { int s=data[0]; if(c>=s+1) { c=s>MaxLength ? MaxLength : s; memcpy(Buffer,&data[1],c); if(c<s) { data[c]=s-c; rb->Del(c); } else rb->Del(c+1); if(Buffer[2]!=0x80 || LOG(L_CORE_CIFULL)) { LDUMP(L_CORE_CI,Buffer,c,"%d.%d <-",cardIndex,Buffer[0]); readTimer.Set(); } return c; } else { LDUMP(L_GEN_DEBUG,data,c,"internal: sc-ci %d rb frame sync got=%d avail=%d -",cardIndex,c,rb->Available()); rb->Clear(); } } } 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)#define PUT_TAG(data,len) do { unsigned char *_d=(data)-1; int _l=(len); _d[0]=_l; if(rb) rb->Put(_d,_l+1); } while(0)void cScCiAdapter::Write(const unsigned char *buff, int len){ cMutexLock lock(&ciMutex); if(cam && buff && len>=5) { unsigned char a[128], *b=&a[1]; struct TPDU *tpdu=(struct TPDU *)buff; int slot=tpdu->slot; 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 { TPDU(b,slot); int l=2, c; unsigned char *d=slots[slot]->Get(c); if(d) { int s=d[0]; if(c>=s) { memcpy(&b[l],&d[1],s); l+=s; slots[slot]->Del(s+1); } else slots[slot]->Del(c); } SB_TAG(&b[l],0x00); PUT_TAG(b,l+4); break; } case 0x82: // T_CREATE_TC tcid=tpdu->data[0]; TPDU(b,slot); TAG(&b[2],0x83,0x01); b[4]=tcid; SB_TAG(&b[5],0x00); PUT_TAG(b,9); static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 }; memcpy(b,reqCAS,sizeof(reqCAS)); b[2]=tcid; a[0]=sizeof(reqCAS); slots[slot]->Put(a,sizeof(reqCAS)+1); break; case 0xA0: // T_DATA_LAST slots[slot]->Process(buff,len); TPDU(b,slot); SB_TAG(&b[2],slots[slot]->Available()>0 ? 0x80:0x00); PUT_TAG(b,6); 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;}#endif //APIVERSNUM >= 10500// -- cDeCSA -------------------------------------------------------------------#define MAX_CSA_PIDS 8192#define MAX_CSA_IDX 16class cDeCSA : public cMutex {private: int cs; unsigned char **range; unsigned char pidmap[MAX_CSA_PIDS]; void *keys[MAX_CSA_IDX]; // bool GetKeyStruct(int idx);public: cDeCSA(void); ~cDeCSA(); bool Decrypt(unsigned char *data, int len, bool force); bool SetDescr(ca_descr_t *ca_descr); bool SetCaPid(ca_pid_t *ca_pid); };cDeCSA::cDeCSA(void){ cs=get_suggested_cluster_size(); PRINTF(L_CORE_CSA,"clustersize=%d rangesize=%d",cs,cs*2+5); range=MALLOC(unsigned char *,(cs*2+5)); memset(keys,0,sizeof(keys)); memset(pidmap,0,sizeof(pidmap));}cDeCSA::~cDeCSA(){ for(int i=0; i<MAX_CSA_IDX; i++) if(keys[i]) free_key_struct(keys[i]); free(range);}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){ cMutexLock lock(this); int idx=ca_descr->index; if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) { if(ca_descr->parity==0) { // even key set_even_control_word(keys[idx],ca_descr->cw); PRINTF(L_CORE_CSA,"even key set"); } else { // odd key set_odd_control_word(keys[idx],ca_descr->cw); PRINTF(L_CORE_CSA,"odd key set"); } } return true;}bool cDeCSA::SetCaPid(ca_pid_t *ca_pid){ cMutexLock lock(this); if(ca_pid->index<MAX_CSA_IDX && ca_pid->pid<MAX_CSA_PIDS) { pidmap[ca_pid->pid]=ca_pid->index; PRINTF(L_CORE_CSA,"set pid %04x to index %d",ca_pid->pid,ca_pid->index); } return true;}bool cDeCSA::Decrypt(unsigned char *data, int len, bool force){ cMutexLock lock(this); int r=-2, ccs=0, currIdx=-1; bool newRange=true; range[0]=0; len-=(TS_SIZE-1); for(int l=0; l<len; l+=TS_SIZE) { if(data[l]!=TS_SYNC_BYTE) { // let higher level cope with that PRINTF(L_CORE_CSA,"garbage in TS buffer"); break; } if(data[l+3]&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(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 { // other index, create hole PRINTF(L_CORE_CSA,"other index. current=%d idx=%d",currIdx,idx); newRange=true; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -