SASC-NG
DVBSoftCAM

cCardClientCamd35 Class Reference

Inheritance diagram for cCardClientCamd35:

List of all members.

Public Member Functions

 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)
virtual bool ProcessEMM (int caSys, const unsigned char *data)

Protected Member Functions

bool ParseUserConfig (const char *config, int *num)
bool SendBlock (struct CmdBlock *cb, int datalen)
int RecvBlock (struct CmdBlock *cb, int maxlen, int to)
void HandleEMMRequest (const struct CmdBlock *cb)
bool CanHandleEMM (unsigned short SysId)

Protected Attributes

bool emmProcessing
char username [33]
char password [33]
int numCaids
int Caids [8]
unsigned char Dx [8]
int lastEmmReq

Detailed Description

Definition at line 422 of file camd.c.


Constructor & Destructor Documentation

cCardClientCamd35::cCardClientCamd35 ( const char *  Name)

Definition at line 451 of file camd.c.

References CCTIMEOUT, Dx, emmProcessing, lastEmmReq, numCaids, cNetSocket::SetRWTimeout(), cNetSocket::SetUDP(), and cCardClient::so.

:cCardClient(Name)
{
  emmProcessing=exclusive=emmCmd06=false; pinid=0; numCaids=0; lastEmmReq=0;
  memset(Dx,0,sizeof(Dx));
  so.SetRWTimeout(CCTIMEOUT);
  so.SetUDP(true);
}

Member Function Documentation

bool cCardClientCamd35::CanHandleEMM ( unsigned short  SysId) [protected]

Definition at line 603 of file camd.c.

References Caids, i, and numCaids.

Referenced by ProcessEMM().

{
  for(int i=numCaids-1; i>=0; i--) if(SysId==Caids[i]) return true;
  return false;
}
void cCardClientCamd35::HandleEMMRequest ( const struct CmdBlock *  cb) [protected]

Definition at line 528 of file camd.c.

References cProviders::AddProv(), EmmReq02::caid, EmmReq05::caidCount, EmmReq05::caids, Caids, cCardClient::CaidsChanged(), cIdSet::card, CheckFF(), CheckNull(), CmdBlock::cmd, crc32_le(), EmmReq05::D0, EmmReq02::D0, EmmReq05::D2, EmmReq02::D2, EmmReq05::D3, EmmReq02::D3, CmdBlock::data, Dx, cCardClient::emmAllowed, emmProcessing, EmmReq02::hex, HexStr(), i, L_CC_CAMD35, L_CC_EMM, L_CC_LOGIN, lastEmmReq, LBEND, LBPUT, LBSTARTF, CmdBlock::len, cCardClient::name, numCaids, PRINTF, EmmReq05::prov, EmmReq05::provInfo, EmmReq05::provMap, cIdSet::ResetIdSet(), EmmReq05::sa, cIdSet::SetCard(), EmmReq05::ua, and CmdBlock::udp_header.

Referenced by ProcessECM().

{
  int c=crc32_le(0,cb->data,cb->udp_header.len);
  if(c!=lastEmmReq) {
    lastEmmReq=c;
    ResetIdSet();
    if(cb->udp_header.cmd==0x02 && cb->udp_header.len>=9) {
      struct EmmReq02 *req=(struct EmmReq02 *)cb->data;
      numCaids=1;
      Caids[0]=bswap_16(req->caid);
      SetCard(new cCardIrdeto(req->hex[3],&req->hex[0]));
      Dx[0]=req->D0;
      Dx[2]=req->D2;
      Dx[3]=req->D3;
      char str[20];
      PRINTF(L_CC_LOGIN,"%s: CAID: %04x HexSerial: %s, HexBase: %02X (D0-%d D2-%d D3-%d)\n",
             name,Caids[0],HexStr(str,((cCardIrdeto *)card)->hexSer,3),((cCardIrdeto *)card)->hexBase,
             Dx[0],Dx[2],Dx[3]);
      if(!emmProcessing || emmCmd06) PRINTF(L_CC_CAMD35,"got cmd 02, doing cmd02 EMM");
      emmCmd06=false;
      }
    else if(cb->udp_header.cmd==0x05 && cb->udp_header.len>=111) {
      struct EmmReq05 *req=(struct EmmReq05 *)cb->data;
      numCaids=bswap_32(req->caidCount);
      for(int i=numCaids-1; i>=0; i--) Caids[i]=bswap_16(req->caids[i]);
      LBSTARTF(L_CC_LOGIN);
      LBPUT("%s: CAIDS:",name);
      for(int i=numCaids-1; i>=0; i--) LBPUT(" %04x",Caids[i]);
      char str[20], str2[20];
      LBPUT(" ua=%s",HexStr(str,req->ua,6));
      switch(Caids[0]>>8) {
        case 0x17:
        case 0x06: SetCard(new cCardIrdeto(req->ua[3],&req->ua[0])); break;
        case 0x01: SetCard(new cCardSeca(&req->ua[0])); break;
        case 0x0d: SetCard(new cCardCryptoworks(&req->ua[0])); break;
        case 0x05: SetCard(new cCardViaccess(&req->ua[0])); break;
        case 0x18: SetCard(new cCardNagra2(&req->ua[2])); break;
        default:
          LBPUT(" (unhandled)");
          break;
        }
      LBPUT(" providers");
      int map=bswap_16(req->provMap);
//      for(int i=0; i<15; i++) //XXX not sure what actualy is the correct
//        if(map & (1<<i)) {    //XXX interpretation of provMap
      for(int i=0; i<map && i<15; i++) {
        LBPUT(" %d:%s/%s",i,HexStr(str,req->provInfo[i].prov,2),HexStr(str2,req->provInfo[i].sa,3));
        if(!CheckNull(req->provInfo[i].sa,3) && !CheckFF(req->provInfo[i].sa,3)) {
          switch(Caids[0]>>8) {
            case 0x17:
            case 0x06: AddProv(new cProviderIrdeto(req->provInfo[i].prov[0],req->provInfo[i].sa)); break;
            case 0x01: AddProv(new cProviderSeca(req->provInfo[i].prov,req->provInfo[i].sa)); break;
            default:
              LBPUT(" <unhandled>");
              break;
            }
          }
        }
      Dx[0]=req->D0;
      Dx[2]=req->D2;
      Dx[3]=req->D3;
      LBPUT(" (D0-%d D2-%d D3-%d)",Dx[0],Dx[2],Dx[3]);
      LBEND();

      if(!emmProcessing || !emmCmd06) PRINTF(L_CC_CAMD35,"got cmd 05, doing cmd06 EMM");
      emmCmd06=true;
      }
    else return;

    if(!emmAllowed) PRINTF(L_CC_EMM,"%s: EMM disabled from config",name);
    emmProcessing=true;
    CaidsChanged();
    }
}
bool cCardClientCamd35::Init ( const char *  config) [virtual]

Implements cCardClient.

Definition at line 510 of file camd.c.

References cCardClient::Logout(), cCardClient::ParseStdConfig(), and ParseUserConfig().

{
  cMutexLock lock(this);
  Logout();
  int num=0;
  return (ParseStdConfig(config,&num) && ParseUserConfig(config,&num));
}
bool cCardClientCamd35::Login ( void  ) [virtual]

Implements cCardClient.

Definition at line 518 of file camd.c.

References cNetSocket::Connect(), emmProcessing, cCardClient::hostname, L_CC_LOGIN, lastEmmReq, cCardClient::Logout(), cCardClient::name, cCardClient::port, PRINTF, and cCardClient::so.

{
  Logout();
  if(!so.Connect(hostname,port)) return false;
  PRINTF(L_CC_LOGIN,"%s: connected to %s:%d (%s)",name,hostname,port,name);
  emmProcessing=false; lastEmmReq=0;
  PRINTF(L_CC_LOGIN,"%s: login done",name);
  return true;
}
bool cCardClientCamd35::ParseUserConfig ( const char *  config,
int *  num 
) [protected]

