#include "log-core.h"
#define ISO_FREQ 3571200 // Hz
+#define ISO_BAUD 9600
-//#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 CARD_EMU // include smartcard emulation code
//#define NO_PTS_PROTO // disable PTS protocol (baudrate changes)
-struct BaudRates {
- int real;
- speed_t apival;
- };
+// -- cSmartCardSlot -----------------------------------------------------------
-static const struct BaudRates BaudRateTab[] = {
- { 9600, B9600 },
- { 19200, B19200 },
- { 38400, B38400 },
- { 57600, B57600 },
- { 115200, B115200 },
- { 230400, B230400 }
+class cSmartCardSlot : private cThread, public cStructItem {
+private:
+ cSmartCard *card;
+ int usecount, cardid;
+ bool firstRun, needsReset, dead, ready;
+ cMutex mutex;
+ cCondVar cond;
+ //
+ void SetCard(cSmartCard *c, int cid=0);
+ bool CardReset(void);
+protected:
+ virtual bool DeviceOpen(const char *cfg)=0;
+ virtual void DeviceClose(void) {}
+ virtual bool DeviceSetMode(int mode, int baud)=0;
+ virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0)=0;
+ virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0)=0;
+ virtual void DeviceToggleReset(void)=0;
+ virtual bool DevicePTS(void)=0;
+ virtual bool DeviceIsInserted(void)=0;
+ virtual int DeviceCurrentMode(void)=0;
+ //
+ virtual void Action(void);
+ // possibly virtual
+ bool Reset(void);
+ //
+ int Procedure(unsigned char ins, int restLen);
+ int Read(unsigned char *data, int len, int to=0);
+ int Write(const unsigned char *data, int len);
+ bool Test(bool res);
+ void Invert(unsigned char *data, int n);
+ bool ParseAtr(void);
+ //
+ int slotnum, clock;
+ struct Atr atr;
+ bool localecho;
+public:
+ cSmartCardSlot(void);
+ virtual ~cSmartCardSlot();
+ bool Setup(int num, const char *cfg);
+ void TriggerReset(void) { needsReset=true; }
+ bool HaveCard(int id);
+ cSmartCard *LockCard(int id);
+ void ReleaseCard(cSmartCard *sc);
+ void GetCardIdStr(char *str, int len);
+ bool GetCardInfoStr(char *str, int len);
+ int SlotNum(void) { return slotnum; }
+ // possibly virtual
+ bool IsoRead(const unsigned char *cmd, unsigned char *data);
+ bool IsoWrite(const unsigned char *cmd, const unsigned char *data);
+ int RawRead(unsigned char *data, int len, int to=0);
+ int RawWrite(const unsigned char *data, int len);
};
-// -- cSerial ------------------------------------------------------------------
+static const char *serModes[] = { 0,"8e2","8o2","8n2" };
+
+cSmartCardSlot::cSmartCardSlot(void)
+{
+ card=0; usecount=0; slotnum=-1; clock=ISO_FREQ;
+ firstRun=true; needsReset=false; dead=false; ready=false; localecho=true;
+}
+
+cSmartCardSlot::~cSmartCardSlot()
+{
+ Cancel(3);
+ SetCard(0);
+ DeviceClose();
+}
+
+bool cSmartCardSlot::Setup(int num, const char *cfg)
+{
+ slotnum=num;
+ SetDescription("CardSlot %d watcher",slotnum);
+ if(DeviceOpen(cfg)) {
+ firstRun=true;
+ Start();
+ return true;
+ }
+ return false;
+}
+
+bool cSmartCardSlot::HaveCard(int id)
+{
+ cMutexLock lock(&mutex);
+ while(Running() && firstRun) cond.Wait(mutex);
+ return ready && card && cardid==id;
+}
+
+cSmartCard *cSmartCardSlot::LockCard(int id)
+{
+ mutex.Lock();
+ while(Running() && firstRun) cond.Wait(mutex);
+ if(ready && card && cardid==id) {
+ usecount++;
+ mutex.Unlock();
+ card->Lock();
+ if(DeviceIsInserted() && card->CardUp() && !needsReset) return card;
+ // if failed, unlock the card and decrement UseCount
+ card->Unlock();
+ mutex.Lock();
+ usecount--;
+ cond.Broadcast();
+ }
+ mutex.Unlock();
+ return 0;
+}
+
+void cSmartCardSlot::ReleaseCard(cSmartCard *sc)
+{
+ if(card==sc) {
+ card->Unlock();
+ mutex.Lock();
+ usecount--;
+ cond.Broadcast();
+ mutex.Unlock();
+ }
+}
+
+void cSmartCardSlot::GetCardIdStr(char *str, int len)
+{
+ mutex.Lock();
+ if(ready && card && !card->GetCardIdStr(str,len)) {
+ for(cSmartCardLink *scl=smartcards.First(); scl; smartcards.Next(scl)) {
+ if(scl->Id()==cardid) {
+ strn0cpy(str,scl->Name(),len);
+ break;
+ }
+ }
+ }
+ mutex.Unlock();
+}
+
+bool cSmartCardSlot::GetCardInfoStr(char *str, int len)
+{
+ mutex.Lock();
+ bool res=false;
+ if(ready && card) res=card->GetCardInfoStr(str,len);
+ mutex.Unlock();
+ return res;
+}
+
+void cSmartCardSlot::SetCard(cSmartCard *c, int cid)
+{
+ mutex.Lock();
+ while(usecount) cond.Wait(mutex);
+ if(card!=c) delete card;
+ card=c; cardid=cid; ready=(card!=0); needsReset=dead=false;
+ mutex.Unlock();
+}
+
+void cSmartCardSlot::Action(void)
+{
+ while(Running()) {
+ if(card) {
+ card->Lock();
+ if(!DeviceIsInserted()) {
+ card->Unlock();
+ PRINTF(L_CORE_SC,"%d: card removed (usecount=%d)",slotnum,usecount);
+ SetCard(0);
+ }
+ else if(needsReset) {
+ PRINTF(L_CORE_SC,"%d: card reset requested",slotnum);
+ int mode=DeviceCurrentMode()&SM_MASK;
+ if(!DeviceSetMode(mode,ISO_BAUD)
+ || !CardReset()
+ || !card->Setup(this,mode,&atr)) {
+ card->Unlock();
+ PRINTF(L_CORE_SC,"%d: card re-init failed",slotnum);
+ SetCard(0); dead=true;
+ }
+ }
+ if(card) card->Unlock();
+ }
+ else if(DeviceIsInserted()) {
+ if(!dead) {
+ PRINTF(L_CORE_SC,"%d: new card inserted",slotnum);
+ for(int mode=SM_NONE+1 ; mode<SM_MAX ; mode++) {
+ if(DeviceSetMode(mode,ISO_BAUD)) {
+ if(CardReset()) {
+ for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl)) {
+ if(!Running()) goto done;
+ PRINTF(L_CORE_SC,"%d: checking for %s card",slotnum,scl->Name());
+ card=scl->Create();
+ if(card && card->Setup(this,mode,&atr)) {
+ SetCard(card,scl->Id());
+ goto done; // ugly, any better solution?
+ }
+ delete card; card=0;
+ }
+ PRINTF(L_CORE_SC,"%d: no card handler found",slotnum);
+ }
+ else PRINTF(L_CORE_SC,"%d: reset/atr error",slotnum);
+ }
+ else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slotnum,serModes[mode]);
+ }
+ dead=true;
+ PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slotnum);
+ }
+ }
+ else {
+ if(dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slotnum);
+ dead=false;
+ }
+done:
+ if(firstRun) {
+ mutex.Lock();
+ cond.Broadcast();
+ firstRun=false;
+ mutex.Unlock();
+ }
+ cCondWait::SleepMs(300);
+ }
+}
+
+bool cSmartCardSlot::Reset(void)
+{
+ PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",slotnum,serModes[DeviceCurrentMode()]);
+ DeviceToggleReset();
+ cCondWait::SleepMs(100);
+ DeviceToggleReset();
+ int r=DeviceRead(atr.atr,-MAX_ATR_LEN,800,2000);
+ atr.atrLen=r;
+ if(r>0) LDUMP(L_CORE_SC,atr.atr,r,"%d: <- ATR len=%d:",slotnum,r);
+ return r>=2;
+}
+
+bool cSmartCardSlot::CardReset(void)
+{
+ if(!Reset() || !ParseAtr()) return false;
+ if((atr.F!=372 || atr.D!=1.0) && !DevicePTS()) {
+ // reset card again and continue without PTS
+ if(!Reset() || !ParseAtr()) return false;
+ }
+ return true;
+}
+
+void cSmartCardSlot::Invert(unsigned char *data, int n)
+{
+ static const unsigned char swaptab[] = { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 };
+ for(int i=n-1; i>=0; i--)
+ data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4];
+}
+
+int cSmartCardSlot::Read(unsigned char *data, int len, int to)
+{
+ int r=DeviceRead(data,len,card->cfg->serTO,to);
+ if(atr.convention==SM_INDIRECT && r>0) Invert(data,r);
+ return r;
+}
+
+int cSmartCardSlot::Write(const unsigned char *data, int len)
+{
+ unsigned char *tmp=AUTOMEM(len);
+ if(atr.convention==SM_INDIRECT) {
+ memcpy(tmp,data,len);
+ Invert(tmp,len);
+ data=tmp;
+ }
+ int r=DeviceWrite(data,len,card->cfg->serDL);
+ if(r>0 && localecho) {
+ unsigned char *buff=AUTOMEM(r);
+ int rr=DeviceRead(buff,r,card->cfg->serTO);
+ if(rr<0) r=rr;
+ }
+ return r;
+}
+
+int cSmartCardSlot::Procedure(unsigned char ins, int restLen)
+{
+ int r;
+ unsigned char buff;
+ LBSTARTF(L_CORE_SC);
+ LBPUT("%d: <- PROC: ",slotnum);
+ do {
+ do {
+ if(Read(&buff,1,card->cfg->workTO)<=0) return -1;
+ LBPUT("%02x ",buff);
+ } while(buff==0x60);
+
+ if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2
+ card->sb[0]=buff;
+ if(Read(&buff,1)<=0) return -1;
+ LBPUT("%02x",buff);
+ card->sb[1]=buff;
+ return 0;
+ }
+ else {
+ if((buff&0xFE)==(ins&0xFE)) r=restLen;
+ else if((~buff&0xFE)==(ins&0xFE)) r=1;
+ else {
+ LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins);
+ return -1;
+ }
+ if(r>restLen) {
+ LBPUT("data overrun r=%d restLen=%d",r,restLen);
+ return -1;
+ }
+ }
+ } while(r==0);
+ LBEND();
+ return r;
+}
+
+bool cSmartCardSlot::Test(bool res)
+{
+ if(!res) {
+ TriggerReset();
+ PRINTF(L_CORE_SC,"%d: reset triggered",slotnum);
+ }
+ return res;
+}
+
+bool cSmartCardSlot::IsoRead(const unsigned char *cmd, unsigned char *data)
+{
+ LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
+ if(Write(cmd,CMD_LEN)<0) return Test(false);
+ int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256;
+ int len=0;
+ while(1) {
+ int r=Procedure(cmd[INS_IDX],tr-len);
+ if(r<=0) return Test(r==0);
+ if(Read(data+len,r)<0) return Test(false);
+ LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",slotnum);
+ len+=r;
+ }
+}
+
+bool cSmartCardSlot::IsoWrite(const unsigned char *cmd, const unsigned char *data)
+{
+ LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
+ if(Write(cmd,CMD_LEN)<0) return Test(false);
+ int len=0;
+ while(1) {
+ int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len);
+ if(r<=0) return Test(r==0);
+ if(Write(data+len,r)<0) return Test(false);
+ LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",slotnum);
+ len+=r;
+ }
+}
+
+int cSmartCardSlot::RawRead(unsigned char *data, int len, int to)
+{
+ int r=Read(data,len,to);
+ if(r<0) Test(false);
+ return r;
+}
+
+int cSmartCardSlot::RawWrite(const unsigned char *data, int len)
+{
+ int r=Write(data,len);
+ if(r<0) Test(false);
+ return r;
+}
+
+#define NEED(x) { if(len+(x)>atr.atrLen) { LBPUT("SHORT ATR"); return false; } }
+
+bool cSmartCardSlot::ParseAtr(void)
+{
+ // default values
+ atr.histLen=0; atr.T=0; atr.F=372; atr.D=1.0; atr.N=0; atr.WI=10;
+ atr.BWI=4; atr.CWI=0; atr.Tspec=-1;
+
+ static const int Ftable[16] = {
+ 372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0
+ };
+ static const float Dtable[16] = {
+ 0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0,
+ 0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625
+ };
+
+ const unsigned char *rawatr=atr.atr;
+ if(rawatr[0]==0x03) {
+ PRINTF(L_CORE_SC,"%d: indirect convention detected",slotnum);
+ Invert(atr.atr,atr.atrLen);
+ atr.convention=SM_INDIRECT;
+ }
+ else if(rawatr[0]==0x3B) {
+ PRINTF(L_CORE_SC,"%d: direct convention detected",slotnum);
+ atr.convention=SM_DIRECT;
+ }
+ else {
+ PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",slotnum,rawatr[0]);
+ return false;
+ }
-class cSerial {
+ // TS TO
+ atr.histLen=rawatr[1]&0x0F;
+ int Y=rawatr[1]&0xF0, i=1, len=2;
+ LBSTARTF(L_CORE_SC);
+ LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",slotnum,rawatr[0],atr.histLen,i,Y);
+ do {
+ if(Y&0x10) { // TAi
+ NEED(1);
+ LBPUT("TA%d=%02x ",i,rawatr[len]);
+ if(i==1) {
+ atr.TA1=rawatr[len];
+ atr.F=Ftable[(rawatr[len]>>4)&0x0F];
+ atr.D=Dtable[ rawatr[len] &0x0F];
+ LBPUT("F=%d D=%f ",atr.F,atr.D);
+ }
+ else if(i==2) {
+ atr.Tspec=rawatr[len]&0x0F;
+ LBPUT("Tspec=%d ",atr.Tspec);
+ }
+ else if(i==3) {
+ LBPUT("IFSC=%d ",rawatr[len]);
+ }
+ len++;
+ }
+ if(Y&0x20) { // TBi
+ NEED(1);
+ LBPUT("TB%d=%02x ",i,rawatr[len]);
+ if(i==3) {
+ atr.BWI=(rawatr[len]>>4)&0x0F;
+ atr.CWI=rawatr[len]&0x0F;
+ LBPUT("BWI=%d CWI=%d ",atr.BWI,atr.CWI);
+ }
+ len++;
+ }
+ if(Y&0x40) { // TCi
+ NEED(1);
+ LBPUT("TC%d=%02x ",i,rawatr[len]);
+ if(i==1) {
+ atr.N=rawatr[len];
+ LBPUT("N=%d ",atr.N);
+ }
+ else if(i==2) {
+ atr.WI=rawatr[len];
+ LBPUT("WI=%d ",atr.WI);
+ }
+ else if(i==3) {
+ LBPUT("CHK=%s ",rawatr[len]&1 ? "CRC16":"LRC");
+ }
+ len++;
+ }
+ if(Y&0x80) { // TDi
+ NEED(1);
+ LBPUT("TD%d=%02x ",i,rawatr[len]);
+ if(i==1) {
+ atr.T=rawatr[len]&0x0F;
+ LBPUT("T=%d ",atr.T);
+ }
+ else {
+ LBPUT("Tn=%d ",rawatr[len]&0x0F);
+ }
+ Y=rawatr[len]&0xF0;
+ len++;
+ }
+ else Y=0;
+ i++;
+ LBPUT("Y%d=%02x ",i,Y);
+ } while(Y);
+ NEED(atr.histLen);
+ LBEND();
+
+ LBSTART(L_CORE_SC);
+ LBPUT("%d: historical:",slotnum);
+ for(int i=0; i<atr.histLen; i++) LBPUT(" %02x",rawatr[len+i]);
+ LBFLUSH();
+ LBPUT("%d: historical: '",slotnum);
+ for(int i=0; i<atr.histLen; i++) LBPUT("%c",isprint(rawatr[len+i]) ? rawatr[len+i] : '.');
+ LBEND();
+
+ memcpy(atr.hist,&rawatr[len],atr.histLen);
+ len+=atr.histLen;
+
+ // TCK
+ if(atr.T!=0 && len+1<=atr.atrLen) {
+ len++;
+ unsigned char cs=XorSum(rawatr+1,len-1);
+ // according to the ISO the initial TS byte isn't checksumed, but
+ // some cards do so. In this case the checksum is equal TS.
+ if(cs==0) PRINTF(L_CORE_SC,"%d: atr checksum ok",slotnum);
+ else if(cs==rawatr[0]) PRINTF(L_CORE_SC,"iso: %d: atr checksum is TS (not ISO compliant)",slotnum);
+ else {
+ PRINTF(L_CORE_SC,"%d: atr checksum FAILED (cs:%02x)",slotnum,cs);
+ return false;
+ }
+ }
+ else PRINTF(L_CORE_SC,"%d: atr checksum not given/not required",slotnum);
+
+ if(atr.atrLen>len) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",slotnum,atr.atrLen,len);
+ atr.wwt=960*atr.WI*atr.F/(clock/1000);
+ atr.bwt=(int)(960*(float)(1<<atr.BWI)*372/(clock/1000));
+ PRINTF(L_CORE_SC,"%d: indicated wwt(T0)=%d ms, bwt(T1)=%d ms (at %.4f MHz)",slotnum,atr.wwt,atr.bwt,(float)clock/1000000);
+ return true;
+}
+
+#undef NEED
+
+// -- cSmartCardSlots ----------------------------------------------------------
+
+class cSmartCardSlots : public cStructListPlain<cSmartCardSlot> {
+friend class cSmartCardSlotLink;
private:
- char *devName;
- int fd;
- int currMode, statInv;
- bool invRST;
+ static cSmartCardSlotLink *first;
//
- 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;
-#endif
+ static void Register(cSmartCardSlotLink *scl);
+protected:
+ virtual bool ParseLinePlain(const char *line);
public:
- 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; }
+ cSmartCardSlots(void);
+ cSmartCardSlot *GetSlot(int num);
+ cSmartCardSlot *FirstSlot(void);
+ void Release(void);
};
-cSerial::cSerial(const char *DevName, bool invCD, bool InvRST)
+cSmartCardSlotLink *cSmartCardSlots::first=0;
+
+static cSmartCardSlots cardslots;
+
+// -- cSmartCardSlotLink -------------------------------------------------------
+
+class cSmartCardSlotLink {
+public:
+ cSmartCardSlotLink *next;
+ const char *name;
+public:
+ cSmartCardSlotLink(const char *Name);
+ virtual ~cSmartCardSlotLink() {}
+ virtual cSmartCardSlot *Create(void)=0;
+ };
+
+template<class LL> class cSmartCardSlotLinkReg : public cSmartCardSlotLink {
+public:
+ cSmartCardSlotLinkReg(const char *Name):cSmartCardSlotLink(Name) {}
+ virtual cSmartCardSlot *Create(void) { return new LL; }
+ };
+
+cSmartCardSlotLink::cSmartCardSlotLink(const char *Name)
+{
+ name=Name;
+ cSmartCardSlots::Register(this);
+}
+
+// -- cSmartCardSlots ----------------------------------------------------------
+
+cSmartCardSlots::cSmartCardSlots(void)
+:cStructListPlain<cSmartCardSlot>("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE)
+{}
+
+void cSmartCardSlots::Register(cSmartCardSlotLink *scl)
{
- devName=strdup(DevName);
- statInv=invCD ? TIOCM_CAR:0;
- invRST=InvRST;
- fd=-1; currMode=SM_NONE;
+ PRINTF(L_CORE_DYN,"registering cardslot type %s",scl->name);
+ scl->next=first;
+ first=scl;
}
-cSerial::~cSerial()
+cSmartCardSlot *cSmartCardSlots::GetSlot(int num)
{
- Close();
- free(devName);
+ ListLock(false);
+ for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
+ if(slot->SlotNum()==num) return slot;
+ return 0;
}
-#ifndef SER_EMU
+cSmartCardSlot *cSmartCardSlots::FirstSlot(void)
+{
+ ListLock(false);
+ return First();
+}
-bool cSerial::Open(void)
+void cSmartCardSlots::Release(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;
+ ListUnlock();
+}
+
+bool cSmartCardSlots::ParseLinePlain(const char *line)
+{
+ char type[32];
+ int num;
+ if(sscanf(line,"%31[^:]:%n",type,&num)==1) {
+ for(cSmartCardSlotLink *scs=first; scs; scs=scs->next) {
+ if(!strcasecmp(type,scs->name)) {
+ cSmartCardSlot *slot=scs->Create();
+ if(slot) {
+ if(slot->Setup(Count(),&line[num])) {
+ Add(slot);
+ return true;
+ }
+ delete slot;
+ }
+ else PRINTF(L_GEN_ERROR,"failed to create cardslot");
+ return false;
+ }
+ }
+ PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type);
+ }
+ return false;
+}
+
+// -- cSmartCardSlotSerial -----------------------------------------------------
+
+class cSmartCardSlotSerial : public cSmartCardSlot {
+private:
+ char devName[256];
+ int fd;
+ int currMode, statInv, invRST;
+ //
+ void Flush(void);
+ speed_t FindBaud(int baud);
+protected:
+ virtual bool DeviceOpen(const char *cfg);
+ virtual void DeviceClose(void);
+ virtual bool DeviceSetMode(int mode, int baud);
+ virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0);
+ virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+ virtual void DeviceToggleReset(void);
+ virtual bool DevicePTS(void);
+ virtual bool DeviceIsInserted(void);
+ virtual int DeviceCurrentMode(void) { return currMode; }
+public:
+ cSmartCardSlotSerial(void);
+ };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotSerial> __scs_serial("serial");
+
+cSmartCardSlotSerial::cSmartCardSlotSerial(void)
+{
+ fd=-1; statInv=0; invRST=false; currMode=SM_NONE;
+}
+
+bool cSmartCardSlotSerial::DeviceOpen(const char *cfg)
+{
+ int invCD=0;
+ if(sscanf(cfg,"%255[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) {
+ statInv=invCD ? TIOCM_CAR:0;
+ 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);
+ PRINTF(L_CORE_LOAD,"cardslot: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)",
+ devName,slotnum,invCD?"inverse":"normal",invRST?"inverse":"normal",clock);
+ return true;
+ }
+ else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));
}
- else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));
+ else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'serial'");
return false;
}
-void cSerial::Close(void)
+void cSmartCardSlotSerial::DeviceClose(void)
{
if(fd>=0) {
PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);
}
}
-speed_t cSerial::FindBaud(int baud)
+void cSmartCardSlotSerial::Flush(void)
{
+ if(fd>=0) CHECK(tcflush(fd,TCIOFLUSH));
+}
+
+speed_t cSmartCardSlotSerial::FindBaud(int baud)
+{
+ static const struct BaudRates { int real; speed_t apival; } BaudRateTab[] = {
+ { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 },
+ { 57600, B57600 }, { 115200, B115200 }, { 230400, B230400 }
+ };
+
for(int i=0; i<(int)(sizeof(BaudRateTab)/sizeof(struct BaudRates)); i++) {
int b=BaudRateTab[i].real;
int d=((b-baud)*10000)/b;
return B0;
}
-bool cSerial::SetMode(int mode, int baud)
+bool cSmartCardSlotSerial::DeviceSetMode(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);
cfsetispeed(&tio,bconst);
cfsetospeed(&tio,bconst);
switch(mode&SM_MASK) {
- case SM_8E2:
+ case SM_8E2:
LBPUT("8e%d",(mode&SM_1SB)?1:2);
tio.c_cflag |= PARENB; break;
case SM_8N2:
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)
+int cSmartCardSlotSerial::DeviceRead(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;
return n;
}
-int cSerial::Write(const unsigned char *mem, int len, int delay)
+int cSmartCardSlotSerial::DeviceWrite(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);
return n;
}
-void cSerial::ToggleRTS(void)
+void cSmartCardSlotSerial::DeviceToggleReset(void)
{
int mask=0;
if(ioctl(fd,TIOCMGET,&mask)<0) { LOG_ERROR; return; }
Flush();
}
-bool cSerial::CheckCAR(void)
+bool cSmartCardSlotSerial::DevicePTS(void)
+{
+ int baud=(int)((float)clock*atr.D/atr.F);
+ PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",slotnum,baud);
+
+ if(atr.Tspec<0) {
+ PRINTF(L_CORE_SC,"%d: negotiable mode",slotnum);
+#ifdef NO_PTS_PROTO
+ PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",slotnum);
+ return true;
+#else
+ unsigned char req[4], conf[16];
+ req[0]=0xFF;
+ req[1]=0x10 | atr.T;
+ req[2]=atr.TA1;
+ req[3]=XorSum(req,3);
+ LDUMP(L_CORE_SC,req,4,"%d: PTS request:",slotnum);
+ if(DeviceWrite(req,4)!=4) {
+ PRINTF(L_CORE_SC,"%d: PTS request, write failed",slotnum);
+ return false;
+ }
+ if(DeviceRead(conf,4,100,100)!=4) {
+ PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",slotnum);
+ return false;
+ }
+ int n=DeviceRead(conf,-16,200,1000);
+ if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",slotnum);
+ if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) {
+ PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",slotnum);
+ return false;
+ }
+ if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) {
+ PRINTF(L_CORE_SC,"%d: PTS not confirmed",slotnum);
+ return false;
+ }
+#endif // NO_PTS_PROTO
+ }
+ else
+ PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",slotnum,atr.Tspec);
+
+ int mode=DeviceCurrentMode();
+ if(atr.N==255) mode|=SM_1SB;
+ if(!DeviceSetMode(mode,baud)) {
+ PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",slotnum,baud);
+ return false;
+ }
+ return true;
+}
+
+bool cSmartCardSlotSerial::DeviceIsInserted(void)
{
int status=0;
if(ioctl(fd,TIOCMGET,&status)<0) { LOG_ERROR; return false; }
return !(status & TIOCM_CAR);
}
-#else //SER_EMU
+#ifdef CARD_EMU
+
+// -- cSmartCardSlotEmuGeneric -------------------------------------------------
+
+#define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); }
+#define PUSHB(b) { devBuff[buffCount++]=(b); }
+
+class cSmartCardSlotEmuGeneric : public cSmartCardSlot {
+private:
+ int currMode;
+protected:
+ char devName[256];
+ unsigned char devBuff[1024], nextSW[SB_LEN];
+ int buffCount, dataLen, record;
+ bool cmdStart, rts, dsr, flag;
+ time_t remTime;
+ //
+ virtual bool DeviceOpen(const char *cfg);
+ virtual void DeviceClose(void);
+ virtual bool DeviceSetMode(int mode, int baud);
+ virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0);
+ virtual void DeviceToggleReset(void);
+ virtual bool DevicePTS(void);
+ virtual bool DeviceIsInserted(void);
+ virtual int DeviceCurrentMode(void) { return currMode; }
+ //
+ virtual void EmuPushAtr(void)=0;
+ void Flush(void);
+public:
+ cSmartCardSlotEmuGeneric(void);
+ };
-//
-// emulator for a serial phoenix interface
-// (activate in smartcard.h)
-//
+cSmartCardSlotEmuGeneric::cSmartCardSlotEmuGeneric(void)
+{
+ currMode=SM_NONE;
+}
-bool cSerial::Open(void)
+bool cSmartCardSlotEmuGeneric::DeviceOpen(const char *cfg)
{
- 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;
+ PRINTF(L_CORE_SERIAL,"%s: open serial port (emulator)",devName);
+ PRINTF(L_CORE_SERIAL,"%s: init done",devName);
+ buffCount=0; cmdStart=true; rts=false; flag=false;
remTime=time(0); dsr=true;
+ PRINTF(L_CORE_LOAD,"cardslot: added emulated port %s as port %d",devName,slotnum);
return true;
}
-void cSerial::Close(void)
+void cSmartCardSlotEmuGeneric::DeviceClose(void)
{
- if(fd>=0) {
- PRINTF(L_CORE_SERIAL,"serial: shutting down ... ");
- fd=-1;
- PRINTF(L_CORE_SERIAL,"done");
- }
+ PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);
}
-speed_t cSerial::FindBaud(int baud)
+void cSmartCardSlotEmuGeneric::Flush(void)
{
- return B0;
+ buffCount=0;
}
-bool cSerial::SetMode(int mode, int baud)
+bool cSmartCardSlotEmuGeneric::DeviceSetMode(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)
+int cSmartCardSlotEmuGeneric::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout)
{
- PRINTF(L_CORE_SERIAL,"serial: read len=%d timeout=%d",len,timeout);
+ PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d",devName,len,timeout);
if(len<0) {
len=-len;
if(buffCount<len) len=buffCount;
return len;
}
-int cSerial::Write(const unsigned char *mem, int len, int delay)
+void cSmartCardSlotEmuGeneric::DeviceToggleReset(void)
+{
+ rts=!rts;
+ if(!rts) {
+ EmuPushAtr();
+ PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now off",devName);
+ }
+ else { PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now on",devName); }
+}
+
+bool cSmartCardSlotEmuGeneric::DevicePTS(void)
+{
+ return true;
+}
+
+bool cSmartCardSlotEmuGeneric::DeviceIsInserted(void)
+{
+#if 0
+ if(time(0)>=remTime+30) {
+ dsr=!dsr;
+ remTime=time(0);
+ }
+#endif
+ return dsr;
+}
+
+// -- cSmartCardSlotEmuSeca ----------------------------------------------------
+
+class cSmartCardSlotEmuSeca : public cSmartCardSlotEmuGeneric {
+protected:
+ virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+ virtual void EmuPushAtr(void);
+public:
+ cSmartCardSlotEmuSeca(void);
+ };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotEmuSeca> __scs_emuseca("emuseca");
+
+cSmartCardSlotEmuSeca::cSmartCardSlotEmuSeca(void)
+{
+ strcpy(devName,"emuseca");
+}
+
+int cSmartCardSlotEmuSeca::DeviceWrite(const unsigned char *mem, int len, int delay)
{
- PRINTF(L_CORE_SERIAL,"serial: write len=%d delay=%d",len,delay);
+ PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,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;
cmdStart=true;
}
}
-#elif defined(EMU_CRYPTO)
+ //---
+ return len;
+}
+
+void cSmartCardSlotEmuSeca::EmuPushAtr(void)
+{
+ static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00,
+ 0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 };
+ PUSH(atr,sizeof(atr));
+}
+
+// -- cSmartCardSlotEmuCrypto --------------------------------------------------
+
+class cSmartCardSlotEmuCrypto : public cSmartCardSlotEmuGeneric {
+protected:
+ virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+ virtual void EmuPushAtr(void);
+public:
+ cSmartCardSlotEmuCrypto(void);
+ };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotEmuCrypto> __scs_emucrypto("emucrypto");
+
+cSmartCardSlotEmuCrypto::cSmartCardSlotEmuCrypto(void)
+{
+ strcpy(devName,"emucrypto");
+}
+
+int cSmartCardSlotEmuCrypto::DeviceWrite(const unsigned char *mem, int len, int delay)
+{
+ PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
+ Flush();
+ cCondWait::SleepMs(300);
+ PUSH(mem,len); // echo back
+ //---
if(cmdStart && len==CMD_LEN) { // new INS
cmdStart=false;
dataLen=mem[LEN_IDX];
switch(mem[0]*256+mem[1]) {
case 0xa4a4:
switch(mem[5]*256+mem[6]) {
- case 0x2f01:
+ case 0x2f01:
case 0x0f00:
case 0x0f20:
//case 0x0f40:
0x92,0x20,0x00 // ...
};
memcpy(data,resp,sizeof(resp));
- }
+ }
break;
case 0x80:
dataLen=0x07;
- data[0]=0x80;
- data[1]=0x05;
- data[2]=0x5c;
- data[3]=0x0c;
- data[4]=0x00;
- data[5]=0xec;
- data[6]=0x0a;
+ data[0]=0x80; data[1]=0x05; data[2]=0x5c; data[3]=0x0c;
+ data[4]=0x00; data[5]=0xec; data[6]=0x0a;
break;
case 0xD1:
dataLen=0x04;
- data[0]=0xd1;
- data[1]=0x02;
- data[2]=0x0d;
- data[3]=0x22;
+ data[0]=0xd1; data[1]=0x02; data[2]=0x0d; data[3]=0x22;
break;
case 0x9F:
dataLen=0x03;
- data[0]=0x9f;
- data[1]=0x01;
- data[2]=0x88;
+ data[0]=0x9f; data[1]=0x01; data[2]=0x88;
break;
case 0x9E:
{
if(mem[2]==0) {
dataLen=0x0C;
memset(data,0,0x0c);
- data[0]=0xDF;
- data[1]=0x0A;
- data[4]=0xDF;
- data[5]=0x88;
+ data[0]=0xDF; data[1]=0x0A; data[4]=0xDF; data[5]=0x88;
}
else {
dataLen=0;
case 0xa4c0:
readcmd=true;
if(mem[4]==0x1c) {
- data[0]=0xdb;
- data[1]=0x10;
+ data[0]=0xdb; data[1]=0x10;
memset(&data[2],0x45,16);
- data[18]=0xdf;
- data[19]=0x08;
- data[20]=0x50;
- data[23]=0x80;
+ data[18]=0xdf; data[19]=0x08; data[20]=0x50; data[23]=0x80;
}
else if(mem[4]==0x11) {
memset(data,0,0x11);
- data[0]=0xdf;
- data[1]=0x0f;
- data[6]=0x3f;
- data[7]=0x6a;
+ data[0]=0xdf; data[1]=0x0f; data[6]=0x3f; data[7]=0x6a;
}
else if(mem[4]==0x42) {
static const unsigned char resp[0x42] = {
cmdStart=true;
}
}
-#elif defined(EMU_IRD)
+ //---
+ return len;
+}
+
+void cSmartCardSlotEmuCrypto::EmuPushAtr(void)
+{
+ static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00,
+ 0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 };
+ PUSH(atr,sizeof(atr));
+}
+
+// -- cSmartCardSlotEmuIrdeto --------------------------------------------------
+
+class cSmartCardSlotEmuIrdeto : public cSmartCardSlotEmuGeneric {
+private:
+ bool acs384;
+protected:
+ virtual bool DeviceOpen(const char *cfg);
+ virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+ virtual void EmuPushAtr(void);
+public:
+ cSmartCardSlotEmuIrdeto(void);
+ };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotEmuIrdeto> __scs_emuirdeto("emuirdeto");
+
+cSmartCardSlotEmuIrdeto::cSmartCardSlotEmuIrdeto(void)
+{
+ strcpy(devName,"emuirdeto");
+ acs384=false;
+}
+
+bool cSmartCardSlotEmuIrdeto::DeviceOpen(const char *cfg)
+{
+ char acs[32];
+ if(sscanf(cfg,"%31[^:]",acs)>=0) {
+ if(!strcasecmp(acs,"acs384")) acs384=true;
+ else if(!strcasecmp(acs,"acs383")) acs384=false;
+ else {
+ PRINTF(L_GEN_ERROR,"unknown ACS type");
+ return false;
+ }
+ return cSmartCardSlotEmuGeneric::DeviceOpen(0);
+ }
+ else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",devName);
+ return false;
+}
+
+int cSmartCardSlotEmuIrdeto::DeviceWrite(const unsigned char *mem, int len, int delay)
+{
+ PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
+ Flush();
+ cCondWait::SleepMs(300);
+ PUSH(mem,len); // echo back
+ //---
static const struct Resp {
unsigned int cmd;
+ int acs;
unsigned char data[MAX_LEN];
} resp[] = {
-#ifdef EMU_IRD_384
- { 0x01020203,
+ { 0x01020203,0x384,
{0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x84,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} },
- { 0x01020E02,
+ { 0x01020E02,0x384,
{0x01,0x02,0x00,0x00,0x0e,0x02,0x00,0x40,0xa9,0x6d,0x73,0x97,0x9e,0xfc,0x9b,0x8e,0x5b,0x8c,0xfa,0xb2,0x0c,0xb2,0x57,0x0f,0xb2,0xf7,0x29,0x4e,0xa2,0xcb,0xbd,0x5b,0x52,0x74,0xb1,0x2a,0xb7,0xc5,0xd9,0x62,0x6d,0x37,0x6d,0x9d,0xa3,0xe9,0x61,0xbb,0x1b,0x2b,0x56,0xb7,0x86,0x0c,0xe6,0xb1,0x07,0x6f,0xe0,0xf8,0x8a,0xd3,0x05,0x83,0xf6,0x53,0x0e,0xd2,0x72,0xd5,0xc1,0x50} },
- { 0x01020E03,
+ { 0x01020E03,0x384,
{0x01,0x02,0x00,0x00,0x0e,0x03,0x00,0x40,0xb6,0xde,0xa8,0xce,0x86,0x1c,0x42,0x72,0xa8,0x16,0x4b,0xf9,0xce,0x33,0xb5,0x43,0xd0,0x50,0xe6,0xa7,0xf1,0xcb,0x55,0x25,0x97,0x13,0xee,0x62,0x98,0xe7,0x17,0x50,0xeb,0x3b,0x59,0x10,0x0a,0xb6,0x2e,0x93,0x61,0x71,0x3c,0xe6,0xe2,0x2c,0x1e,0x7d,0xbd,0x6a,0x49,0xbb,0x04,0x5b,0xdf,0x2f,0xb7,0xa7,0x93,0xe0,0x3d,0x40,0x4e,0xd1} },
-#else
- { 0x01020203,
+ //
+ { 0x01020203,0x383,
{0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x83,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} },
- { 0x01020E02,
+ { 0x01020E02,0x383,
{0x01,0x02,0x00,0x00,0x0E,0x02,0x00,0x40,0x65,0xEF,0xD0,0xA7,0xF3,0x80,0x48,0x0E,0xC1,0x4B,0x41,0x6C,0xDB,0x68,0x47,0xE4,0x23,0xAD,0x96,0x12,0x07,0x58,0x58,0x29,0xE9,0x14,0x27,0x7F,0x7D,0xF8,0xC2,0x65,0x76,0x4D,0x75,0x04,0x7C,0x9B,0xAA,0x99,0x58,0xEA,0xE2,0x43,0xB5,0x03,0x05,0xD6,0x62,0x99,0xF5,0x18,0x16,0x4E,0xCF,0x49,0x11,0xBD,0xF3,0xEE,0xC3,0xCD,0x90,0x3B} },
- { 0x01020E03,
+ { 0x01020E03,0x383,
{0x01,0x02,0x00,0x00,0x0E,0x03,0x00,0x40,0x9B,0x06,0xB5,0x0A,0x98,0xC6,0x2E,0x1D,0x71,0xA1,0xE8,0x84,0xAE,0x98,0x57,0xE9,0xE6,0xC2,0x97,0x46,0x25,0x7A,0x2B,0xA1,0xD5,0x33,0x18,0xDE,0x16,0xC1,0xAB,0x22,0x2C,0xC2,0x11,0x24,0x81,0x11,0xA8,0x39,0xE3,0xB1,0xDB,0x33,0x1A,0x93,0x31,0xB0,0x61,0xD8,0xDE,0x92,0x1F,0x29,0x20,0xD0,0x9E,0x0F,0x6A,0xF0,0x7C,0xBA,0xCD,0xCC} },
-#endif
- { 0x01020003,
+ //
+ { 0x01020003,0x0,
{0x01,0x02,0x00,0x00,0x00,0x03,0x00,0x14,0x37,0x30,0x31,0x32,0x30,0x36,0x39,0x33,0x34,0x37,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} },
- { 0x01020103,
+ { 0x01020103,0x0,
{0x01,0x02,0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x17,0x00,0x00,0x01,0x00,0x17,0x00,0x00,0x01,0x04,0x00,0xF3,0x86,0x01,0x1A} },
- { 0x01021100,
+ { 0x01021100,0x0,
{0x01,0x02,0x58,0x00,0x11,0x00,0x00,0x00} },
- { 0x01020903,
+ { 0x01020903,0x0,
{0x01,0x02,0x55,0x00,0x09,0x03,0x00,0x00} },
- { 0x01020303,
+ { 0x01020303,0x0,
{0x01,0x02,0x00,0x00,0x03,0x03,0x02,0x18,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} },
- { 0x01020400,
+ { 0x01020400,0x0,
{0x01,0x02,0x54,0x00,0x04,0x00,0x00,0x00} },
- { 0x01050000,
+ { 0x01050000,0x0,
{0x01,0x05,0x9D,0x00,0x38,0x00,0x02,0x16,0x00,0x01,0x00,0x13,0xFF,0xFF,0x22,0x88,0xBF,0x02,0x70,0xFA,0x5F,0x80,0xFD,0x1E,0xD4,0xD6,0xF0,0xF1,0x81,0xB3} },
- { 0x01010000,
+ { 0x01010000,0x0,
{0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xFF} },
- { 0x00000000, // don't delete this one
+ { 0x00000000,0x0, // don't delete this one
{} }
};
const unsigned int cmd=(mem[0]<<24) + (mem[1]<<16) + (mem[2]<<8) + mem[3];
const struct Resp *r=&resp[0];
+ int acs=acs384 ? 0x384:0x383;
while(1) {
if(!r->cmd) {
static const unsigned char fail[] = { 0x01,0x99,0x6f };
PUSH(fail,sizeof(fail));
break;
}
- if(cmd==r->cmd) {
+ if(cmd==r->cmd && (!r->acs || r->acs==acs)) {
const int len=r->data[7]+9-1;
int cs=0x3f;
for(int i=0 ; i<len ; i++) cs ^= r->data[i];
}
r++;
}
-#else
-#error No serial emulation mode selected
-#endif
+ //---
return len;
}
-void cSerial::ToggleRTS(void)
-{
- rts=!rts;
- if(!rts) {
-#if defined(EMU_SECA)
- static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00,
- 0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 };
-#elif defined(EMU_IRD)
- static const unsigned char atr[] = { 0x3B,0x9F,0x21,0x0E,
-#ifdef EMU_IRD_384
- 0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d };
-#else
- 0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 };
-#endif
-#elif defined(EMU_CRYPTO)
- static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00,
- 0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 };
-#else
-#error No serial emulation mode selected
-#endif
- PUSH(atr,sizeof(atr));
- PRINTF(L_CORE_SERIAL,"serial: toggle RTS, now off");
- }
- else { PRINTF(L_CORE_SERIAL,"serial: toggle RTS, now on"); }
-}
-
-bool cSerial::CheckCAR(void)
+void cSmartCardSlotEmuIrdeto::EmuPushAtr(void)
{
-#if 0
- if(time(0)>=remTime+30) {
- dsr=!dsr;
- remTime=time(0);
- }
-#endif
- return dsr;
+ static const unsigned char atr384[] = { 0x3B,0x9F,0x21,0x0E,
+ 0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d };
+ static const unsigned char atr383[] = { 0x3B,0x9F,0x21,0x0E,
+ 0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 };
+ if(acs384) PUSH(atr384,sizeof(atr384))
+ else PUSH(atr383,sizeof(atr383))
}
-#endif //SER_EMU
+#endif // CARD_EMU
// -- cInfoStr -----------------------------------------------------------------
// -- cSmartCardData -----------------------------------------------------------
-cSmartCardData::cSmartCardData(int Ident)
-{
- ident=Ident;
-}
-
-// -- cSmartCardDatas ----------------------------------------------------------
-
-cSmartCardDatas carddatas;
-
-cSmartCardDatas::cSmartCardDatas(void)
-:cStructList<cSmartCardData>("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE)
-{}
-
-cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param)
-{
- ListLock(false);
- cSmartCardData *cd;
- for(cd=First(); cd; cd=Next(cd))
- if(cd->Ident()==param->Ident() && cd->Matches(param)) break;
- ListUnlock();
- return cd;
-}
-
-cStructItem *cSmartCardDatas::ParseLine(char *line)
-{
- char *r=index(line,':');
- if(r)
- for(cSmartCardLink *scl=cSmartCards::first; scl; scl=scl->next)
- if(!strncasecmp(scl->name,line,r-line)) {
- cSmartCardData *scd=scl->CreateData();
- if(scd && scd->Parse(r+1)) return scd;
- delete scd;
- break;
- }
- return 0;
-}
-
-// -- cSmartCardSlot -----------------------------------------------------------
-
-cSmartCardSlot::cSmartCardSlot(int num)
-{
- Serial=0; Card=0;
- CardId=0; UseCount=0; Dead=false;
- SlotNum=num;
- Clock=ISO_FREQ;
-}
-
-cSmartCardSlot::~cSmartCardSlot()
-{
- delete Card;
- delete Serial;
-}
-
-// -- cSmartCard ---------------------------------------------------------------
-
-static const int Ftable[16] = {
- 372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0
- };
-
-static const float Dtable[16] = {
- 0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0,
- 0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625
- };
-
-cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg)
-{
- msg=Msg;
- ser=0; atr=0; idStr[0]=0; cardUp=false; needsReset=true;
- NewCardConfig(Cfg);
-}
-
-void cSmartCard::NewCardConfig(const struct CardConfig *Cfg)
-{
- cfg=Cfg;
-}
-
-bool cSmartCard::GetCardIdStr(char *str, int len)
-{
- strn0cpy(str,idStr,len);
- return (str[0]!=0);
-}
-
-bool cSmartCard::GetCardInfoStr(char *str, int len)
-{
- return infoStr.Get(str,len);
-}
-
-bool cSmartCard::Setup(cSerial *Ser, const struct Atr *Atr, int Id)
-{
- ser=Ser; atr=Atr; id=Id;
- if(cfg->SerMode==(ser->CurrentMode()&SM_MASK) && Init()) {
- cardUp=true; needsReset=false;
- return true;
- }
- return false;
-}
-
-#define NEED(x) { \
- if(len+(x)>Atr->atrLen) { \
- LBPUT("SHORT ATR"); \
- return false; \
- } \
- }
-
-bool cSmartCard::ParseAtr(struct Atr *Atr, int id, int clock)
-{
- // default values
- Atr->histLen=0; Atr->T=0; Atr->F=372; Atr->D=1.0; Atr->N=0; Atr->WI=10;
- Atr->BWI=4; Atr->CWI=0; Atr->Tspec=-1;
-
- const unsigned char *atr=Atr->atr;
- if(atr[0]==0x03) {
- PRINTF(L_CORE_SC,"%d: indirect convention detected",id);
- cSmartCard::Invert(Atr->atr,Atr->atrLen);
- Atr->convention=SM_INDIRECT;
- }
- else if(atr[0]==0x3B) {
- PRINTF(L_CORE_SC,"%d: direct convention detected",id);
- Atr->convention=SM_DIRECT;
- }
- else {
- PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",id,atr[0]);
- return false;
- }
-
- // TS TO
- Atr->histLen=atr[1]&0x0F;
- int Y=atr[1]&0xF0, i=1, len=2;
- LBSTARTF(L_CORE_SC);
- LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",id,atr[0],Atr->histLen,i,Y);
- do {
- if(Y&0x10) { // TAi
- NEED(1);
- LBPUT("TA%d=%02x ",i,atr[len]);
- if(i==1) {
- Atr->TA1=atr[len];
- Atr->F=Ftable[(atr[len]>>4)&0x0F];
- Atr->D=Dtable[ atr[len] &0x0F];
- LBPUT("F=%d D=%f ",Atr->F,Atr->D);
- }
- else if(i==2) {
- Atr->Tspec=atr[len]&0x0F;
- LBPUT("Tspec=%d ",Atr->Tspec);
- }
- else if(i==3) {
- LBPUT("IFSC=%d ",atr[len]);
- }
- len++;
- }
- if(Y&0x20) { // TBi
- NEED(1);
- LBPUT("TB%d=%02x ",i,atr[len]);
- if(i==3) {
- Atr->BWI=(atr[len]>>4)&0x0F;
- Atr->CWI=atr[len]&0x0F;
- LBPUT("BWI=%d CWI=%d ",Atr->BWI,Atr->CWI);
- }
- len++;
- }
- if(Y&0x40) { // TCi
- NEED(1);
- LBPUT("TC%d=%02x ",i,atr[len]);
- if(i==1) {
- Atr->N=atr[len];
- LBPUT("N=%d ",Atr->N);
- }
- else if(i==2) {
- Atr->WI=atr[len];
- LBPUT("WI=%d ",Atr->WI);
- }
- else if(i==3) {
- LBPUT("CHK=%s ",atr[len]&1 ? "CRC16":"LRC");
- }
- len++;
- }
- if(Y&0x80) { // TDi
- NEED(1);
- LBPUT("TD%d=%02x ",i,atr[len]);
- if(i==1) {
- Atr->T=atr[len]&0x0F;
- LBPUT("T=%d ",Atr->T);
- }
- else {
- LBPUT("Tn=%d ",atr[len]&0x0F);
- }
- Y=atr[len]&0xF0;
- len++;
- }
- else Y=0;
- i++;
- LBPUT("Y%d=%02x ",i,Y);
- } while(Y);
- NEED(Atr->histLen);
- LBEND();
-
- LBSTART(L_CORE_SC);
- LBPUT("%d: historical:",id);
- for(int i=0 ; i<Atr->histLen ; i++) LBPUT(" %02x",atr[len+i]);
- LBFLUSH();
- LBPUT("%d: historical: '",id);
- for(int i=0 ; i<Atr->histLen ; i++) LBPUT("%c",isprint(atr[len+i]) ? atr[len+i] : '.');
- LBEND();
+cSmartCardData::cSmartCardData(int Ident)
+{
+ ident=Ident;
+}
- memcpy(Atr->hist,&atr[len],Atr->histLen);
- len+=Atr->histLen;
+// -- cSmartCardDatas ----------------------------------------------------------
- // TCK
- if(Atr->T!=0 && len+1<=Atr->atrLen) {
- len++;
- unsigned char cs=XorSum(atr+1,len-1);
- // according to the ISO the initial TS byte isn't checksumed, but
- // some cards do so. In this case the checksum is equal TS.
- if(cs==0) PRINTF(L_CORE_SC,"%d: atr checksum ok",id);
- else if(cs==atr[0]) PRINTF(L_CORE_SC,"iso: %d: atr checksum is TS (not ISO compliant)",id);
- else {
- PRINTF(L_CORE_SC,"%d: atr checksum FAILED (cs:%02x)",id,cs);
- return false;
- }
- }
- else PRINTF(L_CORE_SC,"%d: atr checksum not given/not required",id);
+class cSmartCardDatas : public cStructList<cSmartCardData> {
+protected:
+ virtual cStructItem *ParseLine(char *line);
+public:
+ cSmartCardDatas(void);
+ cSmartCardData *Find(cSmartCardData *param);
+ };
- if(Atr->atrLen>len) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",id,Atr->atrLen,len);
- Atr->wwt=960*Atr->WI*Atr->F/(clock/1000);
- Atr->bwt=(int)(960*(float)(1<<Atr->BWI)*372/(clock/1000));
- PRINTF(L_CORE_SC,"%d: indicated wwt(T0)=%d ms, bwt(T1)=%d ms (at %.4f MHz)",id,Atr->wwt,Atr->bwt,(float)clock/1000000);
- return true;
+static cSmartCardDatas carddatas;
+
+cSmartCardDatas::cSmartCardDatas(void)
+:cStructList<cSmartCardData>("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE)
+{}
+
+cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param)
+{
+ ListLock(false);
+ cSmartCardData *cd;
+ for(cd=First(); cd; cd=Next(cd))
+ if(cd->Ident()==param->Ident() && cd->Matches(param)) break;
+ ListUnlock();
+ return cd;
}
-void cSmartCard::Invert(unsigned char *data, int n)
+cStructItem *cSmartCardDatas::ParseLine(char *line)
{
- static const unsigned char swaptab[] = { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 };
- for(int i=n-1; i>=0; i--)
- data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4];
+ char *r=index(line,':');
+ if(r)
+ for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl))
+ if(!strncasecmp(scl->Name(),line,r-line)) {
+ cSmartCardData *scd=scl->CreateData();
+ if(scd && scd->Parse(r+1)) return scd;
+ delete scd;
+ break;
+ }
+ return 0;
}
-int cSmartCard::SerRead(unsigned char *data, int len, int to)
+// -- cSmartCard ---------------------------------------------------------------
+
+cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg)
{
- if(atr->T==1 || atr->T==14) {
- int r=Read(data,len,to);
- if(r<0) Test(false);
- return r;
- }
- else {
- PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",id,atr->T);
- return -1;
- }
+ msg=Msg;
+ slot=0; atr=0; idStr[0]=0; cardUp=false;
+ NewCardConfig(Cfg);
}
-int cSmartCard::SerWrite(const unsigned char *data, int len)
+void cSmartCard::NewCardConfig(const struct CardConfig *Cfg)
{
- if(atr->T==1 || atr->T==14) {
- int r=Write(data,len);
- if(r<0) Test(false);
- return r;
- }
- else {
- PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",id,atr->T);
- return -1;
- }
+ cfg=Cfg;
}
-int cSmartCard::Read(unsigned char *data, int len, int to)
+bool cSmartCard::GetCardIdStr(char *str, int len)
{
- int r=ser->Read(data,len,cfg->serTO,to);
- if(atr->convention==SM_INDIRECT && r>0) Invert(data,r);
- return r;
+ strn0cpy(str,idStr,len);
+ return (str[0]!=0);
+}
+
+bool cSmartCard::GetCardInfoStr(char *str, int len)
+{
+ return infoStr.Get(str,len);
}
-int cSmartCard::Write(const unsigned char *data, int len)
+bool cSmartCard::Setup(cSmartCardSlot *Slot, int sermode, const struct Atr *Atr)
{
- unsigned char *tmp=AUTOMEM(len);
- if(atr->convention==SM_INDIRECT) {
- memcpy(tmp,data,len);
- Invert(tmp,len);
- data=tmp;
- }
- int r=ser->Write(data,len,cfg->serDL);
- if(r>0) {
- unsigned char *buff=AUTOMEM(r);
- int rr=ser->Read(buff,r,cfg->serTO);
- if(rr<0) r=rr;
- }
- return r;
+ slot=Slot; atr=Atr; slotnum=slot->SlotNum();
+ cardUp=false;
+ if(cfg->SerMode==sermode && Init()) cardUp=true;
+ return cardUp;
}
-int cSmartCard::Procedure(unsigned char ins, int restLen)
+int cSmartCard::SerRead(unsigned char *data, int len, int to)
{
- int r;
- unsigned char buff;
- LBSTARTF(L_CORE_SC);
- LBPUT("%d: <- PROC: ",id);
- do {
- do {
- if(Read(&buff,1,cfg->workTO)<=0) return -1;
- LBPUT("%02x ",buff);
- } while(buff==0x60);
+ if(atr->T==1 || atr->T==14) return slot->RawRead(data,len,to);
+ PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T);
+ return -1;
+}
- if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2
- sb[0]=buff;
- if(Read(&buff,1)<=0) return -1;
- LBPUT("%02x",buff);
- sb[1]=buff;
- return 0;
- }
- else {
- if((buff&0xFE)==(ins&0xFE)) r=restLen;
- else if((~buff&0xFE)==(ins&0xFE)) r=1;
- else {
- LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins);
- return -1;
- }
- if(r>restLen) {
- LBPUT("data overrun r=%d restLen=%d",r,restLen);
- return -1;
- }
- }
- } while(r==0);
- LBEND();
- return r;
+int cSmartCard::SerWrite(const unsigned char *data, int len)
+{
+ if(atr->T==1 || atr->T==14) return slot->RawWrite(data,len);
+ PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T);
+ return -1;
}
bool cSmartCard::IsoRead(const unsigned char *cmd, unsigned char *data)
{
- if(atr->T==0) { // only for ISO complaint cards
- LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",id);
- if(Write(cmd,CMD_LEN)<0) return Test(false);
- int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256;
- int len=0;
- while(1) {
- int r=Procedure(cmd[INS_IDX],tr-len);
- if(r<=0) return Test(r==0);
- if(Read(data+len,r)<0) return Test(false);
- LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",id);
- len+=r;
- }
- }
- else PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",id,atr->T);
+ if(atr->T==0) return slot->IsoRead(cmd,data);
+ PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",slotnum,atr->T);
return false;
}
bool cSmartCard::IsoWrite(const unsigned char *cmd, const unsigned char *data)
{
- if(atr->T==0) { // only for ISO complaint cards
- LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",id);
- if(Write(cmd,CMD_LEN)<0) return Test(false);
- int len=0;
- while(1) {
- int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len);
- if(r<=0) return Test(r==0);
- if(Write(data+len,r)<0) return Test(false);
- LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",id);
- len+=r;
- }
- }
- else PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",id,atr->T);
+ if(atr->T==0) return slot->IsoWrite(cmd,data);
+ PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",slotnum,atr->T);
return false;
}
-bool cSmartCard::Test(bool res)
-{
- if(!res) {
- TriggerReset();
- PRINTF(L_CORE_SC,"%d: reset triggered",id);
- }
- return res;
-}
-
bool cSmartCard::Status(void)
{
const struct StatusMsg *m=msg;
while(m->sb[0]!=0xFF) {
if(sb[0]==m->sb[0] && (m->sb[1]==0xFF || sb[1]==m->sb[1])) {
- if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",id,m->message,sb[0],sb[1]);
+ if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",slotnum,m->message,sb[0],sb[1]);
return m->retval;
}
m++;
}
- PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",id,sb[0],sb[1]);
+ PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",slotnum,sb[0],sb[1]);
return false;
}
cSmartCards smartcards;
-static const char *serModes[] = { 0,"8e2","8o2","8n2" };
-
-cSmartCards::cSmartCards(void)
-:cThread("SmartcardWatcher")
-,cStructListPlain<cSmartCardSlot>("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE)
-{
- firstRun=true;
-}
-
void cSmartCards::Register(cSmartCardLink *scl)
{
PRINTF(L_CORE_DYN,"registering %s smartcard (id %x)",scl->name,scl->id);
first=scl;
}
-void cSmartCards::LaunchWatcher(void)
-{
- firstRun=true;
- if(Count()>0) Start();
- else {
- firstRun=false;
- PRINTF(L_GEN_WARN,"no smartcard slot defined!");
- }
-}
-
void cSmartCards::Shutdown(void)
{
- PreLoad();
+ carddatas.SafeClear();
+ cardslots.SafeClear();
}
-void cSmartCards::PreLoad(void)
+void cSmartCards::Disable(void)
{
- Cancel(3);
- mutex.Lock();
- Clear(); Modified(false);
- mutex.Unlock();
+ carddatas.Disable();
+ cardslots.Disable();
}
-bool cSmartCards::ParseLinePlain(const char *line)
+cSmartCardData *cSmartCards::FindCardData(cSmartCardData *param)
{
- char type[32];
- int num;
- if(sscanf(line,"%31[^:]:%n",type,&num)==1) {
- if(!strcasecmp(type,"serial")) {
- int invCD=0, invRST=0, clock=0;
- char devName[64];
- if(sscanf(&line[num],"%63[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) {
- cSmartCardSlot *slot=new cSmartCardSlot(Count());
- if(slot) {
- cSerial *ser=new cSerial(devName,invCD,invRST);
- if(ser && ser->Open()) {
- slot->Serial=ser;
- if(clock>0) slot->Clock=clock;
- Add(slot);
- PRINTF(L_CORE_LOAD,"smartcards: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)",
- devName,slot->SlotNum,invCD?"inverse":"normal",invRST?"inverse":"normal",slot->Clock);
- return true;
- }
- else PRINTF(L_GEN_ERROR,"failed to open serial port %s",devName);
- delete ser;
- delete slot;
- }
- else PRINTF(L_GEN_ERROR,"failed to create cardslot");
- }
- else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",type);
- }
- else PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type);
- }
- return false;
+ return carddatas.Find(param);
}
-
bool cSmartCards::HaveCard(int id)
{
- cMutexLock lock(&mutex);
- while(Running() && firstRun) cond.Wait(mutex);
- for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
- if(slot->CardId==id) return true;
- return false;
+ bool res=false;
+ for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
+ if(slot->HaveCard(id)) { res=true; break; }
+ cardslots.Release();
+ return res;
}
cSmartCard *cSmartCards::LockCard(int id)
{
- mutex.Lock();
- while(Running() && firstRun) cond.Wait(mutex);
- for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) {
- if(slot->CardId==id) {
- slot->UseCount++;
- mutex.Unlock();
- cSmartCard *sc=slot->Card;
- sc->Lock();
- if(CardInserted(slot->Serial) && sc->CardUp() && !sc->NeedsReset())
- return sc;
- // if failed, unlock the card and decrement UseCount
- sc->Unlock();
- mutex.Lock();
- slot->UseCount--;
- cond.Broadcast();
- break;
- }
- }
- mutex.Unlock();
- return 0;
+ cSmartCard *sc=0;
+ for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
+ if((sc=slot->LockCard(id))) break;
+ cardslots.Release();
+ return sc;
}
void cSmartCards::ReleaseCard(cSmartCard *sc)
{
- sc->Unlock();
- mutex.Lock();
- for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) {
- if(slot->Card==sc) {
- slot->UseCount--;
- cond.Broadcast();
- mutex.Unlock();
- return;
- }
- }
- mutex.Unlock();
- PRINTF(L_GEN_DEBUG,"internal: can't find port in cSmartCards::ReleaseCard()");
-}
-
-bool cSmartCards::CardInserted(cSerial *ser)
-{
- return ser->CheckCAR();
-}
-
-bool cSmartCards::CardReset(cSmartCardSlot *port)
-{
- if(Reset(port)<2 || !cSmartCard::ParseAtr(&port->Atr,port->SlotNum,port->Clock))
- return false;
- if(!DoPTS(port)) {
- // reset card again and continue without PTS
- if(Reset(port)<2 || !cSmartCard::ParseAtr(&port->Atr,port->SlotNum,port->Clock))
- return false;
- }
- return true;
-}
-
-int cSmartCards::Reset(cSmartCardSlot *port)
-{
- cSerial *ser=port->Serial;
- PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",port->SlotNum,serModes[ser->CurrentMode()]);
- ser->ToggleRTS();
- cCondWait::SleepMs(100);
- ser->ToggleRTS();
- int r=ser->Read(port->Atr.atr,-MAX_ATR_LEN,800,2000);
- port->Atr.atrLen=r;
- if(r>0) LDUMP(L_CORE_SC,port->Atr.atr,r,"%d: <- ATR len=%d:",port->SlotNum,r);
- return r;
-}
-
-bool cSmartCards::DoPTS(cSmartCardSlot *port)
-{
- const struct Atr *atr=&port->Atr;
- if(atr->F!=372 || atr->D!=1.0) { // PTS required
- cSerial *ser=port->Serial;
- const int id=port->SlotNum;
- int baud=(int)((float)port->Clock*atr->D/atr->F);
- PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",id,baud);
-
- if(atr->Tspec<0) {
- PRINTF(L_CORE_SC,"%d: negotiable mode",id);
-#ifdef NO_PTS_PROTO
- PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",id);
- return true;
-#else
- unsigned char req[4], conf[16];
- req[0]=0xFF;
- req[1]=0x10 | atr->T;
- req[2]=atr->TA1;
- req[3]=XorSum(req,3);
- LDUMP(L_CORE_SC,req,4,"%d: PTS request:",id);
- if(ser->Write(req,4)!=4) {
- PRINTF(L_CORE_SC,"%d: PTS request, write failed",id);
- return false;
- }
- if(ser->Read(conf,4,100,100)!=4) {
- PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",id);
- return false;
- }
- int n=ser->Read(conf,-16,200,1000);
- if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",id);
- if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) {
- PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",id);
- return false;
- }
- if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) {
- PRINTF(L_CORE_SC,"%d: PTS not confirmed",id);
- return false;
- }
-#endif // NO_PTS_PROTO
- }
- else
- PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",id,atr->Tspec);
-
- int mode=ser->CurrentMode();
- if(atr->N==255) mode|=SM_1SB;
- if(!ser->SetMode(mode,baud)) {
- PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",id,baud);
- return false;
- }
- }
- return true;
-}
-
-void cSmartCards::SetPort(cSmartCardSlot *port, cSmartCard *sc, int id, bool dead)
-{
- mutex.Lock();
- while(port->UseCount) cond.Wait(mutex);
- delete port->Card;
- port->Card=sc;
- port->CardId=id;
- port->Dead=dead;
- port->UseCount=0;
- mutex.Unlock();
-}
-
-void cSmartCards::Action(void)
-{
- while(Running()) {
- for(cSmartCardSlot *slot=First(); slot;) {
- cSerial *ser=slot->Serial;
- if(ser) {
- if(slot->Card) {
- cSmartCard *sc=slot->Card;
- sc->Lock();
- if(!CardInserted(ser)) {
- sc->Unlock(); sc=0;
- PRINTF(L_CORE_SC,"%d: card removed (UseCount=%d)",slot->SlotNum,slot->UseCount);
- SetPort(slot,0,0,false);
- }
- else if(sc->NeedsReset()) {
- PRINTF(L_CORE_SC,"%d: card reset requested",slot->SlotNum);
- if(!ser->SetMode(ser->CurrentMode()&SM_MASK)
- || !CardReset(slot)
- || !sc->Setup(ser,&slot->Atr,slot->SlotNum)) {
- sc->Unlock(); sc=0;
- PRINTF(L_CORE_SC,"%d: card re-init failed",slot->SlotNum);
- SetPort(slot,0,0,true);
- }
- }
- if(sc) sc->Unlock();
- }
- else if(CardInserted(ser)) {
- if(!slot->Dead) {
- PRINTF(L_CORE_SC,"%d: new card inserted",slot->SlotNum);
- for(int mode=SM_NONE+1 ; mode<SM_MAX ; mode++) {
- if(ser->SetMode(mode)) {
- if(CardReset(slot)) {
- cSmartCardLink *scl=first;
- while(scl) {
- PRINTF(L_CORE_SC,"%d: checking for %s card",slot->SlotNum,scl->name);
- cSmartCard *sc=scl->Create();
- if(sc && sc->Setup(ser,&slot->Atr,slot->SlotNum)) {
- SetPort(slot,sc,scl->id,false);
- goto next; // ugly, any better solution?
- }
- delete sc;
- scl=scl->next;
- }
- PRINTF(L_CORE_SC,"%d: no card handler found",slot->SlotNum);
- }
- else PRINTF(L_CORE_SC,"%d: reset/atr error",slot->SlotNum);
- }
- else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slot->SlotNum,serModes[mode]);
- }
- slot->Dead=true;
- PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slot->SlotNum);
- }
- }
- else {
- if(slot->Dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slot->SlotNum);
- slot->Dead=false;
- }
- }
-next: slot=Next(slot);
- }
- if(firstRun) {
- mutex.Lock();
- cond.Broadcast();
- firstRun=false;
- mutex.Unlock();
- }
- cCondWait::SleepMs(300);
- }
-}
-
-cSmartCardSlot *cSmartCards::GetSlot(int num)
-{
- for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
- if(slot->SlotNum==num) return slot;
- return 0;
+ for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
+ slot->ReleaseCard(sc);
+ cardslots.Release();
}
bool cSmartCards::ListCard(int num, char *str, int len)
{
- cSmartCardSlot *slot=GetSlot(num);
- if(!slot) return false;
+ cSmartCardSlot *slot=cardslots.GetSlot(num);
str[0]=0;
- mutex.Lock();
- cSmartCard *sc=slot->Card;
- if(sc) {
- if(!sc->GetCardIdStr(str,len)) {
- cSmartCardLink *scl=first;
- while(scl) {
- if(scl->id==slot->CardId) {
- strn0cpy(str,scl->name,len);
- break;
- }
- scl=scl->next;
- }
- }
- }
- mutex.Unlock();
- return true;
+ bool res=false;
+ if(slot) { slot->GetCardIdStr(str,len); res=true; }
+ cardslots.Release();
+ return res;
}
bool cSmartCards::CardInfo(int num, char *str, int len)
{
+ cSmartCardSlot *slot=cardslots.GetSlot(num);
+ str[0]=0;
bool res=false;
- cSmartCardSlot *slot=GetSlot(num);
- if(slot) {
- str[0]=0;
- mutex.Lock();
- cSmartCard *sc=slot->Card;
- if(sc) res=sc->GetCardInfoStr(str,len);
- mutex.Unlock();
- }
+ if(slot) res=slot->GetCardInfoStr(str,len);
+ cardslots.Release();
return res;
}
void cSmartCards::CardReset(int num)
{
- cSmartCardSlot *slot=GetSlot(num);
- if(slot) {
- mutex.Lock();
- cSmartCard *sc=slot->Card;
- if(sc) sc->TriggerReset();
- mutex.Unlock();
- }
+ cSmartCardSlot *slot=cardslots.GetSlot(num);
+ if(slot) slot->TriggerReset();
+ cardslots.Release();
}