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 ); }
NTSTATUS CBRawTransmit( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBRawTransmit: finishes the callback RDF_TRANSMIT for the RAW protocol Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR TLVList[ TLV_BUFFER_SIZE ], Val, Len; ULONG TLVListLen; PREADER_EXTENSION ReaderExtension; SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBRawTransmit: Enter\n" ) ); ReaderExtension = SmartcardExtension->ReaderExtension; // // read the status file of ICC1 from the reader // TLVListLen = TLV_BUFFER_SIZE; NTStatus = CmdReadStatusFile( ReaderExtension, ReaderExtension->Device, TLVList, &TLVListLen ); // // check the active protocol of the reader // if ( NT_SUCCESS( NTStatus )) { Len = sizeof(Val); NTStatus = CmdGetTagValue( TAG_ICC_PROTOCOLS, TLVList, TLVListLen, &Len, ( PVOID ) &Val ); // execute the active protocol if ( NT_SUCCESS( NTStatus )) { // translate the actual protocol to a value the lib can understand switch ( Val ) { case PSCR_PROTOCOL_T0: NTStatus = CBT0Transmit( SmartcardExtension ); break; case PSCR_PROTOCOL_T1: NTStatus = CBT1Transmit( SmartcardExtension ); break; default: NTStatus = STATUS_UNSUCCESSFUL; break; } } } SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBRawTransmit: Exit (%lx)\n", NTStatus ) ); return( NTStatus ); }
/** * @brief Transmission by T=1 Short 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_XfrShortApduT1( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { int32_t retransmit = 0; int32_t ErrorCode; uint8_t rbuf[MIN_BUFFER_SIZE], rsp_type; uint32_t idx, rlen; S_SC_DEV_T *dev; dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); if(portno == 0) { dev->rcv_buf = (uint8_t *)&g_Port0_RxBUF;//(uint8_t *)malloc(MAX_BUF_LEN * sizeof(uint8_t)); dev->snd_buf = (uint8_t *)&g_Port0_TxBUF; } else { dev->rcv_buf = (uint8_t *)&g_Port1_RxBUF;//(uint8_t *)malloc(MAX_BUF_LEN * sizeof(uint8_t)); dev->snd_buf = (uint8_t *)&g_Port1_TxBUF; } CCIDSCDEBUG("Ifd_XfrShortApduT1: header=%02x %02x %02x %02x, len=%d\n", pBlockBuffer[0], pBlockBuffer[1], pBlockBuffer[2], pBlockBuffer[3], *pBlockSize); /* IFS request only for EMV T=1 */ /* First block (S-block IFS request) transmits after ATR */ if(g_ifs_req_flag==1) { retransmit++; g_ifs_req_flag = 0; ErrorCode = SendSBlock( dev, T1_BLOCK_S_IFS_REQ, 0xFE); rsp_type = T1BlockGetType(dev->rcv_buf); if(rsp_type==T1_BLOCK_S) { /* check IFS RESPONSE */ if(dev->rcv_buf[1]!=T1_BLOCK_S_IFS_RES) ErrorCode = PROTOCOL_T1_ERROR; /* IFSC shall have a value in the range '10' to 'FE' && check NAD && response's inf data must be 0xFE */ if ( T1BlockGetLength(dev->rcv_buf)!=0x01 || T1BlockGetNAD(dev->rcv_buf)!=0x00 || dev->rcv_buf[3]!=0xFE) ErrorCode = PROTOCOL_T1_ERROR; } while( (ErrorCode!=SC_STATUS_SUCCESS || rsp_type!=T1_BLOCK_S) && retransmit!=3 ) { ErrorCode = SendSBlock( dev, T1_BLOCK_S_IFS_REQ, 0xFE); rsp_type = T1BlockGetType(dev->rcv_buf); if(rsp_type==T1_BLOCK_S) { /* check IFS RESPONSE */ if(dev->rcv_buf[1]!=T1_BLOCK_S_IFS_RES) ErrorCode = PROTOCOL_T1_ERROR; /* IFSC shall have a value in the range '10' to 'FE' && check NAD && response's inf data must be 0xFE */ if ( T1BlockGetLength(dev->rcv_buf)!=0x01 || T1BlockGetNAD(dev->rcv_buf)!=0x00 || dev->rcv_buf[3]!=0xFE) ErrorCode = PROTOCOL_T1_ERROR; } retransmit++; } if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); } //for(idx=0; idx<*pBlockSize; idx++) // skip checksum byte // CCIDSCDEBUG("Sending Data: Data[%d]=0x%02x \n", idx, pBlockBuffer[idx]); // Sending procedure ErrorCode = CBT1Transmit( dev, pBlockBuffer, *pBlockSize, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); CCIDSCDEBUG("Ifd_XfrShortApduT1: dwLength = %d, Data = ", rlen); // received data for(idx=0; idx<rlen; idx++) { //CCIDSCDEBUG("Received Data: Data[%d]=0x%02x \n", idx, rbuf[idx]); CCIDSCDEBUG("%02x", rbuf[idx]); *pBlockBuffer = rbuf[idx]; pBlockBuffer++; } CCIDSCDEBUG("\n"); // length of received data *pBlockSize = rlen; return SLOT_NO_ERROR; }
/** * @brief Transmission by T=1 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_XfrExtendApduT1( int32_t portno, unsigned char *pBlockBuffer, unsigned int *pBlockSize ) { int32_t ErrorCode; uint8_t rbuf[MIN_BUFFER_SIZE]; uint32_t idx, rlen; uint32_t datalength; S_SC_DEV_T *dev; dev = (S_SC_DEV_T *)((uint32_t)&sc_device[portno]); if(portno == 0) { dev->rcv_buf = (uint8_t *)&g_Port0_RxBUF;//(uint8_t *)malloc(MAX_BUF_LEN * sizeof(uint8_t)); dev->snd_buf = (uint8_t *)&g_Port0_TxBUF; } else { dev->rcv_buf = (uint8_t *)&g_Port1_RxBUF;//(uint8_t *)malloc(MAX_BUF_LEN * sizeof(uint8_t)); dev->snd_buf = (uint8_t *)&g_Port1_TxBUF; } if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x01) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; while(datalength) { if(datalength >= 0xFE) ErrorCode = CBT1Transmit( dev, pBlockBuffer, 0xFE, &rbuf[0], &rlen); else ErrorCode = CBT1Transmit( dev, pBlockBuffer, datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); if(datalength >= 0xFE) { pBlockBuffer+=0xFE; datalength-=0xFE; } 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; ErrorCode = CBT1Transmit( dev, pBlockBuffer, datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); // check if data bytes still available //datalength = rlen - 3 - (dev->CardCapabilities.T1.EDC?2:1); pBlockBuffer = pBlockBuffer -7; for(idx=0; idx<rlen; idx++) pBlockBuffer[idx] = rbuf[idx]; // length of received data *pBlockSize = rlen; // Chain Parameter Setting g_ChainParameter = 0x01; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x03) { datalength = (*pBlockSize) - 7; pBlockBuffer = pBlockBuffer + 7; while(datalength) { if(datalength >= 0xFE) ErrorCode = CBT1Transmit( dev, pBlockBuffer, 0xFE, &rbuf[0], &rlen); else ErrorCode = CBT1Transmit( dev, pBlockBuffer, datalength, &rbuf[0], &rlen); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); if(datalength >= 0xFE) { pBlockBuffer+=0xFE; datalength-=0xFE; } else datalength-=datalength; } // length of received data *pBlockSize = 0; // Chain Parameter Setting g_ChainParameter = 0x10; } else if( UsbMessageBuffer[OFFSET_WLEVELPARAMETER] == 0x10) { ErrorCode = SendRBlock( dev, 1, 0); if(ErrorCode != SC_STATUS_SUCCESS) return Ifd_SC2CCIDErrorCode(ErrorCode); datalength = dev->rcv_pos - 3 - (dev->CardCapabilities.T1.EDC?2:1); pBlockBuffer = pBlockBuffer -7; for(idx=0; idx<datalength; idx++) pBlockBuffer[idx] = dev->rcv_buf[3+idx]; // length of received data if(dev->rcv_pos==0xFE+3) *pBlockSize = 0xFE; else *pBlockSize = dev->rcv_pos - 3; // Chain Parameter Setting if(dev->rcv_pos==0xFE) g_ChainParameter = 0x03; else g_ChainParameter = 0x02; } return SLOT_NO_ERROR; }