]> www.vanbest.org Git - sasc-ng.git/commitdiff
add initial version of real CCcam client (cccam2)
authorleslie <unknown>
Wed, 29 Jul 2009 09:09:53 +0000 (17:09 +0800)
committerleslie <unknown>
Wed, 29 Jul 2009 09:09:53 +0000 (17:09 +0800)
examples/cardclient.conf.example
systems/cardclient/cc.mk
systems/cardclient/cccam2.c [new file with mode: 0644]

index afdc68565037f993781c642be9fba43a2fbb801f..efb9c01d7e7f3ae26891c47b2461b6e2f79a6373 100644 (file)
@@ -47,10 +47,16 @@ newcamd:hostname:port:emm/caid/mask:username:password:cfgKey
 # machine. For convinience you should choose localhost:8004
 gbox:hostname:port:emm/caid/mask
 #
-# ccam client
+# cccam client (via LD_PRE_LOAD wrapper)
 #
 # NOTE: hostname will be ignore. CCcam must be runnning on the local machine
 # 'socket' is the name of the camd socket file. For multiple cards add %d
 # into the string. This will be replaced with the number 0-3.
 # e.g. /var/emu/chroot%d/tmp/camd.socket
 cccam:hostname:port:emm/caid/mask:socket
+#
+# (the real) cccam client
+#
+# NOTE: this is a real client. You don't need to have CCcam running on local
+# machine.
+cccam2:hostname:port:emm/caid/mask:username:password
index 468828ac992780f709385b7260f5134259f88c46..75ae5ec12fd967829d05ea3b4bf0a6d88ab015ed 100644 (file)
@@ -2,5 +2,5 @@
 # Cardclient
 #
 TARGET = cardclient
-OBJS   = cc.o camd.o radegast.o aroureos.o newcamd.o gbox.o cccam.o
+OBJS   = cc.o camd.o radegast.o aroureos.o newcamd.o gbox.o cccam.o cccam2.o
 LIBS   = -lcrypto -lcrypt
diff --git a/systems/cardclient/cccam2.c b/systems/cardclient/cccam2.c
new file mode 100644 (file)
index 0000000..e34e57d
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+* 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
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <boost/scoped_array.hpp>
+#include <openssl/sha.h>
+#include "cc.h"
+#include "network.h"
+
+typedef unsigned char node_id[8];
+
+struct cccam_crypt_block
+{
+   unsigned char keytable[256];
+   unsigned char state;
+   unsigned char counter;
+   unsigned char sum;
+};
+
+
+// -- cHandlerItem -------------------------------------------------------------
+
+class cHandlerItem : public cSimpleItem {
+   private:
+      int handlerid,caid,provid;
+   public:
+      cHandlerItem(int Handlerid, int Caid, int Provid);
+      int GetHandlerID(void){ return handlerid; };
+      int GetCaID(void) { return caid;};
+      int GetProvID(void) { return provid; };
+};
+
+cHandlerItem::cHandlerItem(int Handlerid, int Caid, int Provid)
+{
+   handlerid=Handlerid;
+   caid=Caid;
+   provid=Provid;
+}
+
+class cHandlers {
+   public:
+      cSimpleList<cHandlerItem>  cHandlerList;
+};
+
+// -- cCCcam2Card ---------------------------------------------------------------
+
+class cCCcam2Card : public cMutex {
+   private:
+      bool newcw;
+      unsigned char cw[16];
+      cCondVar cwwait;
+   public:
+      cCCcam2Card(void);
+      bool GetCw(unsigned char *Cw);
+      void NewCw(const unsigned char *Cw, bool result);
+};
+
+cCCcam2Card::cCCcam2Card(void) {
+   newcw=false;
+}
+
+void cCCcam2Card::NewCw(const unsigned char *Cw, bool result)
+{
+  cMutexLock lock(this);
+  if(result) {
+     newcw=true;
+     memcpy(cw,Cw,sizeof(cw));
+  }else{
+     newcw=false;
+  }
+  cwwait.Broadcast();
+}
+
+bool cCCcam2Card::GetCw(unsigned char *Cw)
+{
+  cMutexLock lock(this);
+  if(!newcw) cwwait.Wait(*this);
+  if(newcw) {
+    memcpy(Cw,cw,sizeof(cw));
+    newcw=false;
+    return true;
+    }
+  return false;
+}
+
+// -- cCardClientCCcam2 ---------------------------------------------------------
+
+class cCardClientCCcam2 : public cCardClient , private cThread {
+private:
+   cCCcam2Card card;
+   cHandlers *handlers;
+  cNetSocket so;
+   node_id nodeid;
+   int server_packet_count;
+   bool login_completed;
+   struct cccam_crypt_block client_encrypt_state,client_decrypt_state;
+   unsigned char buffer[3072];
+   unsigned char recvbuff[3072];
+   unsigned char netbuff[1024];
+   int shareid;
+   unsigned char cwdata[16];
+   char username[20], password[20];
+   bool getcards;
+
+   bool check_connect_checksum( unsigned char* data, int length );
+   void cccam_xor( unsigned char* data, int length );
+   int cccam_init_crypt( cccam_crypt_block* block, const unsigned char* key, int length );
+   int cccam_decrypt( cccam_crypt_block* block, const unsigned char* in, unsigned char* out, int length );
+   int cccam_encrypt( cccam_crypt_block* block, const unsigned char* in, unsigned char* out, int length );
+   inline unsigned int pow_of_two( unsigned int n );
+   inline unsigned int shift_right_and_fill( unsigned int value, unsigned int fill, unsigned int places );
+   void scramble_dcw( unsigned char* data, unsigned int length, node_id nodeid, unsigned int shareid );
+   bool dcw_checksum( unsigned char *data);
+   bool packet_analyzer(cccam_crypt_block* block,unsigned char* data, int length);
+protected:
+  virtual bool Login(void);
+  virtual void Action(void);
+public:
+  cCardClientCCcam2(const char *Name);
+  ~cCardClientCCcam2();
+  virtual bool Init(const char *CfgDir);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+  virtual bool ProcessEMM(int caSys, const unsigned char *data);
+  };
+
+static cCardClientLinkReg<cCardClientCCcam2> __ncd("cccam2");
+
+cCardClientCCcam2::cCardClientCCcam2(const char *Name)
+:cCardClient(Name)
+,cThread("CCcam listener")
+,so(DEFAULT_CONNECT_TIMEOUT,20,DEFAULT_IDLE_TIMEOUT)
+{
+  server_packet_count=0;
+  login_completed=false;
+  bzero(client_encrypt_state.keytable,sizeof(client_encrypt_state.keytable));
+   bzero(client_decrypt_state.keytable,sizeof(client_decrypt_state.keytable));
+   bzero(nodeid,sizeof(nodeid));
+   bzero(buffer,sizeof(buffer));
+   bzero(cwdata,sizeof(cwdata));
+   handlers=new cHandlers();
+   shareid=0;
+   getcards=false;
+}
+
+cCardClientCCcam2::~cCardClientCCcam2()
+{
+   so.Disconnect();
+  Cancel(3);
+}
+
+bool cCardClientCCcam2::check_connect_checksum( unsigned char* data, int length )
+{
+    bool valid=false;
+   if (length == 16)  {
+      unsigned char sum1( data[0] + data[4] + data[8] );
+      unsigned char sum2( data[1] + data[5] + data[9] );
+      unsigned char sum3( data[2] + data[6] + data[10] );
+      unsigned char sum4( data[3] + data[7] + data[11] );
+      valid = ( ( sum1 == data[12] ) && ( sum2 == data[13] ) && ( sum3 == data[14] ) && ( sum4 == data[15] ) );
+   }
+   return valid;
+}
+
+void cCardClientCCcam2::cccam_xor(unsigned char* data, int length)
+{
+    if (data == 0) return;
+   if ( length >= 16 )   {
+      const char* cccam="CCcam";
+      unsigned char index(0);
+      do
+      {
+         *(data + 8) = index * (*data);
+          if ( index <= 5 ) *data ^= cccam[index];
+         ++index;
+         ++data;
+      }
+      while( index < 8 );
+   }
+}
+
+int cCardClientCCcam2::cccam_init_crypt( cccam_crypt_block* block, const unsigned char* key, int length )
+{
+   int result=0;
+  if ( block == 0 )  return result;
+  unsigned char* keytable( &block->keytable[0] );
+  unsigned char* it( &block->keytable[0] );
+  unsigned char prev_char( 0 );
+  unsigned char curr_char( 0 );
+  int pos=0;
+  do
+   {
+      keytable[pos] = pos;
+      ++pos;
+   }
+   while ( pos <= 255 );
+   block->counter = 0;
+   block->sum = 0;
+   pos = 0;
+   do
+   {
+      curr_char = keytable[pos++] + *reinterpret_cast<const unsigned char*>(key + result);
+      curr_char += prev_char;
+      prev_char = curr_char;
+      std::swap( *it++, *(keytable + curr_char) );
+      result = ( result + 1 ) % length;
+   }
+   while ( pos <= 255 );
+   block->state = *key;
+   return result;
+}
+
+int cCardClientCCcam2::cccam_decrypt( cccam_crypt_block* block, const unsigned char* in, unsigned char* out, int length )
+{
+   if ( block == 0 ) return 0;
+   unsigned char* keytable( &block->keytable[0] );
+   int pos( 0 );
+    do
+    {
+      unsigned char in_xor( *(in + pos) ^ block->state );
+      unsigned char key_sum( block->sum + *(keytable + ++block->counter) );
+      block->sum += *(keytable + block->counter);
+      std::swap( *(keytable + block->counter), *(keytable + key_sum) );
+      unsigned char out_xor( in_xor ^ *(keytable + (unsigned char)(*(keytable + key_sum) + *(keytable + block->counter))) );
+      *(out + pos) = out_xor;
+      block->state ^= out_xor;
+      ++pos;
+    }
+    while ( pos < length );
+   return length;
+}
+
+int cCardClientCCcam2::cccam_encrypt( cccam_crypt_block* block, const unsigned char* in, unsigned char* out, int length )
+{
+   if ( block == 0 )   return 0;
+   unsigned char* keytable( &block->keytable[0] );
+   int pos( 0 );
+   do
+   {
+      unsigned char key_sum( block->sum + *(keytable + ++block->counter) );
+      block->sum += *(keytable + block->counter);
+      std::swap( *(keytable + block->counter), *(keytable + key_sum) );
+      unsigned char state( *(in + pos) ^ *(keytable  + (unsigned char)(*(keytable + key_sum) + *(keytable + block->counter))) );
+      *(out + pos) = block->state ^ state;
+      block->state ^= *(in + pos++);
+   }
+   while ( pos < length );
+   return length;
+}
+
+inline unsigned int cCardClientCCcam2::pow_of_two( unsigned int n )
+{
+   uint result( 1 );
+  for ( uint i( 0 ); i < n; ++i) result *= 2;
+  return result;
+}
+
+inline unsigned int cCardClientCCcam2::shift_right_and_fill( unsigned int value, unsigned int fill, unsigned int places )
+{
+   return ( value >> places ) | ( ( ( pow_of_two( places ) - 1 ) & fill ) << ( 32 - places ) );
+}
+
+void cCardClientCCcam2::scramble_dcw( unsigned char* data, unsigned int length, node_id nodeid, unsigned int shareid)
+{
+    unsigned int i( 0 );
+   int s( 0 );
+   int nodeid_high( ( nodeid[0] << 24 ) | ( nodeid[1] << 16 ) | ( nodeid[2] << 8 ) | nodeid[3] );
+   int nodeid_low( ( nodeid[4] << 24 ) | ( nodeid[5] << 16 ) | ( nodeid[6] << 8 ) | nodeid[7] );
+   do
+   {
+      /* Nible index, 0..4..8 */
+      char nible_index( i + s );
+      /* Shift one nible to the right for high and low nodeid */
+      /* Make sure the first shift is an signed one (sar on intel), else you get wrong results! */
+      int high( nodeid_high >> nible_index );
+      int low( shift_right_and_fill( nodeid_low, nodeid_high, nible_index ) );
+      /* After 8 nibles or 32 bits use bits from high, based on signed flag it will be 0x00 or 0xFF */
+      if ( nible_index & 32 )
+         low = high & 0xFF;
+      char final( *(data + i) ^ ( low & 0xFF ) );
+      /* Odd index inverts final */
+      if ( i & 0x01 )
+         final = ~final;
+      /* Result */
+      *(data + i) = ( ( shareid >> ( 2 * ( i & 0xFF ) ) ) & 0xFF ) ^ final;
+      ++i;
+      s += 3;
+    }
+    while ( i < length );
+}
+
+bool cCardClientCCcam2::dcw_checksum( unsigned char *data)
+{
+   if( ((data[0] + data[1] + data[2]) & 0xff)==data[3] &&
+         ((data[4] + data[5] + data[6]) & 0xff)==data[7] &&
+         ((data[8] + data[9] + data[10]) & 0xff)==data[11] &&
+         ((data[12] + data[13] + data[14]) & 0xff)==data[15] )
+      return true;
+   return false;
+}
+
+bool cCardClientCCcam2::packet_analyzer(cccam_crypt_block* block,unsigned char* data, int length)
+{
+   if (length<4) return false;
+   int cccam_command=data[1];
+   int packet_len=(data[2] & 0xff) <<8 | (data[3] & 0xff);
+   int wp=4;
+   char str[32];
+   if ((packet_len + 4)>length) return false;
+   if(packet_len>=0) {
+      switch(cccam_command) {
+         case  0: {
+            break;
+         }
+         case 1: {
+            unsigned char tempcw[16];
+            memcpy(tempcw,data+4,16);
+            scramble_dcw( tempcw, 16, nodeid, shareid );
+            if (dcw_checksum(tempcw)) {
+               memcpy(cwdata,tempcw,16);
+            }
+            card.NewCw(cwdata,true);
+            unsigned char temp[16];
+            cccam_decrypt(block,tempcw,temp,16);
+            break;
+         }
+         case 4: {
+            int handler=(data[0+4] & 0xff)<<24 | (data[1+4] & 0xff)<<16 |(data[2+4] & 0xff)<<8 | (data[3+4] & 0xff);
+            for ( cHandlerItem *hv=handlers->cHandlerList.First(); hv; hv=handlers->cHandlerList.Next(hv))
+            {
+               if(hv->GetHandlerID()==handler) handlers->cHandlerList.Del(hv);
+               PRINTF(L_CC_CCCAM,"REMOVE handler %08x caid: %04x provider: %06x",hv->GetHandlerID(),hv->GetCaID(),hv->GetProvID());
+            }
+            break;
+         }
+         case 7: {
+            int caid=(data[8+4] & 0xff )<< 8 | (data[9+4] & 0xff);
+            int handler=(data[0+4] & 0xff)<<24 | (data[1+4] & 0xff)<<16 |(data[2+4] & 0xff)<<8 | (data[3+4] & 0xff);
+           int provider_counts=data[20+4] & 0xff;
+           int uphops=data[10+4];
+           int maxdown=data[11+4];
+           PRINTF(L_CC_CCCAM,"handler %08x serial %s uphops %d maxdown %d",handler,HexStr(str,data+12+4,8),uphops,maxdown);
+           for(int i=0;i<provider_counts;i++) {
+              int provider=(data[21+4+i*7] & 0xff)<<16 | (data[22+4+i*7] & 0xff)<<8 | (data[23+4+i*7] & 0xff);
+              cHandlerItem *n=new cHandlerItem(handler,caid,provider);
+              handlers->cHandlerList.Add(n);
+              PRINTF(L_CC_CCCAM,"ADD handler %08x caid: %04x provider: %06x",handler,caid,provider);
+           }
+           getcards=true;
+            break;
+         }
+         case 8: {
+            PRINTF(L_CC_CCCAM,"Server NodeId %s",HexStr(str,data+wp,8));
+            wp+=8;
+            PRINTF(L_CC_CCCAM,"Server Version: %s",data+wp);
+            wp+=32;
+            PRINTF(L_CC_CCCAM,"Builder Version: %s",data+wp);
+            break;
+         }
+         case 0xfe:{
+            PRINTF(L_CC_CCCAM,"cccam can't decode this ecm");
+            card.NewCw(cwdata,false);
+            break;
+         }
+         case 0xff:{
+            PRINTF(L_CC_CCCAM,"cccam can't decode this ecm");
+            card.NewCw(cwdata,false);
+            break;
+         }
+         default: {
+            break;
+         }
+      }
+   }
+   if((packet_len+4)<length) packet_analyzer(block,data+4+packet_len,length-4-packet_len);
+   return true;
+}
+
+bool cCardClientCCcam2::Init(const char *config)
+{
+  cMutexLock lock(this);
+  int num=0;
+  int randomfd=open("/dev/urandom",O_RDONLY|O_NONBLOCK);
+  if(randomfd<0) return false;
+  int len=read(randomfd,nodeid,sizeof(nodeid));
+  close(randomfd);
+  if (len!=sizeof(nodeid)) return false;
+  if(!ParseStdConfig(config,&num)
+     || sscanf(&config[num],":%40[^:]:%40[^:]",username,password)!=2 ) return false;
+  char str[32];
+  PRINTF(L_CC_CORE,"%s: username=%s password=%s nodeid=%s",name,username,password,HexStr(str,nodeid,sizeof(nodeid)));
+  return Immediate() ? Login() : true;
+}
+
+bool cCardClientCCcam2::Login(void)
+{
+   const char *str="CCcam";
+   unsigned char clientinfo[]={
+      0x00,
+      //CCcam command
+      0x00,
+      //packet length
+      0x00,0x5D,
+      #define USERNAME_POS 4
+      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+      0x00,0x00,0x00,0x00,
+      #define NODEID_POS 24
+      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+      #define WANTEMU_POS 32
+      0x00,
+      #define VERSION_POS 33
+      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+      #define BUILDERNUM_POS 65
+      0x32,0x38,0x39,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+   };
+   boost::scoped_array<unsigned char> do_not_overwrite( new unsigned char[20] );
+   boost::scoped_array<unsigned char> response( new unsigned char[20] );
+   boost::scoped_array<unsigned char> sendbuff( new unsigned char[20] );
+   boost::scoped_array<unsigned char> hash(new unsigned char[20]);
+  cMutexLock lock(this);
+  login_completed=false;
+  getcards=false;
+  server_packet_count=0;
+  int len=0;
+  so.Disconnect();
+  if(!so.Connect(hostname,port)) return false;
+   while(len=so.Read(buffer,sizeof(buffer),-1)) {
+     if (server_packet_count > 0) {
+        cccam_decrypt( &client_decrypt_state, buffer, buffer, len );
+        HEXDUMP(L_CC_CCCAM,buffer,len,"Receive Messages");
+     }
+     if (login_completed) {
+        packet_analyzer(&client_decrypt_state,buffer,len);
+        if(getcards)  {
+           Start();
+           return true;
+        }
+     }
+     switch ( server_packet_count ) {
+        case 0:
+           if(len!=16) return false;
+           if(!check_connect_checksum(buffer,len)) return false;
+           PRINTF(L_CC_CCCAM,"Receive Message CheckSum correct");
+           cccam_xor(buffer,len);
+
+           SHA_CTX ctx;
+           SHA1_Init( &ctx );
+            SHA1_Update( &ctx, buffer, len);
+            SHA1_Final( hash.get(),&ctx );
+
+            cccam_init_crypt( &client_decrypt_state, hash.get(), 20 );
+            cccam_decrypt( &client_decrypt_state, buffer, buffer, 16 );
+            cccam_init_crypt( &client_encrypt_state, buffer, 16 );
+            cccam_encrypt( &client_encrypt_state, hash.get(), hash.get(), 20 );
+
+            HEXDUMP(L_CC_CCCAM,hash.get(),20,"Send Messages");
+            cccam_encrypt( &client_encrypt_state, hash.get(), response.get(), 20 );
+            so.Write(response.get(),20);
+            bzero(response.get(),20);
+            bzero(sendbuff.get(),20);
+            strcpy(reinterpret_cast<char*>(response.get()),username);
+            HEXDUMP(L_CC_CCCAM,response.get(),20,"Send UserName Messages");
+            cccam_encrypt( &client_encrypt_state, response.get(), sendbuff.get(), 20 );
+           so.Write(sendbuff.get(),20);
+           bzero(response.get(),20);
+            bzero(sendbuff.get(),20);
+            strcpy(reinterpret_cast<char*>(response.get()),password);
+            HEXDUMP(L_CC_CCCAM,response.get(),20,"Password");
+            cccam_encrypt( &client_encrypt_state, response.get(), sendbuff.get(), strlen(password));
+            bzero(sendbuff.get(),20);
+            cccam_encrypt( &client_encrypt_state,reinterpret_cast<const unsigned char*>(str), sendbuff.get(), 6 );
+            so.Write(sendbuff.get(),6);
+            break;
+         case 1:
+            if (len < 20) break;
+            if(strcmp("CCcam", reinterpret_cast<char*>(buffer))==0) {
+               login_completed=true;
+               PRINTF(L_CC_CORE,"CCcam login Success!");
+               strcpy(reinterpret_cast<char*>(clientinfo + USERNAME_POS),username);
+               strcpy(reinterpret_cast<char*>(clientinfo + VERSION_POS),"vdr-sc");
+               memcpy(clientinfo + NODEID_POS,nodeid,8);
+               bzero(netbuff,sizeof(netbuff));
+               cccam_encrypt( &client_encrypt_state,reinterpret_cast<const unsigned char*>(&clientinfo),
+                reinterpret_cast<unsigned char*>(&netbuff), sizeof(clientinfo) );
+               so.Write(netbuff,sizeof(clientinfo));
+            }else{
+               return false;
+            }
+            break;
+         default:
+            break;
+     }
+     server_packet_count++;
+  }
+  return false;
+}
+
+bool cCardClientCCcam2::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+{
+   const unsigned char ecm_head[]={
+      0x00,
+      #define CCCAM_COMMAND_POS 1
+      0x01,
+      #define CCCAM_LEN_POS 2
+      0x00,0x00,
+      #define ECM_CAID_POS 4
+      0x00,0x00,
+      0x00,
+      #define ECM_PROVIDER_POS 7
+      0x00,0x00,0x00,
+      #define ECM_HANDLER_POS 10
+      0x00,0x00,0x00,0x00,
+      #define ECM_SID_POS 14
+      0x00,0x00,
+      #define ECM_LEN_POS 16
+      0x00,
+      #define ECM_DATA_POS 17
+   };
+  cMutexLock lock(this);
+  if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
+  cCCcam2Card *c=&card;
+  shareid=0;
+  bzero(buffer,sizeof(buffer));
+  memcpy(buffer,ecm_head,sizeof(ecm_head));
+  memcpy(buffer+sizeof(ecm_head),data,SCT_LEN(data));
+  int ecm_len=sizeof(ecm_head)+SCT_LEN(data);
+  buffer[CCCAM_COMMAND_POS]=1;
+  buffer[CCCAM_LEN_POS]=((ecm_len-4) >>8) & 0xff;
+  buffer[CCCAM_LEN_POS+1]=(ecm_len-4) & 0xff;
+  buffer[ECM_CAID_POS]=(ecm->caId >> 8) & 0xFF;
+  buffer[ECM_CAID_POS+1]=ecm->caId & 0xFF;
+  buffer[ECM_PROVIDER_POS]=(ecm->provId >>16) & 0xFF;
+  buffer[ECM_PROVIDER_POS+1]=(ecm->provId >>8) & 0xFF;
+   buffer[ECM_PROVIDER_POS+2]=ecm->provId & 0xFF;
+   buffer[ECM_SID_POS]=(ecm->prgId >> 8) & 0xFF;
+   buffer[ECM_SID_POS+1]=ecm->prgId & 0xFF;
+   buffer[ECM_LEN_POS]=SCT_LEN(data);
+   for ( cHandlerItem *hv=handlers->cHandlerList.First(); hv; hv=handlers->cHandlerList.Next(hv))
+   {
+      if(ecm->caId >= 0x500 && ecm->caId <= 0x05FF){
+         if(hv->GetCaID()==ecm->caId && hv->GetProvID()==ecm->provId) shareid=hv->GetHandlerID();
+      }
+      else if((ecm->caId >= 0x1800 && ecm->caId <= 0x18FF)
+         || (ecm->caId>= 0x0600 && ecm->caId <= 0x06FF)
+         || (ecm->caId >= 0x0900 && ecm->caId <= 0x09FF)
+         || ecm->caId == 0x0B00){
+         if(hv->GetCaID()==ecm->caId) shareid=hv->GetHandlerID();
+      }else{
+         if(hv->GetCaID()==ecm->caId && hv->GetProvID()==ecm->provId) shareid=hv->GetHandlerID();
+      }
+   }
+   PRINTF(L_CC_CORE,"%d: Ecm CaID %04x Provider %04x",cardnum,ecm->caId,ecm->provId);
+   if(shareid==0) return false;
+   buffer[ECM_HANDLER_POS]=(shareid>>24) & 0xFF;
+   buffer[ECM_HANDLER_POS+1]=(shareid>>16) & 0xFF;
+   buffer[ECM_HANDLER_POS+2]=(shareid>>8) & 0xFF;
+   buffer[ECM_HANDLER_POS+3]=shareid & 0xFF;
+   PRINTF(L_CC_CORE,"%d: Find Server HandlerID %x",cardnum,shareid);
+   HEXDUMP(L_CC_CCCAM,buffer,ecm_len,"%d: Send ECM Messages",cardnum);
+   cccam_encrypt( &client_encrypt_state,buffer,netbuff,ecm_len);
+   so.Write(netbuff,ecm_len);
+   if(!c->GetCw(cw)) return false;
+   PRINTF(L_CC_CCCAM,"%d: got CW",cardnum);
+   return true;
+}
+
+bool cCardClientCCcam2::ProcessEMM(int caSys, const unsigned char *data)
+{
+   return false;
+}
+
+void cCardClientCCcam2::Action(void)
+{
+   while(Running()) {
+              usleep(100);
+      bzero(recvbuff,sizeof(recvbuff));
+     int len=so.Read(recvbuff,sizeof(recvbuff),0);
+     if(len>0) {
+         cccam_decrypt( &client_decrypt_state, recvbuff, recvbuff, len );
+         HEXDUMP(L_CC_CCCAM,recvbuff,len,"Receive Messages");
+         packet_analyzer(&client_decrypt_state,recvbuff,len);
+      }
+   }
+}