/** * @brief Transmission by T=1 Character Mode * @param portno Indicate which port to open (0:Port0; 1:Port1) * @param pBlockBuffer Command Data * @param pBlockSize The size of command data * @param AnswerSize Expected size of received data * @retval Slot Status Error Code */ unsigned char Ifd_XfrCharT1( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize, unsigned int AnswerSize ) { int32_t ErrorCode; uint8_t rbuf[MIN_BUFFER_SIZE]; uint32_t idx, rlen; S_SC_DEV_T *dev; dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); ErrorCode = CBRawTransmit( dev, pBlockBuffer, *pBlockSize, AnswerSize, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // received data for(idx=0; idx<rlen; idx++) { *pBlockBuffer = rbuf[idx]; pBlockBuffer++; } // length of received data *pBlockSize = rlen; return SLOT_NO_ERROR; }
NTSTATUS CBTransmit( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBTransmit: callback handler for SMCLIB RDF_TRANSMIT Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBTransmit: Enter\n" ) ); // dispatch on the selected protocol switch ( SmartcardExtension->CardCapabilities.Protocol.Selected ) { case SCARD_PROTOCOL_T0: NTStatus = CBT0Transmit( SmartcardExtension ); break; case SCARD_PROTOCOL_T1: NTStatus = CBT1Transmit( SmartcardExtension ); break; case SCARD_PROTOCOL_RAW: NTStatus = CBRawTransmit( SmartcardExtension ); break; default: NTStatus = STATUS_INVALID_DEVICE_REQUEST; break; } SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBTransmit: Exit (%lx)\n", NTStatus ) ); return( NTStatus ); }
/** * @brief Transmission by T=0 Extend APDU Mode * @param portno Indicate which port to open (0:Port0; 1:Port1) * @param pBlockBuffer Command Data * @param pBlockSize The size of command data * @retval Slot Status Error Code */ unsigned char Ifd_XfrExtendApduT0( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { int32_t ErrorCode, idx; uint8_t rbuf[MIN_BUFFER_SIZE]; uint32_t datalength, rlen; S_SC_DEV_T *dev; unsigned char getresponsebuf[5]; unsigned char envelopebuf[300]; // 255 bytes + 5 command data dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x01) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; while(datalength) { envelopebuf[0] = USB_ConfigDescriptor[49+18]; // CLA = bClassEnvelope field envelopebuf[1] = 0xC2; // 0xC2 = Envelope command envelopebuf[2] = 0x00; // 0x00 envelopebuf[3] = 0x00; // 0x00 if(datalength >= 0xFF) envelopebuf[4] = 0xFF; // APDU length > buffer length else envelopebuf[4] = datalength; // APDU length > buffer length if(datalength >= 0xFF) { for(idx=0; idx < 0xFF; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } else { for(idx=0; idx < datalength; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } if(datalength >= 0xFF) ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+0xFF, &rbuf[0], &rlen); else ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); if(datalength >= 0xFF) { pBlockBuffer+=0xFF; datalength-=0xFF; } else datalength-=datalength; } // length of received data *pBlockSize = 0; // Chain Parameter Setting g_ChainParameter = 0x10; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x02) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; envelopebuf[0] = USB_ConfigDescriptor[49+18]; // CLA = bClassEnvelope field envelopebuf[1] = 0xC2; // 0xC2 = Envelope command envelopebuf[2] = 0x00; // 0x00 envelopebuf[3] = 0x00; // 0x00 envelopebuf[4] = datalength; // last part of APDU command for(idx=0; idx < datalength; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+envelopebuf[4], &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // get response command getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 = Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = 0x00; // 0x00 ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // check if data bytes still available, max. size of buffer is 500 bytes //while(1) //{ if((rlen==2) && (rbuf[0]==0x61)) { getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 == Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = rbuf[1]; // Licc = how many data bytes still available if(getresponsebuf[4]==0xFF) // TODO: care this point. NOT sure how to handle this ErrorCode = CBRawTransmit( dev, &getresponsebuf[0], 0x5, 0xFF, &rbuf[0], &rlen); else { ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); printf("why available data is less than 0xff \n"); } if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); } //} // store received data pBlockBuffer = pBlockBuffer - 7; for(idx=0; idx<rlen; idx++) pBlockBuffer[idx] = rbuf[idx]; // length of received data *pBlockSize = getresponsebuf[4]; // Chain Parameter Setting g_ChainParameter = 0x01; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x03) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; while(datalength) { envelopebuf[0] = USB_ConfigDescriptor[49+18]; // CLA = bClassEnvelope field envelopebuf[1] = 0xC2; // 0xC2 = Envelope command envelopebuf[2] = 0x00; // 0x00 envelopebuf[3] = 0x00; // 0x00 if(datalength >= 0xFF) envelopebuf[4] = 0xFF; // APDU length > buffer length else envelopebuf[4] = datalength; // APDU length > buffer length if(datalength >= 0xFF) { for(idx=0; idx < 0xFF; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } else { for(idx=0; idx < datalength; idx++) envelopebuf[idx + 5] = pBlockBuffer[idx]; } if(datalength >= 0xFF) ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+0xFF, &rbuf[0], &rlen); else ErrorCode = CBT0Transmit( dev, &envelopebuf[0], 0x5+datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); if(datalength >= 0xFF) { pBlockBuffer+=0xFF; datalength-=0xFF; } else datalength-=datalength; } // length of received data *pBlockSize = 0; // Chain Parameter Setting g_ChainParameter = 0x10; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x10) { // get response command getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 = Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = 0x00; // 0x00 ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // check if data bytes still available, max. size of buffer is 500 bytes if((rlen==2) && (rbuf[0]==0x61)) { getresponsebuf[0] = USB_ConfigDescriptor[48+18]; // CLA = bClassGetResponse field getresponsebuf[1] = 0xC0; // 0xC0 == Get response command getresponsebuf[2] = 0x00; // 0x00 getresponsebuf[3] = 0x00; // 0x00 getresponsebuf[4] = rbuf[1]; // Licc = how many data bytes still available if(getresponsebuf[4]==0xFF) ErrorCode = CBRawTransmit( dev, &getresponsebuf[0], 0x5, 0xFF, &rbuf[0], &rlen); else ErrorCode = CBT0Transmit( dev, &getresponsebuf[0], 0x5, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); } // store received data for(idx=0; idx<rlen; idx++) pBlockBuffer[idx] = rbuf[idx]; // length of received data if(getresponsebuf[4]==0xFF) *pBlockSize = getresponsebuf[4]; else *pBlockSize = rlen; // Chain Parameter Setting if(getresponsebuf[4]==0xFF) g_ChainParameter = 0x03; else g_ChainParameter = 0x02; } return SLOT_NO_ERROR; }
/** * @brief Transmission by T=1 TPDU Mode * @param portno Indicate which port to open (0:Port0; 1:Port1) * @param pBlockBuffer Command Data * @param pBlockSize The size of command data * @retval Slot Status Error Code */ unsigned char Ifd_XfrTpduT1( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { int32_t ErrorCode, origBwt=0; uint8_t rbuf[MIN_BUFFER_SIZE]; uint32_t idx, XfrWaitingTime = 0, rlen; S_SC_DEV_T *dev; dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); // if not equal to zero, change BWT according to BWI if(UsbMessageBuffer[OFFSET_BBWI] != 0) { origBwt = dev->CardCapabilities.T1.BWT; dev->CardCapabilities.T1.BWT *= UsbMessageBuffer[OFFSET_BBWI]; // how to integrate into BWT?????? } // Sending procedure ErrorCode = CBRawTransmit( dev, pBlockBuffer, *pBlockSize, 0, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // Receiving procedure /* [EMV 2000] */ XfrWaitingTime = (dev->CardCapabilities.T1.BWT / dev->CardCapabilities.etu) + (BitRateAdjustment[dev->CardCapabilities.Dl].DNumerator * 4700) + 1; SMARTCARD_TimerCountSet(dev, SC_TIMER0, SC_TMR_MODE_DC_RELOAD_S_S, XfrWaitingTime); SMARTCARD_TimerStart(dev, SC_TIMER0); dev->errno = PROTOCOL_T1_OK; dev->rcv_buf = pBlockBuffer; dev->rcv_len = 3; // Prologue field length dev->rcv_cnt = 0; dev->rcv_pos = 0; dev->op_state = SC_OP_READ; SMARTCARD_WaitFirstReceivedData(dev, SC_TIMER2, SC_TMR_MODE_DC, XfrWaitingTime); while(dev->op_state == SC_OP_READ && !(dev->errno)) ; if(dev->errno < 0) return Ifd_SC2CCIDErrorCode(dev->errno); dev->rcv_len = dev->rcv_buf[2] + (dev->CardCapabilities.T1.EDC?2:1); dev->rcv_cnt = 0; dev->rcv_pos = 3; dev->op_state = SC_OP_READ; while(dev->op_state == SC_OP_READ && !(dev->errno)) ; if(dev->errno < 0) return Ifd_SC2CCIDErrorCode(dev->errno); SMARTCARD_TimerStop(dev, SC_TIMER0); // stop timer // restore the original BWT value if(UsbMessageBuffer[OFFSET_BBWI] != 0) dev->CardCapabilities.T1.BWT = origBwt; // received data for(idx=0; idx<(dev->rcv_buf[2]+3+(dev->CardCapabilities.T1.EDC?2:1)); idx++) { CCIDSCDEBUG("Received Data: Data[%d]=0x%02x \n", idx, dev->rcv_buf[idx]); *pBlockBuffer = dev->rcv_buf[idx]; pBlockBuffer++; } // length of received data *pBlockSize = dev->rcv_buf[2]+3+(dev->CardCapabilities.T1.EDC?2:1); return SLOT_NO_ERROR; }