Definition at line 460 of file camd.c.

References crc32_le(), L_CC_CORE, cCardClient::name, password, PRINTF, cAES::SetKey(), and username.

Referenced by Init().

{
  int startNum=*num;
  if(sscanf(&config[*num],":%32[^:]:%32[^:]%n",username,password,num)==2) {
    *num+=startNum;
    unsigned char md[16];
    ucrc=bswap_32(crc32_le(0,MD5((unsigned char *)username,strlen(username),md),16));
    PRINTF(L_CC_CORE,"%s: username=%s password=%s ucrc=%08x",name,username,password,ucrc);;
    SetKey(MD5((unsigned char *)password,strlen(password),md));
    return true;
    }
  return false;
}
bool cCardClientCamd35::ProcessECM ( const cEcmInfo *  ecm,
const unsigned char *  data,
unsigned char *  cw 
) [virtual]

Implements cCardClient.

Definition at line 677 of file camd.c.

References cCondVar::Broadcast(), cEcmInfo::caId, CmdBlock::casID, CCTIMEOUT, CheckNull(), CmdBlock::cmd, CmdBlock::data, HandleEMMRequest(), L_CC_CAMD35, L_CC_ECM, CmdBlock::len, cMutex::Lock(), cCardClient::name, CmdBlock::pinID, cEcmInfo::prgId, PRINTF, cEcmInfo::provId, CmdBlock::prvID, RecvBlock(), SCT_LEN, SendBlock(), CmdBlock::service, cTimeMs::Set(), CmdBlock::srvID, cTimeMs::TimedOut(), cCondVar::TimedWait(), CmdBlock::udp_header, cMutex::Unlock(), and cCondVar::Wait().

{
  bool res=false;
  const int length=SCT_LEN(data);
  if(length<=255) {
    Lock();
    while(exclusive) sleepCond.Wait(*this);
    unsigned char buff[300];
    memset(buff,0xff,sizeof(buff));
    struct CmdBlock *cb=(struct CmdBlock *)buff;
    const unsigned short pid=pinid++;
    int n;
    while((n=RecvBlock(cb,sizeof(buff),0))>0) {
      if(cb->udp_header.cmd==0x01 || cb->udp_header.cmd==0x44)
        PRINTF(L_CC_CAMD35,"unexpected CW answer on flush");
      else
        HandleEMMRequest(cb);
      }
    cb->udp_header.cmd=0x00;
    cb->service.srvID=bswap_16(ecm->prgId);
    cb->service.casID=bswap_16(ecm->caId);
    cb->service.prvID=bswap_32(ecm->provId);
    cb->service.pinID=pid;
    memcpy(&cb->data[0],data,length);
    if(SendBlock(cb,length)) {
      exclusive=true;
      time.Set(CCTIMEOUT);
      do {
        sleepCond.TimedWait(*this,50);
        while((n=RecvBlock(cb,sizeof(buff),0))>0) {
          if(cb->udp_header.cmd==0x01) {
            if(cb->udp_header.len>=16 && cb->service.pinID==pid && !res) {
              if(!CheckNull(&cb->data[0],8)) memcpy(&cw[0],&cb->data[0],8);
              if(!CheckNull(&cb->data[8],8)) memcpy(&cw[8],&cb->data[8],8);
              res=true;
              }
            else PRINTF(L_CC_CAMD35,"unexpected/bad CW packet");
            }
          else if(cb->udp_header.cmd==0x44) {
            if(cb->service.pinID==pid) {
              PRINTF(L_CC_ECM,"%s: server is unable to handle ECM",name);
              n=-1;
              break;
              }
            }
          else HandleEMMRequest(cb);
          }
        } while(!res && n>=0 && !time.TimedOut());
      if(!res && time.TimedOut()) PRINTF(L_CC_ECM,"%s: CW request timed out",name);
      exclusive=false;
      sleepCond.Broadcast();
      }
    Unlock();
    }
  else PRINTF(L_CC_ECM,"%s: ECM length %d > 255, not supported by UDP protocol",name,length);
  return res;
}
bool cCardClientCamd35::ProcessEMM ( int  caSys,
const unsigned char *  data 
) [virtual]

Reimplemented from cCardClient.

Definition at line 609 of file camd.c.

References cAssembleData::Assembled(), cMsgCache::Cache(), CanHandleEMM(), CmdBlock::casID, CmdBlock::cmd, CmdBlock::data, Dx, cCardClient::emmAllowed, emmProcessing, cMsgCache::Get(), L_CC_CAMDEXTR, L_CC_EMM, LDUMP, CmdBlock::len, cIdSet::MatchAndAssemble(), cCardClient::msEMM, cCardClient::name, CmdBlock::pinID, PRINTF, cProvider::ProvId(), CmdBlock::prvID, SCT_LEN, SendBlock(), CmdBlock::service, SetSctLen(), CmdBlock::srvID, and CmdBlock::udp_header.

{
  if(emmProcessing && emmAllowed) {
    cMutexLock lock(this);
    PRINTF(L_CC_CAMDEXTR,"got EMM caSys=%.4x",caSys);
    if(CanHandleEMM(caSys)) {
      LDUMP(L_CC_CAMDEXTR,&data[0],10,"EMM starts with");
      int upd;
      cProvider *p;
      cAssembleData ad(data);
      if(MatchAndAssemble(&ad,&upd,&p)) {
        PRINTF(L_CC_CAMDEXTR,"EMM matched upd=%d provId=%.4llx",upd,p ? p->ProvId() : 0);
        while((data=ad.Assembled())) {
          LDUMP(L_CC_CAMDEXTR,&data[0],10,"processing assembled EMM");
          if(Dx[upd]) {
            unsigned char buff[300];
            memset(buff,0xff,sizeof(buff));
            struct CmdBlock *cb=(struct CmdBlock *)buff;
            cb->udp_header.cmd=emmCmd06 ? 0x06 : 0x02;
            cb->service.srvID=0;
            cb->service.casID=bswap_16(caSys);
            cb->service.prvID=bswap_32(p ? p->ProvId() : 0);
            cb->service.pinID=pinid++;
            int len=SCT_LEN(data), off=0;
            switch(caSys>>8) {
              case 0x0d:
                {
                static const unsigned char head[] = { 0x8F,0x70,0x00,0xA4,0x42,0x00,0x00,0x00 };
                int c, n;
                switch(data[0]) {
                  case 0x82: c=0x42; n=10; break;
                  case 0x84: c=0x48; n=9; break;
                  case 0x88:
                  case 0x89: c=0x44; n=5; break;
                  default:   continue;
                  }
                if(len<n) continue;
                off=sizeof(head);
                memcpy(&cb->data[0],head,off);
                cb->data[3+1]=c;
                cb->data[3+4]=len-n;
                SetSctLen(&cb->data[0],len-n+5);
                data+=n; len-=n;
                break;
                }
              }
            if(len+off<=255) {
              memcpy(&cb->data[off],data,len);
              int id=msEMM.Get(&cb->data[0],len+off,0);
              if(id>0 || emmAllowed>1) {
                SendBlock(cb,len+off);
                msEMM.Cache(id,true,0);
                }
              else PRINTF(L_CC_CAMDEXTR,"not send, already in cache");
              }
            else PRINTF(L_CC_EMM,"%s: EMM length %d > 255, not supported by UDP protocol",name,len+off);
            }
          else PRINTF(L_CC_CAMDEXTR,"dropped, updtype %d blocked",upd);
          }
        return true;
        }
      else PRINTF(L_CC_CAMDEXTR,"dropped, doesn't match card data");
      }
    else PRINTF(L_CC_CAMDEXTR,"dropped, doesn't want caSys %.4x",caSys);
    }
  return false;
}
int cCardClientCamd35::RecvBlock ( struct CmdBlock *  cb,
int  maxlen,
int  to 
) [protected]

Definition at line 487 of file camd.c.

References CmdBlock::crc, crc32_le(), CmdBlock::data, cAES::Decrypt(), HDSIZE, HEXDUMP, L_CC_CAMD35, L_CC_CAMDEXTR, CmdBlock::len, PRINTF, cCardClient::RecvMsg(), CmdBlock::ucrc, UCSIZE, and CmdBlock::udp_header.

Referenced by ProcessECM().

{
  unsigned char *m=(unsigned char *)cb;
  int n=cCardClient::RecvMsg(m,-maxlen,to);
  if(n<=0) return n;
  if((unsigned int)n>=HDSIZE(cb)) {
    if(cb->ucrc==ucrc) {
      Decrypt(m+UCSIZE(cb),n-UCSIZE(cb));
      if((unsigned int)n<cb->udp_header.len+HDSIZE(cb))
        PRINTF(L_CC_CAMD35,"packet length doesn't match data length");
      else if(cb->udp_header.crc!=bswap_32(crc32_le(0,&cb->data[0],cb->udp_header.len)))
        PRINTF(L_CC_CAMD35,"data crc failed");
      else {
        HEXDUMP(L_CC_CAMDEXTR,cb,n,"recv:");
        return n;
        }
      }
    else PRINTF(L_CC_CAMD35,"wrong ucrc: got %08x, want %08x",cb->ucrc,ucrc);
    }
  else PRINTF(L_CC_CAMD35,"short packet received");
  return -1;
}
bool cCardClientCamd35::SendBlock ( struct CmdBlock *  cb,
int  datalen 
) [protected]

Definition at line 474 of file camd.c.

References AUTOMEM, CBSIZE, CmdBlock::crc, crc32_le(), CmdBlock::data, datalen, cAES::Encrypt(), HEXDUMP, L_CC_CAMDEXTR, CmdBlock::len, cCardClient::SendMsg(), UCSIZE, and CmdBlock::udp_header.

Referenced by ProcessECM(), and ProcessEMM().

{
  cb->udp_header.len=datalen;
  cb->udp_header.crc=bswap_32(crc32_le(0,&cb->data[0],datalen));
  datalen+=CBSIZE(cb);
  unsigned char *buff=AUTOMEM(datalen+UCSIZE(cb)+16);
  *((unsigned int *)buff)=ucrc;
  HEXDUMP(L_CC_CAMDEXTR,cb,datalen+UCSIZE(cb),"send:");
  const int l=Encrypt((unsigned char *)cb+UCSIZE(cb),datalen,buff+UCSIZE(cb));
  if(l<=0) return false;
  return cCardClient::SendMsg(buff,l+UCSIZE(cb));
}

Member Data Documentation

int cCardClientCamd35::Caids[8] [protected]

Definition at line 432 of file camd.c.

Referenced by CanHandleEMM(), and HandleEMMRequest().

unsigned char cCardClientCamd35::Dx[8] [protected]

Definition at line 433 of file camd.c.

Referenced by cCardClientCamd35(), HandleEMMRequest(), and ProcessEMM().

Definition at line 430 of file camd.c.

Referenced by cCardClientCamd35(), HandleEMMRequest(), Login(), and ProcessEMM().

Definition at line 434 of file camd.c.

Referenced by cCardClientCamd35(), HandleEMMRequest(), and Login().

int cCardClientCamd35::numCaids [protected]

Definition at line 432 of file camd.c.

Referenced by CanHandleEMM(), cCardClientCamd35(), and HandleEMMRequest().

char cCardClientCamd35::password[33] [protected]

Definition at line 431 of file camd.c.

Referenced by ParseUserConfig().

char cCardClientCamd35::username[33] [protected]

Definition at line 431 of file camd.c.

Referenced by ParseUserConfig().


The documentation for this class was generated from the following file:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines