SASC-NG
DVBSoftCAM

smartcard.c

Go to the documentation of this file.
00001 /*
00002  * Softcam plugin to VDR (C++)
00003  *
00004  * This code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00018  */
00019 
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <errno.h>
00023 #include <fcntl.h>
00024 #include <sys/ioctl.h>
00025 #include <sys/poll.h>
00026 #include <unistd.h>
00027 #include <termios.h>
00028 #include <linux/serial.h>
00029 #include <ctype.h>
00030 
00031 #include <vdr/tools.h>
00032 #include <vdr/thread.h>
00033 
00034 #include "smartcard.h"
00035 #include "global.h"
00036 #include "misc.h"
00037 #include "log-core.h"
00038 
00039 #define ISO_FREQ 3571200 // Hz
00040 #define ISO_BAUD 9600
00041 
00042 //#define CARD_EMU     // include smartcard emulation code
00043 //#define NO_PTS_PROTO // disable PTS protocol (baudrate changes)
00044 
00045 // -- cSmartCardSlot -----------------------------------------------------------
00046 
00047 class cSmartCardSlot : private cThread, public cStructItem {
00048 private:
00049   cSmartCard *card;
00050   int usecount, cardid;
00051   bool firstRun, needsReset, dead;
00052   cMutex mutex;
00053   cCondVar cond;
00054   //
00055   void SetCard(cSmartCard *c, int cid=0);
00056   bool CardReset(void);
00057 protected:
00058   virtual bool DeviceOpen(const char *cfg)=0;
00059   virtual void DeviceClose(void) {}
00060   virtual bool DeviceSetMode(int mode, int baud)=0;
00061   virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0)=0;
00062   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0)=0;
00063   virtual void DeviceToggleReset(void)=0;
00064   virtual bool DevicePTS(void)=0;
00065   virtual bool DeviceIsInserted(void)=0;
00066   virtual int DeviceCurrentMode(void) { return currMode; }
00067   //
00068   virtual void Action(void);
00069   //
00070   int Procedure(unsigned char ins, int restLen);
00071   int Read(unsigned char *data, int len, int to=0);
00072   int Write(const unsigned char *data, int len);
00073   bool Test(bool res);
00074   void Invert(unsigned char *data, int n);
00075   virtual bool Reset(void);
00076   bool ParseAtr(void);
00077   //
00078   int slotnum, clock;
00079   const struct CardConfig *cfg;
00080   unsigned char sb[SB_LEN];
00081   struct Atr atr;
00082   bool localecho, singlereset;
00083   //
00084   char devName[256];
00085   int currMode;
00086 public:
00087   cSmartCardSlot(void);
00088   virtual ~cSmartCardSlot();
00089   bool Setup(int num, const char *cfg);
00090   void SetCardConfig(const struct CardConfig *Cfg) { cfg=Cfg; }
00091   void TriggerReset(void) { needsReset=true; }
00092   bool HaveCard(int id);
00093   cSmartCard *LockCard(int id);
00094   void ReleaseCard(cSmartCard *sc);
00095   void GetCardIdStr(char *str, int len);
00096   bool GetCardInfoStr(char *str, int len);
00097   int SlotNum(void) { return slotnum; }
00098   //
00099   virtual bool IsoRead(const unsigned char *cmd, unsigned char *data);
00100   virtual bool IsoWrite(const unsigned char *cmd, const unsigned char *data);
00101   virtual int RawRead(unsigned char *data, int len, int to=0);
00102   virtual int RawWrite(const unsigned char *data, int len);
00103   };
00104 
00105 static const char *serModes[] = { 0,"8e2","8o2","8n2" };
00106 
00107 cSmartCardSlot::cSmartCardSlot(void)
00108 {
00109   card=0; cfg=0; usecount=0; slotnum=-1; currMode=SM_NONE; clock=ISO_FREQ;
00110   firstRun=true; needsReset=false; dead=false;
00111   localecho=true; singlereset=false;
00112 }
00113 
00114 cSmartCardSlot::~cSmartCardSlot()
00115 {
00116   Cancel(3);
00117   SetCard(0);
00118   DeviceClose();
00119 }
00120 
00121 bool cSmartCardSlot::Setup(int num, const char *cfg)
00122 {
00123   slotnum=num;
00124   SetDescription("CardSlot %d watcher",slotnum);
00125   if(DeviceOpen(cfg)) {
00126     firstRun=true;
00127     Start();
00128     return true;
00129     }
00130   return false;
00131 }
00132 
00133 bool cSmartCardSlot::HaveCard(int id)
00134 {
00135   cMutexLock lock(&mutex);
00136   while(Running() && firstRun) cond.Wait(mutex);
00137   return card && cardid==id;
00138 }
00139 
00140 cSmartCard *cSmartCardSlot::LockCard(int id)
00141 {
00142   mutex.Lock();
00143   while(Running() && firstRun) cond.Wait(mutex);
00144   if(card && cardid==id) {
00145     usecount++;
00146     mutex.Unlock();
00147     card->Lock();
00148     if(DeviceIsInserted() && card->CardUp() && !needsReset) return card;
00149     // if failed, unlock the card and decrement UseCount
00150     card->Unlock();
00151     mutex.Lock();
00152     usecount--;
00153     cond.Broadcast();
00154     }
00155   mutex.Unlock();
00156   return 0;
00157 }
00158 
00159 void cSmartCardSlot::ReleaseCard(cSmartCard *sc)
00160 {
00161   if(card==sc) {
00162     card->Unlock();
00163     mutex.Lock();
00164     usecount--;
00165     cond.Broadcast();
00166     mutex.Unlock();
00167     }
00168 }
00169 
00170 void cSmartCardSlot::GetCardIdStr(char *str, int len)
00171 {
00172   mutex.Lock();
00173   if(card && !card->GetCardIdStr(str,len)) {
00174     for(cSmartCardLink *scl=smartcards.First(); scl; smartcards.Next(scl)) {
00175       if(scl->Id()==cardid) {
00176         strn0cpy(str,scl->Name(),len);
00177         break;
00178         }
00179       }
00180     }
00181   mutex.Unlock();
00182 }
00183 
00184 bool cSmartCardSlot::GetCardInfoStr(char *str, int len)
00185 {
00186   mutex.Lock();
00187   bool res=false;
00188   if(card) res=card->GetCardInfoStr(str,len);
00189   mutex.Unlock();
00190   return res;
00191 }
00192 
00193 void cSmartCardSlot::SetCard(cSmartCard *c, int cid)
00194 {
00195   mutex.Lock();
00196   while(usecount) cond.Wait(mutex);
00197   delete card;
00198   card=c; cardid=cid; needsReset=dead=false;
00199   mutex.Unlock();
00200 }
00201 
00202 void cSmartCardSlot::Action(void)
00203 {
00204   while(Running()) {
00205     if(card) {
00206       card->Lock();
00207       if(!DeviceIsInserted()) {
00208         card->Unlock();
00209         PRINTF(L_CORE_SC,"%d: card removed (usecount=%d)",slotnum,usecount);
00210         SetCard(0);
00211         }
00212       else if(needsReset) {
00213         PRINTF(L_CORE_SC,"%d: card reset requested",slotnum);
00214         int mode=DeviceCurrentMode()&SM_MASK;
00215         if(!DeviceSetMode(mode,ISO_BAUD)
00216             || !CardReset()
00217             || !card->Setup(this,mode,&atr,sb)) {
00218           card->Unlock();
00219           PRINTF(L_CORE_SC,"%d: card re-init failed",slotnum);
00220           SetCard(0); dead=true;
00221           }
00222         }
00223       if(card) card->Unlock();
00224       }
00225     else if(DeviceIsInserted()) {
00226       if(!dead) {
00227         PRINTF(L_CORE_SC,"%d: new card inserted",slotnum);
00228         bool resetdone=false;
00229         for(int mode=SM_NONE+1 ; mode<SM_MAX ; mode++) {
00230           if(DeviceSetMode(mode,ISO_BAUD)) {
00231             if((singlereset && resetdone) || (resetdone=CardReset())) {
00232               for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl)) {
00233                 if(!Running()) goto done;
00234                 PRINTF(L_CORE_SC,"%d: checking for %s card",slotnum,scl->Name());
00235                 cSmartCard *sc=scl->Create();
00236                 if(sc && sc->Setup(this,mode,&atr,sb)) {
00237                   SetCard(sc,scl->Id());
00238                   goto done; // ugly, any better solution?
00239                   }
00240                 delete sc;
00241                 }
00242               PRINTF(L_CORE_SC,"%d: no card handler found",slotnum);
00243               }
00244             else PRINTF(L_CORE_SC,"%d: reset/atr error",slotnum);
00245             }
00246           else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slotnum,serModes[mode]);
00247           }
00248         dead=true;
00249         PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slotnum);
00250         }
00251       }
00252     else {
00253       if(dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slotnum);
00254       dead=false;
00255       }
00256 done:
00257     if(firstRun) {
00258       mutex.Lock();
00259       cond.Broadcast();
00260       firstRun=false;
00261       mutex.Unlock();
00262       }
00263     cCondWait::SleepMs(300);
00264     }
00265 }
00266 
00267 bool cSmartCardSlot::Reset(void)
00268 {
00269   PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",slotnum,serModes[DeviceCurrentMode()]);
00270   DeviceToggleReset();
00271   cCondWait::SleepMs(100);
00272   DeviceToggleReset();
00273   int r=DeviceRead(atr.atr,-MAX_ATR_LEN,800,2000);
00274   atr.atrLen=r;
00275   if(r>0) LDUMP(L_CORE_SC,atr.atr,r,"%d: <- ATR len=%d:",slotnum,r);
00276   return r>=2;
00277 }
00278 
00279 bool cSmartCardSlot::CardReset(void)
00280 {
00281   if(!Reset() || !ParseAtr()) return false;
00282   if((atr.F!=372 || atr.D!=1.0) && !DevicePTS()) {
00283     // reset card again and continue without PTS
00284     if(!Reset() || !ParseAtr()) return false;
00285     }
00286   return true;
00287 }
00288 
00289 void cSmartCardSlot::Invert(unsigned char *data, int n)
00290 {
00291   static const unsigned char swaptab[] =  { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 };
00292   for(int i=n-1; i>=0; i--)
00293     data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4];
00294 }
00295 
00296 int cSmartCardSlot::Read(unsigned char *data, int len, int to)
00297 {
00298   int r=DeviceRead(data,len,cfg->serTO,to);
00299   if(atr.convention==SM_INDIRECT && r>0) Invert(data,r);
00300   return r;
00301 }
00302 
00303 int cSmartCardSlot::Write(const unsigned char *data, int len)
00304 {
00305   unsigned char *tmp=AUTOMEM(len);
00306   if(atr.convention==SM_INDIRECT) {
00307     memcpy(tmp,data,len);
00308     Invert(tmp,len);
00309     data=tmp;
00310     }
00311   int r=DeviceWrite(data,len,cfg->serDL);
00312   if(r>0 && localecho) {
00313     unsigned char *buff=AUTOMEM(r);
00314     int rr=DeviceRead(buff,r,cfg->serTO);
00315     if(rr<0) r=rr;
00316     }
00317   return r;
00318 }
00319 
00320 int cSmartCardSlot::Procedure(unsigned char ins, int restLen)
00321 {
00322   int r;
00323   unsigned char buff;
00324   LBSTARTF(L_CORE_SC);
00325   LBPUT("%d: <- PROC: ",slotnum);
00326   do {
00327     do {
00328       if(Read(&buff,1,cfg->workTO)<=0) return -1;
00329       LBPUT("%02x ",buff);
00330       } while(buff==0x60);
00331 
00332     if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2
00333       sb[0]=buff;
00334       if(Read(&buff,1)<=0) return -1;
00335       LBPUT("%02x",buff);
00336       sb[1]=buff;
00337       return 0;
00338       }
00339     else {
00340       if((buff&0xFE)==(ins&0xFE)) r=restLen;
00341       else if((~buff&0xFE)==(ins&0xFE)) r=1;
00342       else {
00343         LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins);
00344         return -1;
00345         }
00346       if(r>restLen) {
00347         LBPUT("data overrun r=%d restLen=%d",r,restLen);
00348         return -1;
00349         }
00350       }
00351     } while(r==0);
00352   LBEND();
00353   return r;
00354 }
00355 
00356 bool cSmartCardSlot::Test(bool res)
00357 {
00358  if(!res) {
00359    TriggerReset();
00360    PRINTF(L_CORE_SC,"%d: reset triggered",slotnum);
00361    }
00362  return res;
00363 }
00364 
00365 bool cSmartCardSlot::IsoRead(const unsigned char *cmd, unsigned char *data)
00366 {
00367   LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
00368   if(Write(cmd,CMD_LEN)<0) return Test(false);
00369   int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256;
00370   int len=0;
00371   while(1) {
00372     int r=Procedure(cmd[INS_IDX],tr-len);
00373     if(r<=0) return Test(r==0);
00374     if(Read(data+len,r)<0) return Test(false);
00375     LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",slotnum);
00376     len+=r;
00377     }
00378 }
00379 
00380 bool cSmartCardSlot::IsoWrite(const unsigned char *cmd, const unsigned char *data)
00381 {
00382   LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
00383   if(Write(cmd,CMD_LEN)<0) return Test(false);
00384   int len=0;
00385   while(1) {
00386     int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len);
00387     if(r<=0) return Test(r==0);
00388     if(Write(data+len,r)<0) return Test(false);
00389     LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",slotnum);
00390     len+=r;
00391     }
00392 }
00393 
00394 int cSmartCardSlot::RawRead(unsigned char *data, int len, int to)
00395 {
00396   int r=Read(data,len,to);
00397   if(r<0) Test(false);
00398   return r;
00399 }
00400 
00401 int cSmartCardSlot::RawWrite(const unsigned char *data, int len)
00402 {
00403   int r=Write(data,len);
00404   if(r<0) Test(false);
00405   return r;
00406 }
00407 
00408 #define NEED(x) { if(len+(x)>atr.atrLen) { LBPUT("SHORT ATR"); return false; } }
00409 
00410 bool cSmartCardSlot::ParseAtr(void)
00411 {
00412   // default values
00413   atr.histLen=0; atr.T=0; atr.F=372; atr.fs=clock; atr.D=1.0; atr.N=0; atr.WI=10;
00414   atr.BWI=4; atr.CWI=0; atr.Tspec=-1;
00415 
00416   static const int Ftable[16] = {
00417     372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0
00418     };
00419   static const int fstable[16] = {
00420     3571200,5000000,6000000, 8000000,12000000,16000000,20000000,0,
00421           0,5000000,7500000,10000000,15000000,20000000,       0,0
00422     };
00423   static const float Dtable[16] = {
00424     0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0,
00425     0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625
00426     };
00427 
00428   const unsigned char *rawatr=atr.atr;
00429   if(rawatr[0]==0x03) {
00430     PRINTF(L_CORE_SC,"%d: indirect convention detected",slotnum);
00431     Invert(atr.atr,atr.atrLen);
00432     atr.convention=SM_INDIRECT;
00433     }
00434   else if(rawatr[0]==0x3B) {
00435     PRINTF(L_CORE_SC,"%d: direct convention detected",slotnum);
00436     atr.convention=SM_DIRECT;
00437     }
00438   else if(rawatr[0]==0x3F) {
00439     PRINTF(L_CORE_SC,"%d: inverted indirect convention detected",slotnum);
00440     atr.convention=SM_INDIRECT_INV;
00441     }
00442   else {
00443     PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",slotnum,rawatr[0]);
00444     return false;
00445     }
00446 
00447   // TS TO
00448   atr.histLen=rawatr[1]&0x0F;
00449   int Y=rawatr[1]&0xF0, i=1, len=2;
00450   LBSTARTF(L_CORE_SC);
00451   LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",slotnum,rawatr[0],atr.histLen,i,Y);
00452   do {
00453     if(Y&0x10) { // TAi
00454       NEED(1);
00455       LBPUT("TA%d=%02x ",i,rawatr[len]);
00456       if(i==1) {
00457         atr.TA1=rawatr[len];
00458         int i=(rawatr[len]>>4)&0x0F;
00459         atr.F=Ftable[i]; atr.fs=fstable[i];
00460         atr.D=Dtable[rawatr[len]&0x0F];
00461         LBPUT("F=%d fs=%.4f D=%f ",atr.F,atr.fs/1000000.0,atr.D);
00462         }
00463       else if(i==2) {
00464         atr.Tspec=rawatr[len]&0x0F;
00465         LBPUT("Tspec=%d ",atr.Tspec);
00466         }
00467       else if(i==3) {
00468         LBPUT("IFSC=%d ",rawatr[len]);
00469         }
00470       len++;
00471       }
00472     if(Y&0x20) { // TBi
00473       NEED(1);
00474       LBPUT("TB%d=%02x ",i,rawatr[len]);
00475       if(i==3) {
00476         atr.BWI=(rawatr[len]>>4)&0x0F;
00477         atr.CWI=rawatr[len]&0x0F;
00478         LBPUT("BWI=%d CWI=%d ",atr.BWI,atr.CWI);
00479         }
00480       len++;
00481       }
00482     if(Y&0x40) { // TCi
00483       NEED(1);
00484       LBPUT("TC%d=%02x ",i,rawatr[len]);
00485       if(i==1) {
00486         atr.N=rawatr[len];
00487         LBPUT("N=%d ",atr.N);
00488         }
00489       else if(i==2) {
00490         atr.WI=rawatr[len];
00491         LBPUT("WI=%d ",atr.WI);
00492         }
00493       else if(i==3) {
00494         LBPUT("CHK=%s ",rawatr[len]&1 ? "CRC16":"LRC");
00495         }
00496       len++;
00497       }
00498     if(Y&0x80) { // TDi
00499       NEED(1);
00500       LBPUT("TD%d=%02x ",i,rawatr[len]);
00501       if(i==1) {
00502         atr.T=rawatr[len]&0x0F;
00503         LBPUT("T=%d ",atr.T);
00504         }
00505       else {
00506         LBPUT("Tn=%d ",rawatr[len]&0x0F);
00507         }
00508       Y=rawatr[len]&0xF0;
00509       len++;
00510       }
00511     else Y=0;
00512     i++;
00513     LBPUT("Y%d=%02x ",i,Y);
00514     } while(Y);
00515   NEED(atr.histLen);
00516   LBEND();
00517 
00518   LBSTART(L_CORE_SC);
00519   LBPUT("%d: historical:",slotnum);
00520   for(int i=0; i<atr.histLen; i++) LBPUT(" %02x",rawatr[len+i]);
00521   LBFLUSH();
00522   LBPUT("%d: historical: '",slotnum);
00523   for(int i=0; i<atr.histLen; i++) LBPUT("%c",isprint(rawatr[len+i]) ? rawatr[len+i] : '.');
00524   LBEND();
00525 
00526   memcpy(atr.hist,&rawatr[len],atr.histLen);
00527   len+=atr.histLen;
00528 
00529   // TCK
00530   if(atr.T!=0 && len+1<=atr.atrLen) {
00531     len++;
00532     unsigned char cs=XorSum(rawatr+1,len-1);
00533     // according to the ISO the initial TS byte isn't checksumed, but
00534     // some cards do so. In this case the checksum is equal TS.
00535     if(cs==0) PRINTF(L_CORE_SC,"%d: atr checksum ok",slotnum);
00536     else if(cs==rawatr[0]) PRINTF(L_CORE_SC,"iso: %d: atr checksum is TS (not ISO compliant)",slotnum);
00537     else {
00538       PRINTF(L_CORE_SC,"%d: atr checksum FAILED (cs:%02x)",slotnum,cs);
00539       return false;
00540       }
00541     }
00542   else PRINTF(L_CORE_SC,"%d: atr checksum not given/not required",slotnum);
00543 
00544   if(atr.atrLen>len) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",slotnum,atr.atrLen,len);
00545   atr.wwt=960*atr.WI*atr.F/(clock/1000);
00546   atr.bwt=(int)(960*(float)(1<<atr.BWI)*372/(clock/1000));
00547   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);
00548   return true;
00549 }
00550 
00551 #undef NEED
00552 
00553 // -- cSmartCardSlots / cSmartCardSlotLink -------------------------------------
00554 
00555 class cSmartCardSlotLink {
00556 public:
00557   cSmartCardSlotLink *next;
00558   const char *name;
00559 public:
00560   cSmartCardSlotLink(const char *Name);
00561   virtual ~cSmartCardSlotLink() {}
00562   virtual cSmartCardSlot *Create(void)=0;
00563   };
00564 
00565 template<class LL> class cSmartCardSlotLinkReg : public cSmartCardSlotLink {
00566 public:
00567   cSmartCardSlotLinkReg(const char *Name):cSmartCardSlotLink(Name) {}
00568   virtual cSmartCardSlot *Create(void) { return new LL; }
00569   };
00570 
00571 class cSmartCardSlots : public cStructListPlain<cSmartCardSlot> {
00572 friend class cSmartCardSlotLink;
00573 private:
00574   static cSmartCardSlotLink *first;
00575   //
00576   static void Register(cSmartCardSlotLink *scl);
00577 protected:
00578   virtual bool ParseLinePlain(const char *line);
00579 public:
00580   cSmartCardSlots(void);
00581   cSmartCardSlot *GetSlot(int num);
00582   cSmartCardSlot *FirstSlot(void);
00583   void Release(void);
00584   };
00585 
00586 cSmartCardSlotLink *cSmartCardSlots::first=0;
00587 
00588 static cSmartCardSlots cardslots;
00589 
00590 cSmartCardSlotLink::cSmartCardSlotLink(const char *Name)
00591 {
00592   name=Name;
00593   cSmartCardSlots::Register(this);
00594 }
00595 
00596 cSmartCardSlots::cSmartCardSlots(void)
00597 :cStructListPlain<cSmartCardSlot>("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE)
00598 {}
00599 
00600 void cSmartCardSlots::Register(cSmartCardSlotLink *scl)
00601 {
00602   PRINTF(L_CORE_DYN,"registering cardslot type %s",scl->name);
00603   scl->next=first;
00604   first=scl;
00605 }
00606 
00607 cSmartCardSlot *cSmartCardSlots::GetSlot(int num)
00608 {
00609   ListLock(false);
00610   for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
00611     if(slot->SlotNum()==num) return slot;
00612   return 0;
00613 }
00614 
00615 cSmartCardSlot *cSmartCardSlots::FirstSlot(void)
00616 {
00617   ListLock(false);
00618   return First();
00619 }
00620 
00621 void cSmartCardSlots::Release(void)
00622 {
00623   ListUnlock();
00624 }
00625 
00626 bool cSmartCardSlots::ParseLinePlain(const char *line)
00627 {
00628   char type[32];
00629   int num;
00630   if(sscanf(line,"%31[^:]:%n",type,&num)==1) {
00631     for(cSmartCardSlotLink *scs=first; scs; scs=scs->next) {
00632       if(!strcasecmp(type,scs->name)) {
00633         cSmartCardSlot *slot=scs->Create();
00634         if(slot) {
00635           if(slot->Setup(Count(),&line[num])) {
00636             Add(slot);
00637             return true;
00638             }
00639           delete slot;
00640           }
00641         else PRINTF(L_GEN_ERROR,"failed to create cardslot");
00642         return false;
00643         }
00644       }
00645     PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type);
00646     }
00647   return false;
00648 }
00649 
00650 // -- cSmartCardSlotSerial -----------------------------------------------------
00651 
00652 class cSmartCardSlotSerial : public cSmartCardSlot {
00653 private:
00654   int statInv, invRST;
00655   bool custombaud;
00656   //
00657   speed_t FindBaud(int baud);
00658 protected:
00659   int fd;
00660   //
00661   void Flush(void);
00662   void SetDtrRts(void);
00663   //
00664   virtual bool DeviceOpen(const char *cfg);
00665   virtual void DeviceClose(void);
00666   virtual bool DeviceSetMode(int mode, int baud);
00667   virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0);
00668   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
00669   virtual void DeviceToggleReset(void);
00670   virtual bool DevicePTS(void);
00671   virtual bool DeviceIsInserted(void);
00672 public:
00673   cSmartCardSlotSerial(void);
00674   };
00675 
00676 static cSmartCardSlotLinkReg<cSmartCardSlotSerial> __scs_serial("serial");
00677 
00678 cSmartCardSlotSerial::cSmartCardSlotSerial(void)
00679 {
00680   fd=-1; statInv=0; invRST=false; custombaud=false;
00681 }
00682 
00683 bool cSmartCardSlotSerial::DeviceOpen(const char *cfg)
00684 {
00685   int invCD=0;
00686   if(sscanf(cfg,"%255[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) {
00687     if(clock<=0) clock=ISO_FREQ;
00688     statInv=invCD ? TIOCM_CAR:0;
00689     PRINTF(L_CORE_SERIAL,"%s: open serial port",devName);
00690     fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY);
00691     if(fd>=0) {
00692       SetDtrRts();
00693       PRINTF(L_CORE_SERIAL,"%s: init done",devName);
00694       PRINTF(L_CORE_LOAD,"cardslot: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)",
00695                 devName,slotnum,invCD?"inverse":"normal",invRST?"inverse":"normal",clock);
00696       return true;
00697       }
00698     else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));
00699     }
00700   else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'serial'");
00701   return false;
00702 }
00703 
00704 void cSmartCardSlotSerial::SetDtrRts(void)
00705 {
00706   PRINTF(L_CORE_SERIAL,"%s: set DTR/RTS",devName);
00707   unsigned int modembits;
00708   modembits=TIOCM_DTR; CHECK(ioctl(fd, TIOCMBIS, &modembits));
00709   modembits=TIOCM_RTS; CHECK(ioctl(fd, invRST?TIOCMBIS:TIOCMBIC, &modembits));
00710 }
00711 
00712 void cSmartCardSlotSerial::DeviceClose(void)
00713 {
00714   if(fd>=0) {
00715     PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);
00716     Flush();
00717     unsigned int modembits=0;
00718     CHECK(ioctl(fd,TIOCMSET,&modembits));
00719     close(fd); fd=-1;
00720     PRINTF(L_CORE_SERIAL,"%s: shutdown done",devName);
00721     }
00722 }
00723 
00724 void cSmartCardSlotSerial::Flush(void)
00725 {
00726   if(fd>=0) CHECK(tcflush(fd,TCIOFLUSH));
00727 }
00728 
00729 speed_t cSmartCardSlotSerial::FindBaud(int baud)
00730 {
00731   static const struct BaudRates { int real; speed_t apival; } BaudRateTab[] = {
00732     {   9600, B9600   }, {  19200, B19200  }, {  38400, B38400  },
00733     {  57600, B57600  }, { 115200, B115200 }, { 230400, B230400 }
00734     };
00735 
00736   for(int i=0; i<(int)(sizeof(BaudRateTab)/sizeof(struct BaudRates)); i++) {
00737     int b=BaudRateTab[i].real;
00738     int d=((b-baud)*10000)/b;
00739     if(abs(d)<=300) {
00740       PRINTF(L_CORE_SERIAL,"%s: requested baudrate %d -> %d (%+.2f%%)",devName,baud,b,(float)d/100.0);
00741       return BaudRateTab[i].apival;
00742       }
00743     }
00744   PRINTF(L_CORE_SERIAL,"%s: requested baudrate %d -> custom",devName,baud);
00745   return B0;
00746 }
00747 
00748 bool cSmartCardSlotSerial::DeviceSetMode(int mode, int baud)
00749 {
00750   if(fd>=0) {
00751     speed_t bconst=FindBaud(baud);
00752     bool custom=false;
00753     if(bconst==B0) { custom=true; bconst=B38400; }
00754 
00755     struct termios tio;
00756     memset(&tio,0,sizeof(tio));
00757     LBSTARTF(L_CORE_SERIAL);
00758     LBPUT("%s: set serial options: %d,",devName,baud);
00759     tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
00760     if(!(mode&SM_1SB)) tio.c_cflag |= CSTOPB;
00761     tio.c_iflag = (INPCK | IGNBRK);
00762     tio.c_cc[VMIN] = 1;
00763     cfsetispeed(&tio,bconst);
00764     cfsetospeed(&tio,bconst);
00765     switch(mode&SM_MASK) {
00766       case SM_8E2:
00767         LBPUT("8e%d",(mode&SM_1SB)?1:2);
00768         tio.c_cflag |= PARENB; break;
00769       case SM_8N2:
00770         LBPUT("8n%d",(mode&SM_1SB)?1:2);
00771         break;
00772       case SM_8O2:
00773         LBPUT("8o%d",(mode&SM_1SB)?1:2);
00774         tio.c_cflag |= (PARENB | PARODD); break;
00775       default:
00776         LBPUT("BAD MODE");
00777         return false;
00778       }
00779     LBEND();
00780 
00781     struct serial_struct s;
00782     if(ioctl(fd,TIOCGSERIAL,&s)<0) {
00783       if(custom || custombaud) {
00784         PRINTF(L_GEN_ERROR,"%s: get serial failed: %s",devName,strerror(errno));
00785         return false;
00786         }
00787       PRINTF(L_CORE_SERIAL,"%s: get serial failed: %s",devName,strerror(errno));
00788       PRINTF(L_CORE_SERIAL,"%s: custombaud not used, try to continue...",devName);
00789       }
00790     else if(!custom && ((s.flags&ASYNC_SPD_MASK)==ASYNC_SPD_CUST || s.custom_divisor!=0)) {
00791       s.custom_divisor=0;
00792       s.flags &= ~ASYNC_SPD_MASK;
00793       if(ioctl(fd,TIOCSSERIAL,&s)<0) {
00794         PRINTF(L_GEN_ERROR,"%s: set serial failed: %s",devName,strerror(errno));
00795         return false;
00796         }
00797       custombaud=false;
00798       }
00799     if(!tcsetattr(fd,TCSANOW,&tio)) {
00800       if(custom) {
00801         s.custom_divisor=(s.baud_base+(baud/2))/baud;
00802         s.flags=(s.flags&~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
00803         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);
00804         if(ioctl(fd,TIOCSSERIAL,&s)<0) {
00805           PRINTF(L_GEN_ERROR,"%s: set serial failed: %s",devName,strerror(errno));
00806           return false;
00807           }
00808         custombaud=true;
00809         }
00810       currMode=mode; Flush();
00811       return true;
00812       }
00813     else PRINTF(L_GEN_ERROR,"%s: tcsetattr failed: %s",devName,strerror(errno));
00814     }
00815   return false;
00816 }
00817 
00818 int cSmartCardSlotSerial::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout)
00819 {
00820   PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d:%d",devName,len,timeout,initialTimeout);
00821   bool incomplete=false;
00822   if(len<0) { len=-len; incomplete=true; }
00823   int to=initialTimeout>0 ? initialTimeout : timeout;
00824   int n=0;
00825   while(n<len) {
00826     int r=read(fd,mem+n,len-n);
00827     if(r<=0) {
00828       if(r==0) PRINTF(L_CORE_SERIAL,"%s: read bogus eof",devName);
00829       if(errno==EAGAIN) {
00830         struct pollfd u;
00831         u.fd=fd; u.events=POLLIN;
00832         r=poll(&u,1,to);
00833         if(r<0) {
00834           PRINTF(L_GEN_ERROR,"%s: read poll failed: %s",devName,strerror(errno));
00835           return -1;
00836           }
00837         else if(r==0) { // timeout
00838           PRINTF(L_CORE_SERIAL,"%s: read timeout (%d ms)",devName,to);
00839           if(n>0 && incomplete) break; // return bytes read so far
00840           return -2;
00841           }
00842         continue;
00843         }
00844       else {
00845         PRINTF(L_GEN_ERROR,"%s: read failed: %s",devName,strerror(errno));
00846         return -1;
00847         }
00848       }
00849     n+=r; to=timeout;
00850     }
00851   HEXDUMP(L_CORE_SERIAL,mem,n,"%s: read data",devName);
00852   return n;
00853 }
00854 
00855 int cSmartCardSlotSerial::DeviceWrite(const unsigned char *mem, int len, int delay)
00856 {
00857   PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
00858   HEXDUMP(L_CORE_SERIAL,mem,len,"%s: write data",devName);
00859   Flush();
00860   int n=0;
00861   while(n<len) {
00862     struct pollfd u;
00863     u.fd=fd; u.events=POLLOUT;
00864     int r;
00865     do {
00866       r=poll(&u,1,500);
00867       if(r<0) {
00868         PRINTF(L_GEN_ERROR,"%s: write poll failed: %s",devName,strerror(errno));
00869         return -1;
00870         }
00871       else if(r==0) { // timeout
00872         PRINTF(L_CORE_SERIAL,"%s: write timeout",devName);
00873         return -2;
00874         }
00875       } while(r<1);
00876     r=write(fd,mem+n,delay>0?1:len-n);
00877     if(r<0 && errno!=EAGAIN) {
00878       PRINTF(L_GEN_ERROR,"%s: write failed: %s",devName,strerror(errno));
00879       return -1;
00880       }
00881     if(r>0) n+=r;
00882     if(delay>0) cCondWait::SleepMs(delay);
00883     }
00884   return n;
00885 }
00886 
00887 void cSmartCardSlotSerial::DeviceToggleReset(void)
00888 {
00889   int mask=0;
00890   if(ioctl(fd,TIOCMGET,&mask)<0) { LOG_ERROR; return; }
00891   if(mask&TIOCM_RTS) { mask&=~TIOCM_RTS; PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now off",devName); }
00892   else               { mask|= TIOCM_RTS; PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now on",devName); }
00893   CHECK(ioctl(fd,TIOCMSET,&mask));
00894   Flush();
00895 }
00896 
00897 bool cSmartCardSlotSerial::DevicePTS(void)
00898 {
00899   int baud=(int)((float)clock*atr.D/atr.F);
00900   PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",slotnum,baud);
00901 
00902   if(atr.Tspec<0) {
00903     PRINTF(L_CORE_SC,"%d: negotiable mode",slotnum);
00904 #ifdef NO_PTS_PROTO
00905     PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",slotnum);
00906     return true;
00907 #else
00908     unsigned char req[4], conf[16];
00909     req[0]=0xFF;
00910     req[1]=0x10 | atr.T;
00911     req[2]=atr.TA1;
00912     req[3]=XorSum(req,3);
00913     LDUMP(L_CORE_SC,req,4,"%d: PTS request:",slotnum);
00914     if(DeviceWrite(req,4)!=4) {
00915       PRINTF(L_CORE_SC,"%d: PTS request, write failed",slotnum);
00916       return false;
00917       }
00918     if(DeviceRead(conf,4,100,100)!=4) {
00919       PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",slotnum);
00920       return false;
00921       }
00922     int n=DeviceRead(conf,-16,200,1000);
00923     if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",slotnum);
00924     if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) {
00925       PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",slotnum);
00926       return false;
00927       }
00928     if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) {
00929       PRINTF(L_CORE_SC,"%d: PTS not confirmed",slotnum);
00930       return false;
00931       }
00932 #endif // NO_PTS_PROTO
00933     }
00934   else
00935     PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",slotnum,atr.Tspec);
00936 
00937   int mode=DeviceCurrentMode();
00938   if(atr.N==255) mode|=SM_1SB;
00939   if(!DeviceSetMode(mode,baud)) {
00940     PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",slotnum,baud);
00941     return false;
00942     }
00943   return true;
00944 }
00945 
00946 bool cSmartCardSlotSerial::DeviceIsInserted(void)
00947 {
00948   int status=0;
00949   if(ioctl(fd,TIOCMGET,&status)<0) { LOG_ERROR; return false; }
00950   PRINTF(L_CORE_SERIAL,"%s: CAR is %sactive (lines:%s%s%s%s%s%s%s%s%s)",
00951      devName,(status&TIOCM_CAR)?"in":"",
00952      (status&TIOCM_LE)?" LE":"",  (status&TIOCM_DTR)?" DTR":"",
00953      (status&TIOCM_RTS)?" RTS":"",(status&TIOCM_ST)?" ST":"",
00954      (status&TIOCM_SR)?" SR":"",  (status&TIOCM_CTS)?" CTS":"",
00955      (status&TIOCM_CAR)?" CAR":"",(status&TIOCM_RNG)?" RNG":"",
00956      (status&TIOCM_DSR)?" DSR":"" );
00957   status^=statInv; // invert status for broken cardreaders
00958   return !(status & TIOCM_CAR);
00959 }
00960 
00961 // -- cSmartCardSlotSRPlus -----------------------------------------------------
00962 
00963 class cSmartCardSlotSRPlus : public cSmartCardSlotSerial {
00964 private:
00965   bool SRConfig(int F, float D, int fs, int N, int T, int inv);
00966 protected:
00967   virtual bool DeviceOpen(const char *cfg);
00968   virtual bool DeviceSetMode(int mode, int baud);
00969   virtual bool DevicePTS(void);
00970 public:
00971   cSmartCardSlotSRPlus(void);
00972   };
00973 
00974 static cSmartCardSlotLinkReg<cSmartCardSlotSRPlus> __scs_srplus("srplus");
00975 
00976 cSmartCardSlotSRPlus::cSmartCardSlotSRPlus(void)
00977 {
00978   localecho=false;
00979 }
00980 
00981 bool cSmartCardSlotSRPlus::DeviceOpen(const char *cfg)
00982 {
00983   if(sscanf(cfg,"%255[^:]:%d",devName,&clock)>=1) {
00984     if(clock<=0) clock=ISO_FREQ;
00985     PRINTF(L_CORE_SERIAL,"%s: open serial port",devName);
00986     fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY);
00987     if(fd>=0) {
00988       SetDtrRts();
00989       PRINTF(L_CORE_SERIAL,"%s: init done",devName);
00990       PRINTF(L_CORE_LOAD,"cardslot: added smartreader+ port %s as port %d (CLOCK %d)",
00991                 devName,slotnum,clock);
00992       return true;
00993       }
00994     else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));
00995     }
00996   else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'srplus'");
00997   return false;
00998 }
00999 
01000 bool cSmartCardSlotSRPlus::DeviceSetMode(int mode, int baud)
01001 {
01002   // Configure SmartReader+ with initial settings, ref ISO 7816 3.1.
01003   return baud==ISO_BAUD &&
01004          cSmartCardSlotSerial::DeviceSetMode(mode,ISO_BAUD) &&
01005          SRConfig(372,1.0,clock,0,0,0);
01006 }
01007 
01008 bool cSmartCardSlotSRPlus::DevicePTS(void)
01009 {
01010   // Configure SmartReader+ with work settings, ref ISO 7816 3.1.
01011   int inv=0;
01012   if(atr.convention==SM_INDIRECT) atr.convention=SM_INDIRECT_INV;
01013   if(atr.convention==SM_INDIRECT_INV) inv=1;
01014   // Use ISO work clock frequency unless a fixed frequency is specified.
01015   int cl=(clock==ISO_FREQ) ? atr.fs:clock;
01016   if(!SRConfig(atr.F,atr.D,cl,atr.N,atr.T,inv)) return false;
01017   PRINTF(L_CORE_SERIAL,"%s: SmartReader+ mode %.4f MHz",devName,cl/1000000.0);
01018   return true;
01019 }
01020 
01021 bool cSmartCardSlotSRPlus::SRConfig(int F, float D, int fs, int N, int T, int inv)
01022 {
01023   fs/=1000; // convert to kHz.
01024   PRINTF(L_CORE_SERIAL,"%s: SR+ options F=%d D=%f fs=%d N=%d T=%d inv=%d",devName,F,D,fs,N,T,inv);
01025   // Set SmartReader+ in CMD mode.
01026   struct termios term;
01027   if(tcgetattr(fd,&term)==-1) {
01028     PRINTF(L_GEN_ERROR,"%s: tcgetattr failed: %s",devName,strerror(errno));
01029     return false;
01030     }
01031   term.c_cflag&=~CSIZE;
01032   term.c_cflag|=CS5;
01033   if(tcsetattr(fd,TCSADRAIN,&term)==-1) {
01034     PRINTF(L_GEN_ERROR,"%s: tcsetattr failed: %s",devName,strerror(errno));
01035     return false;
01036     }
01037   // Write SmartReader+ configuration commands.
01038   unsigned char cmd[16];
01039   //XXX how is (int)D supposed to work for fractional values e.g. 0.125 ??
01040   cmd[0]=1; cmd[1]=F>>8; cmd[2]=F; cmd[3]=(int)D;
01041   if(DeviceWrite(cmd,4)!=4) return false;
01042   cmd[0]=2; cmd[1]=fs>>8; cmd[2]=fs;
01043   if(DeviceWrite(cmd,3)!=3) return false;
01044   cmd[0]=3; cmd[1]=N;
01045   if(DeviceWrite(cmd,2)!=2) return false;
01046   cmd[0]=4; cmd[1]=T;
01047   if(DeviceWrite(cmd,2)!=2) return false;
01048   cmd[0]=5; cmd[1]=inv;
01049   if(DeviceWrite(cmd,2)!=2) return false;
01050   // Send zero bits for 0.25 - 0.5 seconds.
01051   if(tcsendbreak(fd,0)==-1) {
01052     PRINTF(L_GEN_ERROR,"%s: tcsendbreak failed: %s",devName,strerror(errno));
01053     return false;
01054     }
01055   // We're entering SmartReader+ mode; speed up serial communication.
01056   // B3000000 is the highest setting that sticks.
01057   cfsetispeed(&term,B3000000);
01058   cfsetospeed(&term,B3000000);
01059   // Set SmartReader+ in DATA mode.
01060   term.c_cflag&=~CSIZE;
01061   term.c_cflag|=CS8;
01062   if(tcsetattr(fd,TCSADRAIN,&term)==-1) {
01063     PRINTF(L_GEN_ERROR,"%s: tcsetattr failed: %s",devName,strerror(errno));
01064     return false;
01065     }
01066   return true;
01067 }
01068 
01069 // -- cSmartCardSlotCCID -------------------------------------------------------
01070 
01071 #ifdef WITH_PCSC
01072 #include <winscard.h>
01073 
01074 class cSmartCardSlotCCID : public cSmartCardSlot {
01075 private:
01076   SCARDCONTEXT hContext;
01077   SCARDHANDLE hCard;
01078   DWORD dwProtocol;
01079   bool needsReOpen;
01080   //
01081   int Transmit(const unsigned char *request, int requestlen, unsigned char *answer, int answerlen);
01082 protected:
01083   virtual bool DeviceOpen(const char *cfg);
01084   virtual void DeviceClose(void);
01085   virtual bool DeviceSetMode(int mode, int baud);
01086   virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0) { return -1; }
01087   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0) { return -1; }
01088   virtual void DeviceToggleReset(void) {}
01089   virtual bool DevicePTS(void) { return true; }
01090   virtual bool DeviceIsInserted(void);
01091   //
01092   virtual bool Reset(void);
01093 public:
01094   cSmartCardSlotCCID(void);
01095   virtual bool IsoRead(const unsigned char *cmd, unsigned char *data);
01096   virtual bool IsoWrite(const unsigned char *cmd, const unsigned char *data);
01097   virtual int RawRead(unsigned char *data, int len, int to=0) { return -1; }
01098   virtual int RawWrite(const unsigned char *data, int len) { return -1; }
01099   };
01100 
01101 static cSmartCardSlotLinkReg<cSmartCardSlotCCID> __scs_ccid("ccid");
01102 
01103 cSmartCardSlotCCID::cSmartCardSlotCCID(void)
01104 {
01105   singlereset=true;
01106 }
01107 
01108 bool cSmartCardSlotCCID::DeviceOpen(const char *cfg)
01109 {
01110   if(!cfg || sscanf(cfg,"%255[^:]",devName)==1) {
01111     LONG rv=SCardEstablishContext(SCARD_SCOPE_SYSTEM,NULL,NULL,&hContext);
01112     PRINTF(L_CORE_SC,"%d: establish context: %lx:%s",slotnum,rv,pcsc_stringify_error(rv));
01113     if(rv==SCARD_S_SUCCESS) {
01114       DWORD protocol=SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1;
01115       rv=SCardConnect(hContext,devName,SCARD_SHARE_SHARED,protocol,&hCard,&dwProtocol);
01116       PRINTF(L_CORE_SC,"%d: connect '%s': %lx:%s",slotnum,devName,rv,pcsc_stringify_error(rv));
01117       if(rv==SCARD_S_SUCCESS) {
01118         needsReOpen=false;
01119         return true;
01120         }
01121       }
01122     }
01123   else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'ccid'");
01124   return false;
01125 }
01126 
01127 void cSmartCardSlotCCID::DeviceClose(void)
01128 {
01129   SCardDisconnect(hCard,SCARD_RESET_CARD);
01130   SCardReleaseContext(hContext);
01131 }
01132 
01133 bool cSmartCardSlotCCID::DeviceSetMode(int mode, int baud)
01134 {
01135   currMode=mode;
01136   return true;
01137 }
01138 
01139 bool cSmartCardSlotCCID::DeviceIsInserted(void)
01140 {
01141   BYTE pbAtr[MAX_ATR_SIZE];
01142   DWORD dwState, dwReaderLen=0, dwAtrLen=sizeof(pbAtr);
01143   LONG rv=SCardStatus(hCard,NULL,&dwReaderLen,&dwState,&dwProtocol,pbAtr,&dwAtrLen);
01144   if(rv==SCARD_S_SUCCESS && (dwState&SCARD_NEGOTIABLE)) return true;
01145   needsReOpen=true;
01146   return false;
01147 }
01148 
01149 bool cSmartCardSlotCCID::Reset(void)
01150 {
01151   PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",slotnum,serModes[DeviceCurrentMode()]);
01152   if(needsReOpen) { DeviceClose(); DeviceOpen(0); }
01153   DWORD protocol=dwProtocol;
01154   LONG rv=SCardReconnect(hCard,SCARD_SHARE_EXCLUSIVE,protocol,SCARD_RESET_CARD,&dwProtocol);
01155   if(rv!=SCARD_S_SUCCESS) {
01156     PRINTF(L_CORE_SC,"%d: reset failed: %lx:%sn",slotnum,rv,pcsc_stringify_error(rv));
01157     return false;
01158     }
01159   DWORD dwState, dwReaderLen=0, dwAtrLen=sizeof(atr.atr);
01160   rv=SCardStatus(hCard,NULL,&dwReaderLen,&dwState,&dwProtocol,atr.atr,&dwAtrLen);
01161   if(rv==SCARD_S_SUCCESS) {
01162     atr.atrLen=dwAtrLen;
01163     LDUMP(L_CORE_SC,atr.atr,dwAtrLen,"%d: <- ATR len=%ld:",slotnum,dwAtrLen);
01164     return true;
01165     }
01166   return false;
01167 }
01168 
01169 int cSmartCardSlotCCID::Transmit(const unsigned char *request, int requestlen, unsigned char *answer, int answerlen)
01170 {
01171   SCARD_IO_REQUEST pioRecvPci, pioSendPci;
01172   switch(dwProtocol) {
01173     case SCARD_PROTOCOL_T0:
01174     case SCARD_PROTOCOL_T1:
01175         pioSendPci.dwProtocol=dwProtocol;
01176         pioSendPci.cbPciLength=sizeof(pioSendPci);
01177         pioRecvPci.dwProtocol=dwProtocol;
01178         pioRecvPci.cbPciLength=sizeof(pioRecvPci);
01179         break;
01180     default:
01181         PRINTF(L_CORE_SC,"%d: protocol failure: %ld",slotnum,dwProtocol);
01182         return 0;
01183     }
01184   DWORD answlen=answerlen;
01185   DWORD rv=SCardTransmit(hCard,&pioSendPci,(LPCBYTE)request,(DWORD)requestlen,&pioRecvPci,(LPBYTE)answer,&answlen);
01186   if(rv!=SCARD_S_SUCCESS) {
01187      PRINTF(L_CORE_SC, "%d: transmit failed: %lx:%s\n",slotnum,rv,pcsc_stringify_error(rv));
01188      return -1;
01189      }
01190   return answlen;
01191 }
01192 
01193 bool cSmartCardSlotCCID::IsoRead(const unsigned char *cmd, unsigned char *data)
01194 {
01195   LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
01196   int restlen=Transmit(cmd,CMD_LEN,data,MAX_LEN);
01197   if(restlen<2) return Test(false);
01198   sb[0]=data[restlen-2];
01199   sb[1]=data[restlen-1];
01200   LDUMP(L_CORE_SC,sb,2,"%d: <- SB: ",slotnum);
01201   LDUMP(L_CORE_SC,data,restlen-2,"%d: <- DATA:",slotnum);
01202   return true;
01203 }
01204 
01205 bool cSmartCardSlotCCID::IsoWrite(const unsigned char *cmd, const unsigned char *data)
01206 {
01207   LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
01208   LDUMP(L_CORE_SC,data,cmd[LEN_IDX],"%d: -> DATA:",slotnum);
01209   unsigned char sendbuf[MAX_LEN+CMD_LEN], recvbuf[MAX_LEN];
01210   memcpy(sendbuf,cmd,CMD_LEN);
01211   memcpy(sendbuf+CMD_LEN,data,sendbuf[LEN_IDX]);
01212   int restlen=Transmit(sendbuf,CMD_LEN+sendbuf[LEN_IDX],recvbuf,MAX_LEN);
01213   if(restlen<2) return Test(false);
01214   sb[0]=recvbuf[restlen-2];
01215   sb[1]=recvbuf[restlen-1];
01216   LDUMP(L_CORE_SC,sb,2,"%d: <- SB: ",slotnum);
01217   return true;
01218 }
01219 
01220 #endif //WITH_PCSC
01221 
01222 // -- cSmartCardSlotEmuGeneric -------------------------------------------------
01223 
01224 #ifdef CARD_EMU
01225 
01226 #define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); }
01227 #define PUSHB(b)      { devBuff[buffCount++]=(b); }
01228 
01229 class cSmartCardSlotEmuGeneric : public cSmartCardSlot {
01230 protected:
01231   unsigned char devBuff[1024], nextSW[SB_LEN];
01232   int buffCount, dataLen, record;
01233   bool cmdStart, rts, dsr, flag;
01234   time_t remTime;
01235   //
01236   virtual bool DeviceOpen(const char *cfg);
01237   virtual void DeviceClose(void);
01238   virtual bool DeviceSetMode(int mode, int baud);
01239   virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0);
01240   virtual void DeviceToggleReset(void);
01241   virtual bool DevicePTS(void);
01242   virtual bool DeviceIsInserted(void);
01243   //
01244   virtual void EmuPushAtr(void)=0;
01245   void Flush(void);
01246   };
01247 
01248 bool cSmartCardSlotEmuGeneric::DeviceOpen(const char *cfg)
01249 {
01250   PRINTF(L_CORE_SERIAL,"%s: open serial port (emulator)",devName);
01251   PRINTF(L_CORE_SERIAL,"%s: init done",devName);
01252   buffCount=0; cmdStart=true; rts=false; flag=false;
01253   remTime=time(0); dsr=true;
01254   PRINTF(L_CORE_LOAD,"cardslot: added emulated port %s as port %d",devName,slotnum);
01255   return true;
01256 }
01257 
01258 void cSmartCardSlotEmuGeneric::DeviceClose(void)
01259 {
01260   PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);
01261 }
01262 
01263 void cSmartCardSlotEmuGeneric::Flush(void)
01264 {
01265   buffCount=0;
01266 }
01267 
01268 bool cSmartCardSlotEmuGeneric::DeviceSetMode(int mode, int baud)
01269 {
01270   currMode=mode;
01271   Flush();
01272   return true;
01273 }
01274 
01275 int cSmartCardSlotEmuGeneric::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout)
01276 {
01277   PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d",devName,len,timeout);
01278   if(len<0) {
01279     len=-len;
01280     if(buffCount<len) len=buffCount;
01281     }
01282   if(buffCount<len) return -2; // timeout
01283   memcpy(mem,devBuff,len);
01284   memmove(devBuff,devBuff+len,buffCount-len);
01285   buffCount-=len;
01286   return len;
01287 }
01288 
01289 void cSmartCardSlotEmuGeneric::DeviceToggleReset(void)
01290 {
01291   rts=!rts;
01292   if(!rts) {
01293     EmuPushAtr();
01294     PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now off",devName);
01295     }
01296   else { PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now on",devName); }
01297 }
01298 
01299 bool cSmartCardSlotEmuGeneric::DevicePTS(void)
01300 {
01301   return true;
01302 }
01303 
01304 bool cSmartCardSlotEmuGeneric::DeviceIsInserted(void)
01305 {
01306 #if 0
01307   if(time(0)>=remTime+30) {
01308     dsr=!dsr;
01309     remTime=time(0);
01310     }
01311 #endif
01312   return dsr;
01313 }
01314 
01315 // -- cSmartCardSlotEmuSeca ----------------------------------------------------
01316 
01317 class cSmartCardSlotEmuSeca : public cSmartCardSlotEmuGeneric {
01318 protected:
01319   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
01320   virtual void EmuPushAtr(void);
01321 public:
01322   cSmartCardSlotEmuSeca(void);
01323   };
01324 
01325 static cSmartCardSlotLinkReg<cSmartCardSlotEmuSeca> __scs_emuseca("emuseca");
01326 
01327 cSmartCardSlotEmuSeca::cSmartCardSlotEmuSeca(void)
01328 {
01329   strcpy(devName,"emuseca");
01330 }
01331 
01332 int cSmartCardSlotEmuSeca::DeviceWrite(const unsigned char *mem, int len, int delay)
01333 {
01334   PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
01335   Flush();
01336   cCondWait::SleepMs(300);
01337   PUSH(mem,len); // echo back
01338   //---
01339   if(cmdStart && len==CMD_LEN) { // new INS
01340     PUSHB(mem[INS_IDX]); // ACK byte
01341     cmdStart=false;
01342     dataLen=mem[LEN_IDX];
01343     unsigned char data[256];
01344     memset(data,0,sizeof(data));
01345     nextSW[0]=0x90; nextSW[1]=0x00;
01346     bool readcmd=false;
01347     switch(mem[0]*256+mem[1]) {
01348       case 0xc13a:
01349       case 0xc10e:
01350         readcmd=true;
01351         break;
01352       case 0xc116:
01353         data[3]=0x04;
01354         readcmd=true;
01355         break;
01356       case 0xc112:
01357         data[1]=0x64;
01358         data[22]=0x1d; data[23]=0x84;
01359         readcmd=true;
01360         break;
01361       case 0xc132:
01362         data[1]=0xFF; data[2]=0xFF; data[3]=0xFF; data[4]=0xFF;
01363         data[5]=0xFF; data[6]=0xFF; data[7]=0xFF; data[8]=0xFF;
01364         readcmd=true;
01365         break;
01366       }
01367     if(readcmd) {
01368       PUSH(data,dataLen);
01369       PUSH(nextSW,2);
01370       cmdStart=true;
01371       }
01372     }
01373   else {
01374     dataLen-=len;
01375     if(dataLen<=0 && !cmdStart) {
01376       PUSH(nextSW,2);
01377       cmdStart=true;
01378       }
01379     }
01380   //---
01381   return len;
01382 }
01383 
01384 void cSmartCardSlotEmuSeca::EmuPushAtr(void)
01385 {
01386   static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00,
01387                                        0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 };
01388   PUSH(atr,sizeof(atr));
01389 }
01390 
01391 // -- cSmartCardSlotEmuCrypto --------------------------------------------------
01392 
01393 class cSmartCardSlotEmuCrypto : public cSmartCardSlotEmuGeneric {
01394 protected:
01395   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
01396   virtual void EmuPushAtr(void);
01397 public:
01398   cSmartCardSlotEmuCrypto(void);
01399   };
01400 
01401 static cSmartCardSlotLinkReg<cSmartCardSlotEmuCrypto> __scs_emucrypto("emucrypto");
01402 
01403 cSmartCardSlotEmuCrypto::cSmartCardSlotEmuCrypto(void)
01404 {
01405   strcpy(devName,"emucrypto");
01406 }
01407 
01408 int cSmartCardSlotEmuCrypto::DeviceWrite(const unsigned char *mem, int len, int delay)
01409 {
01410   PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
01411   Flush();
01412   cCondWait::SleepMs(300);
01413   PUSH(mem,len); // echo back
01414   //---
01415   if(cmdStart && len==CMD_LEN) { // new INS
01416     cmdStart=false;
01417     dataLen=mem[LEN_IDX];
01418     unsigned char data[256];
01419     memset(data,0,sizeof(data));
01420     nextSW[0]=0x90; nextSW[1]=0x00;
01421     bool readcmd=false;
01422     switch(mem[0]*256+mem[1]) {
01423       case 0xa4a4:
01424         switch(mem[5]*256+mem[6]) {
01425           case 0x2f01:
01426           case 0x0f00:
01427           case 0x0f20:
01428           //case 0x0f40:
01429           case 0x0f60:
01430           case 0x0e11:
01431           case 0x1f88:
01432           case 0x1f8c: nextSW[0]=0x9f; nextSW[1]=0x11; break;
01433           default:     nextSW[0]=0x94; nextSW[1]=0x04; break;
01434           }
01435         break;
01436       case 0xa4a2:
01437         if(mem[2]==1) {
01438           if(mem[4]==3) {
01439             record=0x01;
01440             nextSW[0]=0x9f; nextSW[1]=0x26;
01441             }
01442           else {
01443             record=0x02;
01444             nextSW[0]=0x9f; nextSW[1]=0x42;
01445             }
01446           }
01447         else {
01448           record=mem[5];
01449           switch(record) {
01450             case 0x80: nextSW[0]=0x9f; nextSW[1]=0x07; break;
01451             case 0xD1: nextSW[0]=0x9f; nextSW[1]=0x04; break;
01452             case 0x9F: nextSW[0]=0x9f; nextSW[1]=0x03; break;
01453             case 0x9E: nextSW[0]=0x9f; nextSW[1]=0x42; break;
01454             case 0xD6:
01455             case 0xC0: nextSW[0]=0x9f; nextSW[1]=0x12; break;
01456             default:   nextSW[0]=0x94; nextSW[1]=0x02; break;
01457             }
01458           }
01459         break;
01460       case 0xa4b2:
01461         readcmd=true;
01462         switch(record) {
01463           case 0x01:
01464             if(mem[3]==1) {
01465               nextSW[0]=0x94; nextSW[1]=0x02;
01466               dataLen=0;
01467               }
01468             else {
01469               dataLen=0x26;
01470               static const unsigned char resp[0x26] = {
01471                 0x83,0x01,0x88,
01472                 0x8c,0x03,0x40,0x30,0x40,
01473                 0x8d,0x04,0x16,0xac,0x16,0xba,
01474                 0xd5,0x10,'D','u','m','m','y',0,0,0,0,0,0,0,0x12,0x34,0x56,0x67,
01475                 0x8f,0x01,0x55,
01476                 0x91,0x01,0x40
01477                 };
01478               memcpy(data,resp,sizeof(resp));
01479               }
01480             break;
01481           case 0x02:
01482             if(mem[3]==1) {
01483               nextSW[0]=0x94; nextSW[1]=0x02;
01484               dataLen=0;
01485               }
01486             else {
01487               dataLen=0x42;
01488               static const unsigned char resp[0x42] = {
01489                 0x83,0x01,0x88,
01490                 0x8c,0x03,0xA0,0x30,0x40,
01491                 0x8d,0x04,0x16,0xac,0x16,0xba,
01492                 0xd5,0x10,'D','u','m','m','y',0,0,0,0,0,0,0,0x12,0x34,0x56,0x67,
01493                 0x92,0x20,0x00 // ...
01494                 };
01495               memcpy(data,resp,sizeof(resp));
01496               }
01497             break;
01498           case 0x80:
01499             dataLen=0x07;
01500             data[0]=0x80; data[1]=0x05; data[2]=0x5c; data[3]=0x0c;
01501             data[4]=0x00; data[5]=0xec; data[6]=0x0a;
01502             break;
01503           case 0xD1:
01504             dataLen=0x04;
01505             data[0]=0xd1; data[1]=0x02; data[2]=0x0d; data[3]=0x22;
01506             break;
01507           case 0x9F:
01508             dataLen=0x03;
01509             data[0]=0x9f; data[1]=0x01; data[2]=0x88;
01510             break;
01511           case 0x9E:
01512             {
01513             dataLen=0x42;
01514             static const unsigned char resp[0x42] = {
01515               0x9E,0x40,
01516               0x28,0xFE, 
01517               };
01518             memcpy(data,resp,sizeof(resp));
01519             flag=true;
01520             break;
01521             }
01522           case 0xC0:
01523           case 0xD6:
01524             dataLen=0x12;
01525             data[0]=record;
01526             data[1]=0x10;
01527             memset(data+2,0,16);
01528             strcpy((char *)data+2,"Dum Issuer");
01529             break;
01530           }
01531         break;
01532       case 0xa4b8:
01533         readcmd=true;
01534         if(mem[2]==0) {
01535           dataLen=0x0C;
01536           memset(data,0,0x0c);
01537           data[0]=0xDF; data[1]=0x0A; data[4]=0xDF; data[5]=0x88;
01538           }
01539         else {
01540           dataLen=0;
01541           nextSW[0]=0x94; nextSW[1]=0x02;
01542           }
01543         break;
01544       case 0xa44c:
01545         nextSW[0]=0x9f; nextSW[1]=flag ? 0x42 : 0x1c;
01546         break;
01547       case 0xa4c0:
01548         readcmd=true;
01549         if(mem[4]==0x1c) {
01550           data[0]=0xdb; data[1]=0x10;
01551           memset(&data[2],0x45,16);
01552           data[18]=0xdf; data[19]=0x08; data[20]=0x50; data[23]=0x80;
01553           }
01554         else if(mem[4]==0x11) {
01555           memset(data,0,0x11);
01556           data[0]=0xdf; data[1]=0x0f; data[6]=0x3f; data[7]=0x6a;
01557           }
01558         else if(mem[4]==0x42) {
01559           static const unsigned char resp[0x42] = {
01560             0xdf,0x40,
01561             0x6d,0xbb,0x81, // ...
01562             };
01563           memcpy(data,resp,sizeof(resp));
01564           }
01565         break;
01566       }
01567     if(readcmd) {
01568       if(dataLen>0) {
01569         PUSHB(mem[INS_IDX]); // ACK byte
01570         PUSH(data,dataLen);
01571         }
01572       PUSH(nextSW,2);
01573       cmdStart=true;
01574       }
01575     else {
01576       PUSHB(mem[INS_IDX]); // ACK byte
01577       }
01578     }
01579   else {
01580     dataLen-=len;
01581     if(dataLen<=0 && !cmdStart) {
01582       PUSH(nextSW,2);
01583       cmdStart=true;
01584       }
01585     }
01586   //---
01587   return len;
01588 }
01589 
01590 void cSmartCardSlotEmuCrypto::EmuPushAtr(void)
01591 {
01592   static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00,
01593                                        0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 };
01594   PUSH(atr,sizeof(atr));
01595 }
01596 
01597 // -- cSmartCardSlotEmuIrdeto --------------------------------------------------
01598 
01599 class cSmartCardSlotEmuIrdeto : public cSmartCardSlotEmuGeneric {
01600 private:
01601   bool acs384;
01602 protected:
01603   virtual bool DeviceOpen(const char *cfg);
01604   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
01605   virtual void EmuPushAtr(void);
01606 public:
01607   cSmartCardSlotEmuIrdeto(void);
01608   };
01609 
01610 static cSmartCardSlotLinkReg<cSmartCardSlotEmuIrdeto> __scs_emuirdeto("emuirdeto");
01611 
01612 cSmartCardSlotEmuIrdeto::cSmartCardSlotEmuIrdeto(void)
01613 {
01614   strcpy(devName,"emuirdeto");
01615   acs384=false;
01616 }
01617 
01618 bool cSmartCardSlotEmuIrdeto::DeviceOpen(const char *cfg)
01619 {
01620   char acs[32];
01621   if(sscanf(cfg,"%31[^:]",acs)>=0) {
01622     if(!strcasecmp(acs,"acs384")) acs384=true;
01623     else if(!strcasecmp(acs,"acs383")) acs384=false;
01624     else {
01625       PRINTF(L_GEN_ERROR,"unknown ACS type");
01626       return false;
01627       }
01628     return cSmartCardSlotEmuGeneric::DeviceOpen(0);
01629     }
01630   else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",devName);
01631   return false;
01632 }
01633 
01634 int cSmartCardSlotEmuIrdeto::DeviceWrite(const unsigned char *mem, int len, int delay)
01635 {
01636   PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
01637   Flush();
01638   cCondWait::SleepMs(300);
01639   PUSH(mem,len); // echo back
01640   //---
01641   static const struct Resp {
01642     unsigned int cmd;
01643     int acs;
01644     unsigned char data[MAX_LEN];
01645     } resp[] = {
01646   { 0x01020203,0x384,
01647     {0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x84,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} },
01648   { 0x01020E02,0x384,
01649     {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} },
01650   { 0x01020E03,0x384,
01651     {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} },
01652   //
01653   { 0x01020203,0x383,
01654     {0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x83,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} },
01655   { 0x01020E02,0x383,
01656     {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} },
01657   { 0x01020E03,0x383,
01658     {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} },
01659   //
01660   { 0x01020003,0x0,
01661     {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} },
01662   { 0x01020103,0x0,
01663     {0x01,0x02,0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x17,0x00,0x00,0x01,0x00,0x17,0x00,0x00,0x01,0x04,0x00,0xF3,0x86,0x01,0x1A} },
01664   { 0x01021100,0x0,
01665     {0x01,0x02,0x58,0x00,0x11,0x00,0x00,0x00} },
01666   { 0x01020903,0x0,
01667     {0x01,0x02,0x55,0x00,0x09,0x03,0x00,0x00} },
01668   { 0x01020303,0x0,
01669     {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} },
01670   { 0x01020400,0x0,
01671     {0x01,0x02,0x54,0x00,0x04,0x00,0x00,0x00} },
01672   { 0x01050000,0x0,
01673     {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} },
01674   { 0x01010000,0x0,
01675     {0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xFF} },
01676   { 0x00000000,0x0, // don't delete this one
01677     {} }
01678   };
01679   const unsigned int cmd=(mem[0]<<24) + (mem[1]<<16) + (mem[2]<<8) + mem[3];
01680   const struct Resp *r=&resp[0];
01681   int acs=acs384 ? 0x384:0x383;
01682   while(1) {
01683     if(!r->cmd) {
01684       static const unsigned char fail[] = { 0x01,0x99,0x6f };
01685       PUSH(fail,sizeof(fail));
01686       break;
01687       }
01688     if(cmd==r->cmd && (!r->acs || r->acs==acs)) {
01689       const int len=r->data[7]+9-1;
01690       int cs=0x3f;
01691       for(int i=0 ; i<len ; i++) cs ^= r->data[i];
01692       PUSH(r->data,len);
01693       PUSHB(cs);
01694       break;
01695       }
01696     r++;
01697     }
01698   //---
01699   return len;
01700 }
01701 
01702 void cSmartCardSlotEmuIrdeto::EmuPushAtr(void)
01703 {
01704   static const unsigned char atr384[] = { 0x3B,0x9F,0x21,0x0E,
01705                                           0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d };
01706   static const unsigned char atr383[] = { 0x3B,0x9F,0x21,0x0E,
01707                                           0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 };
01708   if(acs384) PUSH(atr384,sizeof(atr384))
01709   else       PUSH(atr383,sizeof(atr383))
01710 }
01711 
01712 // -- cSmartCardSlotEmuNagra --------------------------------------------------
01713 
01714 class cSmartCardSlotEmuNagra : public cSmartCardSlotEmuGeneric {
01715 private:
01716   int toggle;
01717   int dt_count[16];
01718 protected:
01719   virtual void DeviceToggleReset(void);
01720   virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
01721   virtual void EmuPushAtr(void);
01722 public:
01723   cSmartCardSlotEmuNagra(void);
01724   };
01725 
01726 static cSmartCardSlotLinkReg<cSmartCardSlotEmuNagra> __scs_emunagra("emunagra");
01727 
01728 cSmartCardSlotEmuNagra::cSmartCardSlotEmuNagra(void)
01729 {
01730   strcpy(devName,"emunagra");
01731   toggle=0;
01732   memset(dt_count,0,sizeof(dt_count));
01733 }
01734 
01735 void cSmartCardSlotEmuNagra::DeviceToggleReset(void)
01736 {
01737   toggle=0;
01738   memset(dt_count,0,sizeof(dt_count));
01739   cSmartCardSlotEmuGeneric::DeviceToggleReset();
01740 }
01741 
01742 int cSmartCardSlotEmuNagra::DeviceWrite(const unsigned char *mem, int len, int delay)
01743 {
01744   PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
01745   Flush();
01746   cCondWait::SleepMs(100);
01747   PUSH(mem,len); // echo back
01748 
01749 // for this sample data:
01750 // BOXKEY:  BB99FF99BB997788
01751 // CARDMOD: 9A2AE686F360A8F63B679E05443FE32969DE606A8521A48003A9C904F53FCE34D6D62B3DA6A9EF090556559068B4B127213A6EC310E629AEA7286D6B46AB6519
01752 // -> SESSKEY: 9d2cd4cbc4b22bdf65c5c2d8506a2927
01753   static const struct Resp {
01754     int cmd, cc;
01755     unsigned int idata;
01756     unsigned char data[MAX_LEN];
01757     } resp[] = {
01758 /* status */  { 0xC0, 0,0x00000000, { 0x08,0xb0,0x04,0x00,0x13,0x00,0x20,0x90,0x00 } },
01759 /* datetim */ { 0xC8, 0,0x00000000, { 0x08,0xb8,0x04,0x00,0x00,0x00,0x00,0x90,0x00 } },
01760 /* card ID*/  { 0x12, 0,0x00000000, { 0x08,0x92,0x04,0x71,0x2A,0x3B,0x4C,0x90,0x00 } },
01761 /* IRDINFO */ { 0x22, 0,0x00000000, { 0x3b,0xA2,0x37,0x2A,0xFF,0x90,0x00,0x00,0x00,0x01,0x01,0xE9,0x01,0x01,0x01,0x12,0x3B,0x4F,0x5C,0x00,0x00,0x00,0x01,0x60,0x62,0x18,0x7A,0xA8,0xBE,0x10,0x5C,0x4F,0x3B,0x12,0x31,0x37,0x42,0x42,0x44,0x41,0x4C,0x44,0x50,0x34,0x35,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01762 /*  */        { 0x22,-1,0x00000080, { 0x3b,0xa2,0x37,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01763 /* DT01 */    { 0x22, 0,0x00000001, { 0x10,0xa2,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01764 /* DT04 */    { 0x22, 0,0x00000004, { 0x46,0xa2,0x42,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,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,0x00,0x00,0x90,0x00 } },
01765 /*  */        { 0x22,-1,0x00000084, { 0x46,0xa2,0x42,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,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,0x00,0x00,0x90,0x00 } },
01766 /* TIERS */   { 0x22, 0,0x00000005, { 0x59,0xa2,0x55,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01767 /*  */        { 0x22,-1,0x00000085, { 0x59,0xa2,0x55,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01768 /* DT06 */    { 0x22, 0,0x00000006, { 0x18,0xa2,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01769 /* CAMDATA */ { 0x22, 0,0x00000008, { 0x57,0xa2,0x53,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01770 /*  */        { 0x22,-1,0x00000088, { 0x57,0xa2,0x53,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00 } },
01771 /* CMD 26 */  { 0x26, 0,0x123b4f5c, { 0x44,0xa6,0x40,0xa1,0x36,0x96,0xdc,0x3d,0x43,0x98,0xc9,0xd3,0xda,0x73,0xca,0x67,0x37,0x75,0xf0,0x29,0x33,0x6c,0xf9,0x2c,0xb4,0xdd,0x0e,0x18,0xaf,0x9e,0x24,0xb8,0x56,0xa2,0x04,0xd9,0xbf,0x7b,0xf5,0xc2,0x64,0xc4,0x61,0xd0,0xce,0x33,0xa7,0x13,0x56,0x68,0xcd,0xb2,0xa5,0x54,0x04,0xce,0x79,0x72,0x1a,0xde,0x9a,0xc4,0x92,0x2c,0x49,0x4f,0x85,0x90,0x00 } },
01772 /* CMD 27 */  { 0x27, 0,0xfecd819a, { 0x04,0xa7,0x00,0x90,0x00 } },
01773 // don't remove this one
01774 /* END */     { 0xFF, 0,0x00000000, { 0x0 }} };
01775 
01776   unsigned char *rmem=AUTOMEM(len);
01777   memcpy(rmem,mem,len);
01778   Invert(rmem,len);
01779 
01780   unsigned char buff[MAX_LEN+16];
01781   int c=0;
01782   if(rmem[0]==0x21 && rmem[1]==0xc1) { // IFS
01783     buff[c++]=0x12;
01784     buff[c++]=0x00;
01785     buff[c++]=0x00;
01786     buff[c++]=0x00;
01787     }
01788   else {
01789     int cmd=rmem[8], ilen=rmem[9];
01790     unsigned int idata=0;
01791     if(ilen>0) {
01792       if(ilen>4) ilen=4;
01793       for(int i=0; i<ilen; i++) idata=(idata<<8) | rmem[10+i];
01794       }
01795     bool isdt = (cmd==0x22);
01796     for(const struct Resp *r=&resp[0]; 1 ;r++) {
01797       if(r->cmd==0xFF) {
01798         static const unsigned char fail[] = { 0x12,0x82,0x00,0x90 };
01799         c=sizeof(fail);
01800         memcpy(buff,fail,c);
01801         break;
01802         }
01803       if(cmd==r->cmd && idata==r->idata && (!isdt || dt_count[idata&0xF]==r->cc || r->cc<0)) {
01804         buff[c++]=0x12;
01805         buff[c++]=toggle; toggle^=0x40;
01806         unsigned int l=r->data[0]+1;
01807         memcpy(&buff[c],r->data,l);
01808         c+=l;
01809         if(isdt) {
01810           dt_count[idata&0xF]++;
01811           PRINTF(L_CORE_SERIAL,"%s: dt%02x count now %d",devName,idata&0xf,dt_count[idata&0xF]);
01812           }
01813         break;
01814         }
01815       }
01816     }
01817   if(c>0) {
01818     buff[c]=XorSum(buff,c); c++;
01819     Invert(buff,c);
01820     PUSH(buff,c);
01821     }
01822   return len;
01823 }
01824 
01825 void cSmartCardSlotEmuNagra::EmuPushAtr(void)
01826 {
01827   static const unsigned char atr[] = { 0x03,0x00,0x56,0xff,0x00,0x76,0x7e,0x71,0x80,0x1d,0xff,0xdd,0x8d,0x7d,0x35,0xf5,0xb3,0xd3,0x73,0xfb,0xdd,0x31,0xe9,0xed,0xf3,0x33,0x9f };
01828   PUSH(atr,sizeof(atr))
01829 }
01830 
01831 #endif // CARD_EMU
01832 
01833 // -- cInfoStr -----------------------------------------------------------------
01834 
01835 cInfoStr::cInfoStr(void)
01836 :cLineBuff(256)
01837 {
01838   current=0;
01839 }
01840 
01841 cInfoStr::~cInfoStr()
01842 {
01843   free(current);
01844 }
01845 
01846 bool cInfoStr::Get(char *buff, int len)
01847 {
01848   cMutexLock lock(&mutex);
01849   if(current && current[0]) {
01850     strn0cpy(buff,current,len);
01851     return true;
01852     }
01853   return false;
01854 }
01855 
01856 void cInfoStr::Begin(void)
01857 {
01858   Flush();
01859 }
01860 
01861 void cInfoStr::Finish()
01862 {
01863   cMutexLock lock(&mutex);
01864   free(current);
01865   current=Grab();
01866 }
01867 
01868 // -- cSmartCardData -----------------------------------------------------------
01869 
01870 cSmartCardData::cSmartCardData(int Ident)
01871 {
01872   ident=Ident;
01873 }
01874 
01875 // -- cSmartCardDatas ----------------------------------------------------------
01876 
01877 class cSmartCardDatas : public cStructList<cSmartCardData> {
01878 protected:
01879   virtual cStructItem *ParseLine(char *line);
01880 public:
01881   cSmartCardDatas(void);
01882   cSmartCardData *Find(cSmartCardData *param);
01883   };
01884 
01885 static cSmartCardDatas carddatas;
01886 
01887 cSmartCardDatas::cSmartCardDatas(void)
01888 :cStructList<cSmartCardData>("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE)
01889 {}
01890 
01891 cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param)
01892 {
01893   ListLock(false);
01894   cSmartCardData *cd;
01895   for(cd=First(); cd; cd=Next(cd))
01896     if(cd->Ident()==param->Ident() && cd->Matches(param)) break;
01897   ListUnlock();
01898   return cd;
01899 }
01900 
01901 cStructItem *cSmartCardDatas::ParseLine(char *line)
01902 {
01903   char *r=index(line,':');
01904   if(r)
01905     for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl))
01906       if(!strncasecmp(scl->Name(),line,r-line)) {
01907         cSmartCardData *scd=scl->CreateData();
01908         if(scd && scd->Parse(r+1)) return scd;
01909         delete scd;
01910         break;
01911         }
01912   return 0;
01913 }
01914 
01915 // -- cSmartCard ---------------------------------------------------------------
01916 
01917 cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg)
01918 {
01919   msg=Msg;
01920   slot=0; sb=0; atr=0; idStr[0]=0; cardUp=false;
01921   NewCardConfig(Cfg);
01922 }
01923 
01924 void cSmartCard::NewCardConfig(const struct CardConfig *Cfg)
01925 {
01926   cfg=Cfg;
01927   if(slot) slot->SetCardConfig(cfg);
01928 }
01929 
01930 bool cSmartCard::GetCardIdStr(char *str, int len)
01931 {
01932   strn0cpy(str,idStr,len);
01933   return (str[0]!=0);
01934 }
01935 
01936 bool cSmartCard::GetCardInfoStr(char *str, int len)
01937 {
01938   return infoStr.Get(str,len);
01939 }
01940 
01941 bool cSmartCard::Setup(cSmartCardSlot *Slot, int sermode, const struct Atr *Atr, unsigned char *Sb)
01942 {
01943   slot=Slot; atr=Atr; sb=Sb;
01944   slotnum=slot->SlotNum(); slot->SetCardConfig(cfg);
01945   cardUp=false;
01946   if(cfg->SerMode==sermode && Init()) cardUp=true;
01947   return cardUp;
01948 }
01949 
01950 int cSmartCard::SerRead(unsigned char *data, int len, int to)
01951 {
01952   if(atr->T==1 || atr->T==14) return slot->RawRead(data,len,to);
01953   PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T);
01954   return -1;
01955 }
01956 
01957 int cSmartCard::SerWrite(const unsigned char *data, int len)
01958 {
01959   if(atr->T==1 || atr->T==14) return slot->RawWrite(data,len);
01960   PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T);
01961   return -1;
01962 }
01963 
01964 bool cSmartCard::IsoRead(const unsigned char *cmd, unsigned char *data)
01965 {
01966   if(atr->T==0) return slot->IsoRead(cmd,data);
01967   PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",slotnum,atr->T);
01968   return false;
01969 }
01970 
01971 bool cSmartCard::IsoWrite(const unsigned char *cmd, const unsigned char *data)
01972 {
01973   if(atr->T==0) return slot->IsoWrite(cmd,data);
01974   PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",slotnum,atr->T);
01975   return false;
01976 }
01977 
01978 bool cSmartCard::Status(void)
01979 {
01980   const struct StatusMsg *m=msg;
01981   while(m->sb[0]!=0xFF) {
01982     if(sb[0]==m->sb[0] && (m->sb[1]==0xFF || sb[1]==m->sb[1])) {
01983       if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",slotnum,m->message,sb[0],sb[1]);
01984       return m->retval;
01985       }
01986     m++;
01987     }
01988   PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",slotnum,sb[0],sb[1]);
01989   return false;
01990 }
01991 
01992 int cSmartCard::CheckSctLen(const unsigned char *data, int off)
01993 {
01994   int l=SCT_LEN(data);
01995   if(l+off > MAX_LEN) {
01996     PRINTF(L_CORE_SC,"section too long %d > %d",l,MAX_LEN-off);
01997     l=-1;
01998     }
01999   return l;
02000 }
02001 
02002 void cSmartCard::CaidsChanged(void)
02003 {
02004   cGlobal::CaidsChanged();
02005 }
02006 
02007 // -- cSmartCardLink -----------------------------------------------------------
02008 
02009 cSmartCardLink::cSmartCardLink(const char *Name, int Id)
02010 {
02011   name=Name; id=Id;
02012   cSmartCards::Register(this);
02013 }
02014 
02015 // -- cSmartCards --------------------------------------------------------------
02016 
02017 cSmartCardLink *cSmartCards::first=0;
02018 
02019 cSmartCards smartcards;
02020 
02021 void cSmartCards::Register(cSmartCardLink *scl)
02022 {
02023   PRINTF(L_CORE_DYN,"registering %s smartcard (id %x)",scl->name,scl->id);
02024   scl->next=first;
02025   first=scl;
02026 }
02027 
02028 void cSmartCards::Shutdown(void)
02029 {
02030   carddatas.SafeClear();
02031   cardslots.SafeClear();
02032 }
02033 
02034 void cSmartCards::Disable(void)
02035 {
02036   carddatas.Disable();
02037   cardslots.Disable();
02038 }
02039 
02040 cSmartCardData *cSmartCards::FindCardData(cSmartCardData *param)
02041 {
02042   return carddatas.Find(param);
02043 }
02044 
02045 bool cSmartCards::HaveCard(int id)
02046 {
02047   bool res=false;
02048   for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
02049     if(slot->HaveCard(id)) { res=true; break; }
02050   cardslots.Release();
02051   return res;
02052 }
02053 
02054 cSmartCard *cSmartCards::LockCard(int id)
02055 {
02056   cSmartCard *sc=0;
02057   for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
02058     if((sc=slot->LockCard(id))) break;
02059   cardslots.Release();
02060   return sc;
02061 }
02062 
02063 void cSmartCards::ReleaseCard(cSmartCard *sc)
02064 {
02065   for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
02066     slot->ReleaseCard(sc);
02067   cardslots.Release();
02068 }
02069 
02070 bool cSmartCards::ListCard(int num, char *str, int len)
02071 {
02072   cSmartCardSlot *slot=cardslots.GetSlot(num);
02073   str[0]=0;
02074   bool res=false;
02075   if(slot) { slot->GetCardIdStr(str,len); res=true; }
02076   cardslots.Release();
02077   return res;
02078 }
02079 
02080 bool cSmartCards::CardInfo(int num, char *str, int len)
02081 {
02082   cSmartCardSlot *slot=cardslots.GetSlot(num);
02083   str[0]=0;
02084   bool res=false;
02085   if(slot) res=slot->GetCardInfoStr(str,len);
02086   cardslots.Release();
02087   return res;
02088 }
02089 
02090 void cSmartCards::CardReset(int num)
02091 {
02092   cSmartCardSlot *slot=cardslots.GetSlot(num);
02093   if(slot) slot->TriggerReset();
02094   cardslots.Release();
02095 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines