SASC-NG
DVBSoftCAM

camd.c

Go to the documentation of this file.
00001 /*
00002  * Softcam plugin to VDR (C++)
00003  *
00004  * This code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00018  */
00019 
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <byteswap.h>
00023 
00024 #include "cc.h"
00025 #include "crypto.h"
00026 #include "misc.h"
00027 #include "parse.h"
00028 
00029 #include <openssl/md5.h>
00030 
00031 #define CCVERSION "3.37"
00032 #define CCTIMEOUT 5000 // ms
00033 
00034 // -- cCardClientCommon --------------------------------------------------------
00035 
00036 class cCardClientCommon : public cCardClient, public cAES, protected cIdSet {
00037 private:
00038   bool conReply, logReply, doAES;
00039   bool exclusive;
00040   int minMsgLen;
00041   cCondVar sleepCond;
00042   cTimeMs time;
00043 protected:
00044   bool emmProcessing;
00045   char username[11], password[11];
00046   int emmReqLen;
00047   //
00048   bool ParseKeyConfig(const char *config, int *num);
00049   bool ParseUserConfig(const char *config, int *num);
00050   virtual bool SendMsg(const unsigned char *data, int len);
00051   virtual int RecvMsg(unsigned char *data, int len, int to=-1);
00052   virtual void HandleEMMRequest(const unsigned char *buff, int len) {}
00053   virtual bool CanHandleEMM(int SysId) { return false; }
00054 public:
00055   cCardClientCommon(const char *Name, bool ConReply, bool LogReply, bool DoAES, int MinMsgLen);
00056   virtual bool Init(const char *config);
00057   virtual bool Login(void);
00058   virtual bool Immediate(void);
00059   virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
00060   virtual bool ProcessEMM(int caSys, const unsigned char *source);
00061   };
00062 
00063 cCardClientCommon::cCardClientCommon(const char *Name, bool ConReply, bool LogReply, bool DoAES, int MinMsgLen)
00064 :cCardClient(Name)
00065 {
00066   conReply=ConReply; logReply=LogReply; doAES=DoAES; minMsgLen=MinMsgLen;
00067   emmProcessing=exclusive=false;
00068   so.SetRWTimeout(CCTIMEOUT);
00069   emmReqLen=-64;
00070 }
00071 
00072 bool cCardClientCommon::ParseUserConfig(const char *config, int *num)
00073 {
00074   int startNum=*num;
00075   if(sscanf(&config[*num],":%10[^:]:%10[^:]%n",username,password,num)==2) {
00076     *num+=startNum;
00077     PRINTF(L_CC_CORE,"%s: username=%s password=%s",name,username,password);;
00078     return true;
00079     }
00080   return false;
00081 }
00082 
00083 bool cCardClientCommon::ParseKeyConfig(const char *config, int *num)
00084 {
00085   char hexkey[33];
00086   int startNum=*num;
00087   if(sscanf(&config[*num],":%32[^:]%n",hexkey,num)==1) {
00088     *num+=startNum;
00089     PRINTF(L_CC_CORE,"%s: key=%s",name,hexkey);
00090     unsigned char binkey[16];
00091     memset(binkey,0,sizeof(binkey));
00092     const char *line=hexkey;
00093     int n=GetHex(line,binkey,sizeof(binkey),false);
00094     if(n!=(int)sizeof(binkey))
00095       PRINTF(L_CC_CAMD,"warning AES key not %d bytes long",(int)sizeof(binkey));
00096     LDUMP(L_CC_CAMD,binkey,16,"AES activated key =");
00097     SetKey(binkey);
00098     }
00099   return true;
00100 }
00101 
00102 bool cCardClientCommon::SendMsg(const unsigned char *data, int len)
00103 {
00104   unsigned char *buff2=AUTOMEM(minMsgLen);
00105   if(len<minMsgLen) {
00106     memcpy(buff2,data,len);
00107     memset(buff2+len,0,minMsgLen-len);
00108     data=buff2; len=minMsgLen;
00109     }
00110   unsigned char *buff=AUTOMEM(len+16);
00111   const int l=Encrypt(data,len,buff);
00112   if(l>0) { data=buff; len=l; }
00113   return cCardClient::SendMsg(data,len);
00114 }
00115 
00116 int cCardClientCommon::RecvMsg(unsigned char *data, int len, int to)
00117 {
00118   int n=cCardClient::RecvMsg(data,len,to);
00119   if(n>0) {
00120     if(n&15) PRINTF(L_CC_CAMD,"AES crypted message length not a multiple of 16");
00121     Decrypt(data,n);
00122     }
00123   return n;
00124 }
00125 
00126 bool cCardClientCommon::Immediate(void)
00127 {
00128   return emmAllowed && logReply && cCardClient::Immediate();
00129 }
00130 
00131 bool cCardClientCommon::Init(const char *config)
00132 {
00133   cMutexLock lock(this);
00134   Logout();
00135   int num=0;
00136   if(ParseStdConfig(config,&num) &&
00137      ParseUserConfig(config,&num) &&
00138      (!doAES || ParseKeyConfig(config,&num))) {
00139     return true;
00140     }
00141   return false;
00142 }
00143 
00144 bool cCardClientCommon::Login(void)
00145 {
00146   Logout();
00147   if(!so.Connect(hostname,port)) return false;
00148   PRINTF(L_CC_LOGIN,"%s: connected to %s:%d (%s)",name,hostname,port,name);
00149   emmProcessing=false;
00150 
00151   unsigned char buff[128];
00152   if(conReply) {
00153     if(RecvMsg(buff,16)<0) {
00154       PRINTF(L_CC_CAMD,"bad connect reply");
00155       return false;
00156       }
00157     }
00158 
00159   memset(buff,0,32);
00160   int user_len=strlen(username)+1;
00161   memcpy(buff+1,username,user_len);
00162   int pass_len=strlen(password)+1;
00163   memcpy(buff+1+user_len+1,password,pass_len);
00164   int vers_len=strlen(CCVERSION)+1;
00165   memcpy(buff+1+user_len+pass_len+1,CCVERSION,vers_len);
00166   PRINTF(L_CC_CAMD,"login user='%s' password=hidden version=%s",username,CCVERSION);
00167   if(!SendMsg(buff,32)) return false;
00168 
00169   if(emmAllowed && logReply) {
00170     PRINTF(L_CC_CAMD,"waiting for login reply ...");
00171     int r=RecvMsg(buff,emmReqLen);
00172     if(r>0) HandleEMMRequest(buff,r);
00173     }
00174   PRINTF(L_CC_LOGIN,"%s: login done",name);
00175   return true;
00176 }
00177 
00178 bool cCardClientCommon::ProcessEMM(int caSys, const unsigned char *source)
00179 {
00180   if(emmAllowed && CanHandleEMM(caSys)) {
00181     cMutexLock lock(this);
00182     if(MatchEMM(source)) {
00183       const int length=SCT_LEN(source);
00184       int id=msEMM.Get(source,length,0);
00185       if(id>0 || emmAllowed>1) {
00186         unsigned char *buff=AUTOMEM(length+32);
00187         buff[0]=0x03;
00188         buff[1]=(caSys>>8);
00189         buff[2]=(caSys&0xFF);
00190         memcpy(buff+3,((cCardIrdeto *)card)->hexSer,3);
00191         buff[6]=((cCardIrdeto *)card)->hexBase;
00192         memcpy(&buff[7],source,length);
00193         //PRINTF(L_CC_CAMD,"%s: sending EMM for caid 0x%04X",name,caSys);
00194         SendMsg(buff,length+7);
00195         msEMM.Cache(id,true,0);
00196         }
00197       return true;
00198       }
00199     }
00200   return false;
00201 }
00202 
00203 bool cCardClientCommon::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
00204 {
00205   Lock();
00206   bool res=false;
00207   while(exclusive) sleepCond.Wait(*this);
00208   if((so.Connected() || Login()) && (!emmProcessing || CanHandle(ecm->caId))) {
00209     const int length=SCT_LEN(source);
00210     unsigned char *buff=AUTOMEM(length+32);
00211     int n;
00212     while((n=RecvMsg(buff,-16,0))>0) HandleEMMRequest(buff,n);
00213     buff[0]=0x02;
00214     buff[1]=(ecm->caId>>8);
00215     buff[2]=(ecm->caId&0xFF);
00216     memset(&buff[3],0,4);
00217     memcpy(&buff[7],source,length);
00218     if(SendMsg(buff,length+7)) {
00219       exclusive=true;
00220       time.Set(CCTIMEOUT);
00221       do {
00222         sleepCond.TimedWait(*this,50);
00223         while((n=RecvMsg(buff,-32,0))>0) {
00224           if(n>=21 && buff[0]==2) {
00225             if(!CheckNull(buff+5,16)) {
00226               if(!res) {
00227                 memcpy(cw,buff+5,16);
00228                 res=true;
00229                 }
00230               else PRINTF(L_CC_CAMD,"unexpected CW packet");
00231               }
00232             else {
00233               PRINTF(L_CC_ECM,"%s: server is unable to handle ECM",name);
00234               n=-1;
00235               break;
00236               }
00237             }
00238           else HandleEMMRequest(buff,n);
00239           }
00240         } while(!res && n>=0 && !time.TimedOut());
00241       if(!res && time.TimedOut()) PRINTF(L_CC_ECM,"%s: CW request timed out",name);
00242       exclusive=false;
00243       sleepCond.Broadcast();
00244       }
00245     }
00246   Unlock();
00247   return res;
00248 }
00249 
00250 // -- cCardClientCamd33 --------------------------------------------------------
00251 
00252 #define EMMREQLEN33 13
00253 
00254 class cCardClientCamd33 : public cCardClientCommon {
00255 private:
00256   int CAID;
00257   unsigned char lastEmmReq[32];
00258 protected:
00259   virtual void HandleEMMRequest(const unsigned char *buff, int len);
00260   virtual bool CanHandleEMM(int SysId);
00261 public:
00262   cCardClientCamd33(const char *Name);
00263   virtual bool CanHandle(unsigned short SysId);
00264   };
00265 
00266 static cCardClientLinkReg<cCardClientCamd33> __camd33("Camd33");
00267 
00268 cCardClientCamd33::cCardClientCamd33(const char *Name)
00269 :cCardClientCommon(Name,true,true,true,0)
00270 {
00271   CAID=0;
00272   memset(lastEmmReq,0,sizeof(lastEmmReq));
00273   emmReqLen=EMMREQLEN33;
00274 }
00275 
00276 bool cCardClientCamd33::CanHandle(unsigned short SysId)
00277 {
00278   return CanHandleEMM(SysId) || cCardClient::CanHandle(SysId);
00279 }
00280 
00281 bool cCardClientCamd33::CanHandleEMM(int SysId)
00282 {
00283   return (emmProcessing && SysId==CAID);
00284 }
00285 
00286 void cCardClientCamd33::HandleEMMRequest(const unsigned char *buff, int len)
00287 {
00288   if(len>=emmReqLen && buff[0]==0 && !CheckNull(buff,len) && memcmp(buff,lastEmmReq,emmReqLen)) {
00289     emmProcessing=false;
00290     int c=buff[1]*256+buff[2];
00291     if(c!=CAID) CaidsChanged();
00292     CAID=c;
00293     ResetIdSet();
00294     switch(CAID>>8) {
00295       case 0x17:
00296       case 0x06:
00297         SetCard(new cCardIrdeto(buff[6],&buff[3]));
00298         AddProv(new cProviderIrdeto(0,&buff[7]));
00299         AddProv(new cProviderIrdeto(2,&buff[10]));
00300         memcpy(lastEmmReq,buff,13);
00301         PRINTF(L_CC_LOGIN,"%s: CAID: %04x HexSerial: %02X%02X%02X, HexBase: %02X",name,CAID,buff[3],buff[4],buff[5],buff[6]);
00302         PRINTF(L_CC_LOGIN,"%s: Provider00: %02X%02X%02X, Provider10: %02X%02X%02X",name,buff[7],buff[8],buff[9],buff[10],buff[11],buff[12]);
00303         if(!emmAllowed) PRINTF(L_CC_EMM,"%s: EMM disabled from config",name);
00304         emmProcessing=true;
00305         break;
00306       }
00307     }
00308 }
00309 
00310 // -- cCardClientCardd ---------------------------------------------------------
00311 
00312 class cCardClientCardd : public cCardClientCommon {
00313 public:
00314   cCardClientCardd(const char *Name);
00315   };
00316 
00317 static cCardClientLinkReg<cCardClientCardd> __cardd("Cardd");
00318 
00319 cCardClientCardd::cCardClientCardd(const char *Name)
00320 :cCardClientCommon(Name,false,true,false,96)
00321 {}
00322 
00323 // -- cCardClientBuffy ---------------------------------------------------------
00324 
00325 #define MAX_CAIDS 16
00326 
00327 class cCardClientBuffy : public cCardClientCommon {
00328 private:
00329   unsigned short CAIDs[MAX_CAIDS], numCAIDs;
00330 public:
00331   cCardClientBuffy(const char *Name);
00332   virtual bool Init(const char *config);
00333   virtual bool Login(void);
00334   virtual bool CanHandle(unsigned short SysId);
00335   };
00336 
00337 static cCardClientLinkReg<cCardClientBuffy> __buffy("Buffy");
00338 
00339 cCardClientBuffy::cCardClientBuffy(const char *Name)
00340 :cCardClientCommon(Name,true,false,true,0)
00341 {}
00342 
00343 bool cCardClientBuffy::Init(const char *config)
00344 {
00345   cMutexLock lock(this);
00346   return cCardClientCommon::Init(config);
00347 }
00348 
00349 bool cCardClientBuffy::CanHandle(unsigned short SysId)
00350 {
00351   cMutexLock lock(this);
00352   for(int i=0; i<numCAIDs; i++) if(CAIDs[i]==SysId) return true;
00353   return false;
00354 }
00355 
00356 bool cCardClientBuffy::Login(void)
00357 {
00358   cMutexLock lock(this);
00359   if(!cCardClientCommon::Login()) return false;
00360 
00361   unsigned char buff[128];
00362   memset(buff,0,sizeof(buff));
00363   buff[0]=0x0A;
00364   if(!SendMsg(buff,32)) return false;
00365   int n=RecvMsg(buff,-sizeof(buff));
00366   if(n<0) return false;
00367   for(int i=1; i<n && numCAIDs<MAX_CAIDS; i+=2) {
00368     unsigned short caid=(buff[i+1]<<8)+buff[i];
00369     if(caid==0xFFFF) break;
00370     if(caid) CAIDs[numCAIDs++]=caid;
00371     }
00372   CaidsChanged();
00373   LBSTART(L_CC_LOGIN);
00374   LBPUT("%s: CAIDs ",name);
00375   for(int i=0; i<numCAIDs && CAIDs[i]; i++) LBPUT("%04X ",CAIDs[i]);
00376   LBEND();
00377   return true;
00378 }
00379 
00380 // -- cCardClientCamd35 --------------------------------------------------------
00381 
00382 struct CmdBlock {
00383   unsigned int ucrc;
00384   struct {
00385     unsigned char cmd;    // 0
00386     unsigned char len;    // 1
00387     unsigned char pad[2]; // 2  XXXX
00388     unsigned int crc;     // 4
00389     } udp_header;
00390   struct {
00391     unsigned short srvID; // 8
00392     unsigned short casID; // 10
00393     unsigned int prvID;   // 12
00394     unsigned short pinID; // 16
00395     unsigned char pad2[2];// 18 XXXX
00396     } service;
00397   unsigned char data[2];  // 20
00398   };
00399 
00400 #define CBSIZE(cb) (sizeof((cb)->udp_header)+sizeof((cb)->service))
00401 #define UCSIZE(cb) (sizeof((cb)->ucrc))
00402 #define HDSIZE(cb) (CBSIZE(cb)+UCSIZE(cb))
00403 
00404 struct EmmReq02 {
00405   unsigned short caid;
00406   unsigned char hex[4];
00407   unsigned char D0, D2, D3;
00408   };
00409 
00410 struct EmmReq05 {
00411   unsigned short caids[8]; // 0
00412   int caidCount;           // 16
00413   unsigned char ua[6];     // 20
00414   unsigned short provMap;  // 26
00415   struct {                 // 28
00416     unsigned char prov[2];
00417     unsigned char sa[3];
00418     } provInfo[16];
00419   unsigned char D0, D2, D3; // 108
00420   };
00421 
00422 class cCardClientCamd35 : public cCardClient, public cAES, private cIdSet {
00423 private:
00424   unsigned int ucrc;
00425   unsigned short pinid;
00426   bool exclusive, emmCmd06;
00427   cCondVar sleepCond;
00428   cTimeMs time;
00429 protected:
00430   bool emmProcessing;
00431   char username[33], password[33];
00432   int numCaids, Caids[8];
00433   unsigned char Dx[8];
00434   int lastEmmReq;
00435   //
00436   bool ParseUserConfig(const char *config, int *num);
00437   bool SendBlock(struct CmdBlock *cb, int datalen);
00438   int RecvBlock(struct CmdBlock *cb, int maxlen, int to);
00439   void HandleEMMRequest(const struct CmdBlock *cb);
00440   bool CanHandleEMM(unsigned short SysId);
00441 public:
00442   cCardClientCamd35(const char *Name);
00443   virtual bool Init(const char *config);
00444   virtual bool Login(void);
00445   virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw);
00446   virtual bool ProcessEMM(int caSys, const unsigned char *data);
00447   };
00448 
00449 static cCardClientLinkReg<cCardClientCamd35> __camd35("Camd35");
00450 
00451 cCardClientCamd35::cCardClientCamd35(const char *Name)
00452 :cCardClient(Name)
00453 {
00454   emmProcessing=exclusive=emmCmd06=false; pinid=0; numCaids=0; lastEmmReq=0;
00455   memset(Dx,0,sizeof(Dx));
00456   so.SetRWTimeout(CCTIMEOUT);
00457   so.SetUDP(true);
00458 }
00459 
00460 bool cCardClientCamd35::ParseUserConfig(const char *config, int *num)
00461 {
00462   int startNum=*num;
00463   if(sscanf(&config[*num],":%32[^:]:%32[^:]%n",username,password,num)==2) {
00464     *num+=startNum;
00465     unsigned char md[16];
00466     ucrc=bswap_32(crc32_le(0,MD5((unsigned char *)username,strlen(username),md),16));
00467     PRINTF(L_CC_CORE,"%s: username=%s password=%s ucrc=%08x",name,username,password,ucrc);;
00468     SetKey(MD5((unsigned char *)password,strlen(password),md));
00469     return true;
00470     }
00471   return false;
00472 }
00473 
00474 bool cCardClientCamd35::SendBlock(struct CmdBlock *cb, int datalen)
00475 {
00476   cb->udp_header.len=datalen;
00477   cb->udp_header.crc=bswap_32(crc32_le(0,&cb->data[0],datalen));
00478   datalen+=CBSIZE(cb);
00479   unsigned char *buff=AUTOMEM(datalen+UCSIZE(cb)+16);
00480   *((unsigned int *)buff)=ucrc;
00481   HEXDUMP(L_CC_CAMDEXTR,cb,datalen+UCSIZE(cb),"send:");
00482   const int l=Encrypt((unsigned char *)cb+UCSIZE(cb),datalen,buff+UCSIZE(cb));
00483   if(l<=0) return false;
00484   return cCardClient::SendMsg(buff,l+UCSIZE(cb));
00485 }
00486 
00487 int cCardClientCamd35::RecvBlock(struct CmdBlock *cb, int maxlen, int to)
00488 {
00489   unsigned char *m=(unsigned char *)cb;
00490   int n=cCardClient::RecvMsg(m,-maxlen,to);
00491   if(n<=0) return n;
00492   if((unsigned int)n>=HDSIZE(cb)) {
00493     if(cb->ucrc==ucrc) {
00494       Decrypt(m+UCSIZE(cb),n-UCSIZE(cb));
00495       if((unsigned int)n<cb->udp_header.len+HDSIZE(cb))
00496         PRINTF(L_CC_CAMD35,"packet length doesn't match data length");
00497       else if(cb->udp_header.crc!=bswap_32(crc32_le(0,&cb->data[0],cb->udp_header.len)))
00498         PRINTF(L_CC_CAMD35,"data crc failed");
00499       else {
00500         HEXDUMP(L_CC_CAMDEXTR,cb,n,"recv:");
00501         return n;
00502         }
00503       }
00504     else PRINTF(L_CC_CAMD35,"wrong ucrc: got %08x, want %08x",cb->ucrc,ucrc);
00505     }
00506   else PRINTF(L_CC_CAMD35,"short packet received");
00507   return -1;
00508 }
00509 
00510 bool cCardClientCamd35::Init(const char *config)
00511 {
00512   cMutexLock lock(this);
00513   Logout();
00514   int num=0;
00515   return (ParseStdConfig(config,&num) && ParseUserConfig(config,&num));
00516 }
00517 
00518 bool cCardClientCamd35::Login(void)
00519 {
00520   Logout();
00521   if(!so.Connect(hostname,port)) return false;
00522   PRINTF(L_CC_LOGIN,"%s: connected to %s:%d (%s)",name,hostname,port,name);
00523   emmProcessing=false; lastEmmReq=0;
00524   PRINTF(L_CC_LOGIN,"%s: login done",name);
00525   return true;
00526 }
00527 
00528 void cCardClientCamd35::HandleEMMRequest(const struct CmdBlock *cb)
00529 {
00530   int c=crc32_le(0,cb->data,cb->udp_header.len);
00531   if(c!=lastEmmReq) {
00532     lastEmmReq=c;
00533     ResetIdSet();
00534     if(cb->udp_header.cmd==0x02 && cb->udp_header.len>=9) {
00535       struct EmmReq02 *req=(struct EmmReq02 *)cb->data;
00536       numCaids=1;
00537       Caids[0]=bswap_16(req->caid);
00538       SetCard(new cCardIrdeto(req->hex[3],&req->hex[0]));
00539       Dx[0]=req->D0;
00540       Dx[2]=req->D2;
00541       Dx[3]=req->D3;
00542       char str[20];
00543       PRINTF(L_CC_LOGIN,"%s: CAID: %04x HexSerial: %s, HexBase: %02X (D0-%d D2-%d D3-%d)\n",
00544              name,Caids[0],HexStr(str,((cCardIrdeto *)card)->hexSer,3),((cCardIrdeto *)card)->hexBase,
00545              Dx[0],Dx[2],Dx[3]);
00546       if(!emmProcessing || emmCmd06) PRINTF(L_CC_CAMD35,"got cmd 02, doing cmd02 EMM");
00547       emmCmd06=false;
00548       }
00549     else if(cb->udp_header.cmd==0x05 && cb->udp_header.len>=111) {
00550       struct EmmReq05 *req=(struct EmmReq05 *)cb->data;
00551       numCaids=bswap_32(req->caidCount);
00552       for(int i=numCaids-1; i>=0; i--) Caids[i]=bswap_16(req->caids[i]);
00553       LBSTARTF(L_CC_LOGIN);
00554       LBPUT("%s: CAIDS:",name);
00555       for(int i=numCaids-1; i>=0; i--) LBPUT(" %04x",Caids[i]);
00556       char str[20], str2[20];
00557       LBPUT(" ua=%s",HexStr(str,req->ua,6));
00558       switch(Caids[0]>>8) {
00559         case 0x17:
00560         case 0x06: SetCard(new cCardIrdeto(req->ua[3],&req->ua[0])); break;
00561         case 0x01: SetCard(new cCardSeca(&req->ua[0])); break;
00562         case 0x0d: SetCard(new cCardCryptoworks(&req->ua[0])); break;
00563         case 0x05: SetCard(new cCardViaccess(&req->ua[0])); break;
00564         case 0x18: SetCard(new cCardNagra2(&req->ua[2])); break;
00565         default:
00566           LBPUT(" (unhandled)");
00567           break;
00568         }
00569       LBPUT(" providers");
00570       int map=bswap_16(req->provMap);
00571 //      for(int i=0; i<15; i++) //XXX not sure what actualy is the correct
00572 //        if(map & (1<<i)) {    //XXX interpretation of provMap
00573       for(int i=0; i<map && i<15; i++) {
00574         LBPUT(" %d:%s/%s",i,HexStr(str,req->provInfo[i].prov,2),HexStr(str2,req->provInfo[i].sa,3));
00575         if(!CheckNull(req->provInfo[i].sa,3) && !CheckFF(req->provInfo[i].sa,3)) {
00576           switch(Caids[0]>>8) {
00577             case 0x17:
00578             case 0x06: AddProv(new cProviderIrdeto(req->provInfo[i].prov[0],req->provInfo[i].sa)); break;
00579             case 0x01: AddProv(new cProviderSeca(req->provInfo[i].prov,req->provInfo[i].sa)); break;
00580             default:
00581               LBPUT(" <unhandled>");
00582               break;
00583             }
00584           }
00585         }
00586       Dx[0]=req->D0;
00587       Dx[2]=req->D2;
00588       Dx[3]=req->D3;
00589       LBPUT(" (D0-%d D2-%d D3-%d)",Dx[0],Dx[2],Dx[3]);
00590       LBEND();
00591 
00592       if(!emmProcessing || !emmCmd06) PRINTF(L_CC_CAMD35,"got cmd 05, doing cmd06 EMM");
00593       emmCmd06=true;
00594       }
00595     else return;
00596 
00597     if(!emmAllowed) PRINTF(L_CC_EMM,"%s: EMM disabled from config",name);
00598     emmProcessing=true;
00599     CaidsChanged();
00600     }
00601 }
00602 
00603 bool cCardClientCamd35::CanHandleEMM(unsigned short SysId)
00604 {
00605   for(int i=numCaids-1; i>=0; i--) if(SysId==Caids[i]) return true;
00606   return false;
00607 }
00608 
00609 bool cCardClientCamd35::ProcessEMM(int caSys, const unsigned char *data)
00610 {
00611   if(emmProcessing && emmAllowed) {
00612     cMutexLock lock(this);
00613     PRINTF(L_CC_CAMDEXTR,"got EMM caSys=%.4x",caSys);
00614     if(CanHandleEMM(caSys)) {
00615       LDUMP(L_CC_CAMDEXTR,&data[0],10,"EMM starts with");
00616       int upd;
00617       cProvider *p;
00618       cAssembleData ad(data);
00619       if(MatchAndAssemble(&ad,&upd,&p)) {
00620         PRINTF(L_CC_CAMDEXTR,"EMM matched upd=%d provId=%.4llx",upd,p ? p->ProvId() : 0);
00621         while((data=ad.Assembled())) {
00622           LDUMP(L_CC_CAMDEXTR,&data[0],10,"processing assembled EMM");
00623           if(Dx[upd]) {
00624             unsigned char buff[300];
00625             memset(buff,0xff,sizeof(buff));
00626             struct CmdBlock *cb=(struct CmdBlock *)buff;
00627             cb->udp_header.cmd=emmCmd06 ? 0x06 : 0x02;
00628             cb->service.srvID=0;
00629             cb->service.casID=bswap_16(caSys);
00630             cb->service.prvID=bswap_32(p ? p->ProvId() : 0);
00631             cb->service.pinID=pinid++;
00632             int len=SCT_LEN(data), off=0;
00633             switch(caSys>>8) {
00634               case 0x0d:
00635                 {
00636                 static const unsigned char head[] = { 0x8F,0x70,0x00,0xA4,0x42,0x00,0x00,0x00 };
00637                 int c, n;
00638                 switch(data[0]) {
00639                   case 0x82: c=0x42; n=10; break;
00640                   case 0x84: c=0x48; n=9; break;
00641                   case 0x88:
00642                   case 0x89: c=0x44; n=5; break;
00643                   default:   continue;
00644                   }
00645                 if(len<n) continue;
00646                 off=sizeof(head);
00647                 memcpy(&cb->data[0],head,off);
00648                 cb->data[3+1]=c;
00649                 cb->data[3+4]=len-n;
00650                 SetSctLen(&cb->data[0],len-n+5);
00651                 data+=n; len-=n;
00652                 break;
00653                 }
00654               }
00655             if(len+off<=255) {
00656               memcpy(&cb->data[off],data,len);
00657               int id=msEMM.Get(&cb->data[0],len+off,0);
00658               if(id>0 || emmAllowed>1) {
00659                 SendBlock(cb,len+off);
00660                 msEMM.Cache(id,true,0);
00661                 }
00662               else PRINTF(L_CC_CAMDEXTR,"not send, already in cache");
00663               }
00664             else PRINTF(L_CC_EMM,"%s: EMM length %d > 255, not supported by UDP protocol",name,len+off);
00665             }
00666           else PRINTF(L_CC_CAMDEXTR,"dropped, updtype %d blocked",upd);
00667           }
00668         return true;
00669         }
00670       else PRINTF(L_CC_CAMDEXTR,"dropped, doesn't match card data");
00671       }
00672     else PRINTF(L_CC_CAMDEXTR,"dropped, doesn't want caSys %.4x",caSys);
00673     }
00674   return false;
00675 }
00676 
00677 bool cCardClientCamd35::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
00678 {
00679   bool res=false;
00680   const int length=SCT_LEN(data);
00681   if(length<=255) {
00682     Lock();
00683     while(exclusive) sleepCond.Wait(*this);
00684     unsigned char buff[300];
00685     memset(buff,0xff,sizeof(buff));
00686     struct CmdBlock *cb=(struct CmdBlock *)buff;
00687     const unsigned short pid=pinid++;
00688     int n;
00689     while((n=RecvBlock(cb,sizeof(buff),0))>0) {
00690       if(cb->udp_header.cmd==0x01 || cb->udp_header.cmd==0x44)
00691         PRINTF(L_CC_CAMD35,"unexpected CW answer on flush");
00692       else
00693         HandleEMMRequest(cb);
00694       }
00695     cb->udp_header.cmd=0x00;
00696     cb->service.srvID=bswap_16(ecm->prgId);
00697     cb->service.casID=bswap_16(ecm->caId);
00698     cb->service.prvID=bswap_32(ecm->provId);
00699     cb->service.pinID=pid;
00700     memcpy(&cb->data[0],data,length);
00701     if(SendBlock(cb,length)) {
00702       exclusive=true;
00703       time.Set(CCTIMEOUT);
00704       do {
00705         sleepCond.TimedWait(*this,50);
00706         while((n=RecvBlock(cb,sizeof(buff),0))>0) {
00707           if(cb->udp_header.cmd==0x01) {
00708             if(cb->udp_header.len>=16 && cb->service.pinID==pid && !res) {
00709               if(!CheckNull(&cb->data[0],8)) memcpy(&cw[0],&cb->data[0],8);
00710               if(!CheckNull(&cb->data[8],8)) memcpy(&cw[8],&cb->data[8],8);
00711               res=true;
00712               }
00713             else PRINTF(L_CC_CAMD35,"unexpected/bad CW packet");
00714             }
00715           else if(cb->udp_header.cmd==0x44) {
00716             if(cb->service.pinID==pid) {
00717               PRINTF(L_CC_ECM,"%s: server is unable to handle ECM",name);
00718               n=-1;
00719               break;
00720               }
00721             }
00722           else HandleEMMRequest(cb);
00723           }
00724         } while(!res && n>=0 && !time.TimedOut());
00725       if(!res && time.TimedOut()) PRINTF(L_CC_ECM,"%s: CW request timed out",name);
00726       exclusive=false;
00727       sleepCond.Broadcast();
00728       }
00729     Unlock();
00730     }
00731   else PRINTF(L_CC_ECM,"%s: ECM length %d > 255, not supported by UDP protocol",name,length);
00732   return res;
00733 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines