⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smartcard.c

📁 这是一个LINUX环境的 VDR 插件源代码,可支持Irdeto, Seca, Viaccess, Nagra, Conax & Cryptoworks等CA系统的读卡、共享等操作。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 <stdlib.h>#include <stdio.h>#include <string.h>#include <stdarg.h>#include <errno.h>#include <fcntl.h>#include <sys/ioctl.h>#include <sys/poll.h>#include <unistd.h>#include <termios.h>#include <linux/serial.h>#include <ctype.h>#include <vdr/tools.h>#include <vdr/thread.h>#include "smartcard.h"#include "misc.h"#include "log-core.h"#define DATAFILE "smartcard.conf"#define ISO_FREQ 3571200 // Hz//#define SER_EMU   // use serial emulation (select one of the following)//#define EMU_SECA  // fake Seca card//#define EMU_IRD   // fake Irdeto/Beta card//#define EMU_IRD_384 // fake ACS 384, if undefined ACS 383//#define EMU_CRYPTO // fake Cryptoworks card//#define NO_PTS_PROTO // disable PTS protocol (baudrate changes)struct BaudRates {  int real;  speed_t apival;  };static const struct BaudRates BaudRateTab[] = {  {   9600, B9600   },  {  19200, B19200  },  {  38400, B38400  },  {  57600, B57600  },  { 115200, B115200 },  { 230400, B230400 }  };// -- cSerial ------------------------------------------------------------------class cSerial {private:  char *devName;  int fd;  int currMode, statInv;  bool invRST;  //  speed_t FindBaud(int baud);#ifdef SER_EMU  unsigned char devBuff[1024], nextSW[SB_LEN];  int buffCount, dataLen, record;  bool cmdStart, rts, dsr, flag;  int remTime;#endifpublic:  cSerial(const char *DevName, bool invCD, bool InvRST);  ~cSerial();  bool Open(void);  bool SetMode(int mode, int baud=9600);  int CurrentMode(void) const { return currMode; }  void Flush(void);  int Read(unsigned char *mem, int len, int timeout, int initialTimeout=0);  int Write(const unsigned char *mem, int len, int delay=0);  void ToggleRTS(void);  bool CheckCAR(void);  void Close(void);  const char *DeviceName(void) const { return devName; }  };cSerial::cSerial(const char *DevName, bool invCD, bool InvRST){  devName=strdup(DevName);  statInv=invCD ? TIOCM_CAR:0;  invRST=InvRST;  fd=-1; currMode=SM_NONE;}cSerial::~cSerial(){  Close();  free(devName);}#ifndef SER_EMUbool cSerial::Open(void){  PRINTF(L_CORE_SERIAL,"%s: open serial port",devName);  fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY);  if(fd>=0) {    PRINTF(L_CORE_SERIAL,"%s: set DTR/RTS",devName);    unsigned int modembits;    modembits=TIOCM_DTR; CHECK(ioctl(fd, TIOCMBIS, &modembits));    modembits=TIOCM_RTS; CHECK(ioctl(fd, invRST?TIOCMBIS:TIOCMBIC, &modembits));    PRINTF(L_CORE_SERIAL,"%s: init done",devName);    return true;    }  else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));  return false;}void cSerial::Close(void){  if(fd>=0) {    PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);    Flush();    unsigned int modembits=0;    CHECK(ioctl(fd,TIOCMSET,&modembits));    close(fd); fd=-1;    PRINTF(L_CORE_SERIAL,"%s: shutdown done",devName);    }}speed_t cSerial::FindBaud(int baud){  for(int i=0; i<(int)(sizeof(BaudRateTab)/sizeof(struct BaudRates)); i++) {    int b=BaudRateTab[i].real;    int d=((b-baud)*10000)/b;    if(abs(d)<=300) {      PRINTF(L_CORE_SERIAL,"%s: requested baudrate %d -> %d (%+.2f%%)",devName,baud,b,(float)d/100.0);      return BaudRateTab[i].apival;      }    }  PRINTF(L_CORE_SERIAL,"%s: requested baudrate %d -> custom",devName,baud);  return B0;}bool cSerial::SetMode(int mode, int baud){  if(fd>=0) {    speed_t bconst=FindBaud(baud);    bool custom=false;    if(bconst==B0) { custom=true; bconst=B38400; }        struct termios tio;    memset(&tio,0,sizeof(tio));    LBSTARTF(L_CORE_SERIAL);    LBPUT("%s: set serial options: %d,",devName,baud);    tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);    if(!(mode&SM_1SB)) tio.c_cflag |= CSTOPB;    tio.c_iflag = (INPCK | BRKINT);    tio.c_cc[VMIN] = 1;    cfsetispeed(&tio,bconst);    cfsetospeed(&tio,bconst);    switch(mode&SM_MASK) {      case SM_8E2:         LBPUT("8e%d",(mode&SM_1SB)?1:2);        tio.c_cflag |= PARENB; break;      case SM_8N2:        LBPUT("8n%d",(mode&SM_1SB)?1:2);        break;      case SM_8O2:        LBPUT("8o%d",(mode&SM_1SB)?1:2);        tio.c_cflag |= (PARENB | PARODD); break;      default:        LBPUT("BAD MODE");        return false;      }    LBEND();    struct serial_struct s;    if(ioctl(fd,TIOCGSERIAL,&s)<0) {      PRINTF(L_GEN_ERROR,"%s: get serial failed: %s",devName,strerror(errno));      return false;      }    if(!custom && ((s.flags&ASYNC_SPD_MASK)==ASYNC_SPD_CUST || s.custom_divisor!=0)) {      s.custom_divisor=0;      s.flags &= ~ASYNC_SPD_MASK;      if(ioctl(fd,TIOCSSERIAL,&s)<0) {        PRINTF(L_GEN_ERROR,"%s: set serial failed: %s",devName,strerror(errno));        return false;        }      }    if(!tcsetattr(fd,TCSANOW,&tio)) {      if(custom) {        s.custom_divisor=(s.baud_base+(baud/2))/baud;        s.flags=(s.flags&~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;        PRINTF(L_CORE_SERIAL,"%s: custom: baud_base=%d baud=%d devisor=%d -> effective baudrate %d (%+.2f%% off)",devName,s.baud_base,baud,s.custom_divisor,s.baud_base/s.custom_divisor,(float)(s.baud_base/s.custom_divisor-baud)/(float)baud);        if(ioctl(fd,TIOCSSERIAL,&s)<0) {          PRINTF(L_GEN_ERROR,"%s: set serial failed: %s",devName,strerror(errno));          return false;          }        }      currMode=mode; Flush();      return true;      }    else PRINTF(L_GEN_ERROR,"%s: tcsetattr failed: %s",devName,strerror(errno));    }  return false;}void cSerial::Flush(void){  if(fd>=0)    CHECK(tcflush(fd,TCIOFLUSH));}int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout){  PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d:%d",devName,len,timeout,initialTimeout);  bool incomplete=false;  if(len<0) { len=-len; incomplete=true; }  int to=initialTimeout>0 ? initialTimeout : timeout;  int n=0;  while(n<len) {    int r=read(fd,mem+n,len-n);    if(r<=0) {      if(r==0) PRINTF(L_CORE_SERIAL,"%s: read bogus eof",devName);      if(errno==EAGAIN) {        struct pollfd u;        u.fd=fd; u.events=POLLIN;        r=poll(&u,1,to);        if(r<0) {          PRINTF(L_GEN_ERROR,"%s: read poll failed: %s",devName,strerror(errno));          return -1;          }        else if(r==0) { // timeout          PRINTF(L_CORE_SERIAL,"%s: read timeout (%d ms)",devName,to);          if(n>0 && incomplete) break; // return bytes read so far          return -2;          }        continue;        }      else {        PRINTF(L_GEN_ERROR,"%s: read failed: %s",devName,strerror(errno));        return -1;        }      }    n+=r; to=timeout;    }  HEXDUMP(L_CORE_SERIAL,mem,n,"%s: read data",devName);  return n;}int cSerial::Write(const unsigned char *mem, int len, int delay){  PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);  HEXDUMP(L_CORE_SERIAL,mem,len,"%s: write data",devName);  Flush();  int n=0;  while(n<len) {    struct pollfd u;    u.fd=fd; u.events=POLLOUT;    int r;    do {      r=poll(&u,1,500);      if(r<0) {        PRINTF(L_GEN_ERROR,"%s: write poll failed: %s",devName,strerror(errno));        return -1;        }      else if(r==0) { // timeout        PRINTF(L_CORE_SERIAL,"%s: write timeout",devName);        return -2;        }      } while(r<1);    r=write(fd,mem+n,delay>0?1:len-n);    if(r<0 && errno!=EAGAIN) {      PRINTF(L_GEN_ERROR,"%s: write failed: %s",devName,strerror(errno));      return -1;      }    if(r>0) n+=r;    if(delay>0) cCondWait::SleepMs(delay);    }  return n;}void cSerial::ToggleRTS(void){  int mask=0;  if(ioctl(fd,TIOCMGET,&mask)<0) { LOG_ERROR; return; }  if(mask&TIOCM_RTS) { mask&=~TIOCM_RTS; PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now off",devName); }  else               { mask|= TIOCM_RTS; PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now on",devName); }  CHECK(ioctl(fd,TIOCMSET,&mask));  Flush();}bool cSerial::CheckCAR(void){  int status=0;  if(ioctl(fd,TIOCMGET,&status)<0) { LOG_ERROR; return false; }  PRINTF(L_CORE_SERIAL,"%s: CAR is %sactive (lines:%s%s%s%s%s%s%s%s%s)",     devName,(status&TIOCM_CAR)?"in":"",     (status&TIOCM_LE)?" LE":"",  (status&TIOCM_DTR)?" DTR":"",     (status&TIOCM_RTS)?" RTS":"",(status&TIOCM_ST)?" ST":"",     (status&TIOCM_SR)?" SR":"",  (status&TIOCM_CTS)?" CTS":"",     (status&TIOCM_CAR)?" CAR":"",(status&TIOCM_RNG)?" RNG":"",     (status&TIOCM_DSR)?" DSR":"" );  status^=statInv; // invert status for broken cardreaders  return !(status & TIOCM_CAR);}#else //SER_EMU//// emulator for a serial phoenix interface// (activate in smartcard.h)//bool cSerial::Open(void){  PRINTF(L_CORE_SERIAL,"serial: open serial port %s (emulator)",devName);  PRINTF(L_CORE_SERIAL,"serial: init done");  fd=1; buffCount=0; cmdStart=true; rts=false; flag=false;  remTime=time(0); dsr=true;  return true;}void cSerial::Close(void){  if(fd>=0) {    PRINTF(L_CORE_SERIAL,"serial: shutting down ... ");    fd=-1;    PRINTF(L_CORE_SERIAL,"done");    }}speed_t cSerial::FindBaud(int baud){  return B0;}bool cSerial::SetMode(int mode, int baud){  currMode=mode;  Flush();  return true;}void cSerial::Flush(void){  buffCount=0;}#define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); }#define PUSHB(b)      { devBuff[buffCount++]=(b); }int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout){  PRINTF(L_CORE_SERIAL,"serial: read len=%d timeout=%d",len,timeout);  if(len<0) {    len=-len;    if(buffCount<len) len=buffCount;    }  if(buffCount<len) return -2; // timeout  memcpy(mem,devBuff,len);  memmove(devBuff,devBuff+len,buffCount-len);  buffCount-=len;  return len;}int cSerial::Write(const unsigned char *mem, int len, int delay){  PRINTF(L_CORE_SERIAL,"serial: write len=%d delay=%d",len,delay);  Flush();  cCondWait::SleepMs(300);  PUSH(mem,len); // echo back#if defined(EMU_SECA)  if(cmdStart && len==CMD_LEN) { // new INS    PUSHB(mem[INS_IDX]); // ACK byte    cmdStart=false;    dataLen=mem[LEN_IDX];    unsigned char data[256];    memset(data,0,sizeof(data));    nextSW[0]=0x90; nextSW[1]=0x00;    bool readcmd=false;    switch(mem[0]*256+mem[1]) {      case 0xc13a:      case 0xc10e:        readcmd=true;        break;      case 0xc116:        data[3]=0x04;        readcmd=true;        break;      case 0xc112:        data[1]=0x64;        data[22]=0x1d; data[23]=0x84;        readcmd=true;        break;      case 0xc132:        data[1]=0xFF; data[2]=0xFF; data[3]=0xFF; data[4]=0xFF;        data[5]=0xFF; data[6]=0xFF; data[7]=0xFF; data[8]=0xFF;        readcmd=true;        break;      }    if(readcmd) {      PUSH(data,dataLen);      PUSH(nextSW,2);      cmdStart=true;      }    }  else {    dataLen-=len;    if(dataLen<=0 && !cmdStart) {      PUSH(nextSW,2);      cmdStart=true;      }    }#elif defined(EMU_CRYPTO)  if(cmdStart && len==CMD_LEN) { // new INS    cmdStart=false;    dataLen=mem[LEN_IDX];    unsigned char data[256];    memset(data,0,sizeof(data));    nextSW[0]=0x90; nextSW[1]=0x00;    bool readcmd=false;    switch(mem[0]*256+mem[1]) {      case 0xa4a4:        switch(mem[5]*256+mem[6]) {          case 0x2f01:           case 0x0f00:          case 0x0f20:          //case 0x0f40:          case 0x0f60:          case 0x0e11:          case 0x1f88:          case 0x1f8c: nextSW[0]=0x9f; nextSW[1]=0x11; break;          default:     nextSW[0]=0x94; nextSW[1]=0x04; break;          }        break;      case 0xa4a2:        if(mem[2]==1) {          if(mem[4]==3) {            record=0x01;            nextSW[0]=0x9f; nextSW[1]=0x26;            }          else {            record=0x02;            nextSW[0]=0x9f; nextSW[1]=0x42;            }          }        else {          record=mem[5];          switch(record) {            case 0x80: nextSW[0]=0x9f; nextSW[1]=0x07; break;            case 0xD1: nextSW[0]=0x9f; nextSW[1]=0x04; break;            case 0x9F: nextSW[0]=0x9f; nextSW[1]=0x03; break;            case 0x9E: nextSW[0]=0x9f; nextSW[1]=0x42; break;            case 0xD6:            case 0xC0: nextSW[0]=0x9f; nextSW[1]=0x12; break;            default:   nextSW[0]=0x94; nextSW[1]=0x02; break;            }          }        break;      case 0xa4b2:        readcmd=true;        switch(record) {          case 0x01:            if(mem[3]==1) {              nextSW[0]=0x94; nextSW[1]=0x02;              dataLen=0;              }            else {              dataLen=0x26;              static const unsigned char resp[0x26] = {                0x83,0x01,0x88,                0x8c,0x03,0x40,0x30,0x40,                0x8d,0x04,0x16,0xac,0x16,0xba,                0xd5,0x10,'D','u','m','m','y',0,0,0,0,0,0,0,0x12,0x34,0x56,0x67,                0x8f,0x01,0x55,                0x91,0x01,0x40                };              memcpy(data,resp,sizeof(resp));              }            break;          case 0x02:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -