📄 tlp3cb.c
字号:
PULONG serialIoControlCode = &SmartcardExtension->ReaderExtension->SerialIoControlCode;
ULONG bytesToSend, bytesToRead, currentByte = 0;
BOOLEAN restartWorkWaitingTime = FALSE;
NTSTATUS status;
PAGED_CODE();
SmartcardDebug(
DEBUG_TRACE,
("%s!TLP3TransmitT0: Enter\n",
DRIVER_NAME)
);
try {
// Let the lib build a T=0 packet
status = SmartcardT0Request(SmartcardExtension);
if (status != STATUS_SUCCESS)
leave;
//
// The number of bytes we expect from the card
// is Le + 2 status bytes
//
bytesToSend = *requestLength;
bytesToRead = SmartcardExtension->T0.Le + 2;
//
// Send the first 5 bytes to the card
//
*requestLength = 5;
do {
UCHAR procByte;
//
// According to ISO 7816 a procedure byte of
// 60 should be treated as a request for a one time wait.
// In this case we do not write anything to the card
//
if (restartWorkWaitingTime == FALSE) {
SmartcardDebug(
DEBUG_PROTOCOL,
("%s!TLP3TransmitT0: -> Sending %s (%ld bytes)\n",
DRIVER_NAME,
(currentByte == 0 ? "header" : "data"),
*requestLength)
);
//
// Write to the card
//
*serialIoControlCode = SMARTCARD_WRITE;
SmartcardExtension->SmartcardRequest.Buffer = &requestBuffer[currentByte];
status = TLP3SerialIo(SmartcardExtension);
if (status != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
("%s!TLP3TransmitT0: TLP3SerialIo(SMARTCARD_WRITE) returned %lx\n",
DRIVER_NAME,
status)
);
leave;
}
//
// The TLP3 echos all sent bytes. We read the echo
// back into our send buffer
//
*serialIoControlCode = SMARTCARD_READ;
*replyLength = *requestLength;
SmartcardExtension->SmartcardReply.Buffer = &requestBuffer[currentByte];
status = TLP3SerialIo(SmartcardExtension);
if (status != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
("%s!TLP3TransmitT0: TLP3SerialIo(SMARTCARD_READ) returned %lx\n",
DRIVER_NAME,
status)
);
leave;
}
currentByte += *requestLength;
bytesToSend -= *requestLength;
}
// Read the 'Procedure byte'.
SmartcardExtension->SmartcardReply.Buffer = &procByte;
*serialIoControlCode = SMARTCARD_READ;
*replyLength = 1;
status = TLP3SerialIo(SmartcardExtension);
if (status != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
("%s!TLP3TransmitT0: TLP3SerialIo(SMARTCARD_READ) returned %lx\n",
DRIVER_NAME,
status)
);
leave;
}
restartWorkWaitingTime = FALSE;
//
// Check the procedure byte.
// Please take a look at ISO 7816 Part 3 Section 8.2.2
//
if (procByte == requestBuffer[1] ||
procByte == requestBuffer[1] + 1) {
SmartcardDebug(
DEBUG_PROTOCOL,
("%s!TLP3TransmitT0: <- ACK (send all)\n",
DRIVER_NAME)
);
// All remaining data bytes can be sent at once
*requestLength = bytesToSend;
} else if (procByte == (UCHAR) ~requestBuffer[1] ||
procByte == (UCHAR) ~(requestBuffer[1] + 1)) {
SmartcardDebug(
DEBUG_PROTOCOL,
("%s!TLP3TransmitT0: <- ACK (send single)\n",
DRIVER_NAME)
);
// We can send only one byte
*requestLength = 1;
} else if (procByte == 0x60 ||
SmartcardExtension->CardCapabilities.InversConvention &&
procByte == 0xf9) {
//
// We have to reset the wait time and try again to read
//
ULONG TimeRes;
LARGE_INTEGER delayTime;
SmartcardDebug(
DEBUG_PROTOCOL,
("%s!TLP3TransmitT0: <- NULL (%ldms)\n",
DRIVER_NAME,
SmartcardExtension->CardCapabilities.T0.WT / 1000)
);
TimeRes = KeQueryTimeIncrement();
delayTime.HighPart = -1;
delayTime.LowPart =
(-1) *
TimeRes *
((SmartcardExtension->CardCapabilities.T0.WT * 10l / TimeRes) + 1);
KeDelayExecutionThread(
KernelMode,
FALSE,
&delayTime
);
//
// Set flag that we only should read the proc byte
// without writing data to the card
//
restartWorkWaitingTime = TRUE;
} else {
//
// The card returned a status byte.
// Status bytes are always two bytes long.
// Store this byte first and then read the next
//
replyBuffer[0] = procByte;
*serialIoControlCode = SMARTCARD_READ;
*replyLength = 1;
bytesToSend = 0;
bytesToRead = 0;
//
// Read in the second status byte
//
SmartcardExtension->SmartcardReply.Buffer =
&replyBuffer[1];
status = TLP3SerialIo(SmartcardExtension);
SmartcardExtension->SmartcardReply.BufferLength = 2;
SmartcardDebug(
(status == STATUS_SUCCESS ? DEBUG_PROTOCOL : DEBUG_ERROR),
("%s!TLP3TransmitT0: <- SW1=%02x SW2=%02x (%lx)\n",
DRIVER_NAME,
replyBuffer[0],
replyBuffer[1],
status)
);
}
} while(bytesToSend || restartWorkWaitingTime);
if (status != STATUS_SUCCESS)
leave;
if (bytesToRead != 0) {
*serialIoControlCode = SMARTCARD_READ;
*replyLength = bytesToRead;
SmartcardExtension->SmartcardReply.Buffer =
replyBuffer;
status = TLP3SerialIo(SmartcardExtension);
SmartcardDebug(
(status == STATUS_SUCCESS ? DEBUG_PROTOCOL : DEBUG_ERROR),
("%s!TLP3TransmitT0: <- Data %ld bytes, SW1=%02x SW2=%02x (%lx)\n",
DRIVER_NAME,
bytesToRead,
replyBuffer[bytesToRead - 2],
replyBuffer[bytesToRead - 1],
status)
);
}
}
finally {
// Restore pointers to their original location
SmartcardExtension->SmartcardRequest.Buffer =
requestBuffer;
SmartcardExtension->SmartcardReply.Buffer =
replyBuffer;
if (status == STATUS_TIMEOUT) {
// STATUS_TIMEOUT is not mapped to a Win32 error code
status = STATUS_IO_TIMEOUT;
}
if (status == STATUS_SUCCESS) {
status = SmartcardT0Reply(SmartcardExtension);
}
}
SmartcardDebug(
(status == STATUS_SUCCESS ? DEBUG_TRACE : DEBUG_ERROR),
("%s!TLP3TransmitT0: Exit(%lx)\n",
DRIVER_NAME,
status)
);
return status;
}
NTSTATUS
TLP3Transmit(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This function is called by the smart card library whenever a transmission
is required.
Arguments:
SmartcardExtension - Pointer to smart card data struct.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PAGED_CODE();
SmartcardDebug(
DEBUG_TRACE,
("%s!TLP3Transmit: Enter\n",
DRIVER_NAME)
);
_try {
do {
PUCHAR requestBuffer = SmartcardExtension->SmartcardRequest.Buffer;
PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength;
PULONG replyLength = &SmartcardExtension->SmartcardReply.BufferLength;
PULONG serialIoControlCode = &SmartcardExtension->ReaderExtension->SerialIoControlCode;
//
// Tell the lib function how many bytes I need for the prologue
//
*requestLength = 0;
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
case SCARD_PROTOCOL_RAW:
status = SmartcardRawRequest(SmartcardExtension);
break;
case SCARD_PROTOCOL_T0:
//
// T=0 requires a bit more work.
// So we do this in a seperate function.
//
status = TLP3TransmitT0(SmartcardExtension);
leave;
case SCARD_PROTOCOL_T1:
status = SmartcardT1Request(SmartcardExtension);
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
leave;
}
if (status != STATUS_SUCCESS) {
leave;
}
//
// Write the command to the card
//
*replyLength = 0;
*serialIoControlCode = SMARTCARD_WRITE;
status = TLP3SerialIo(SmartcardExtension);
if (status != STATUS_SUCCESS) {
leave;
}
//
// The Bull reader always echos the bytes sent, so read that echo back
//
*serialIoControlCode = SMARTCARD_READ;
*replyLength = *requestLength;
status = TLP3SerialIo(SmartcardExtension);
if (status != STATUS_SUCCESS) {
leave;
}
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
case SCARD_PROTOCOL_RAW:
status = SmartcardRawReply(SmartcardExtension);
break;
case SCARD_PROTOCOL_T1:
//
// Check if the card requested a waiting time extension
//
if (SmartcardExtension->T1.Wtx) {
LARGE_INTEGER waitTime;
waitTime.HighPart = -1;
waitTime.LowPart =
SmartcardExtension->T1.Wtx *
SmartcardExtension->CardCapabilities.T1.BWT *
(-10);
KeDelayExecutionThread(
KernelMode,
FALSE,
&waitTime
);
}
//
// Read NAD, PCB and LEN fields
//
*replyLength = 3;
status = TLP3SerialIo(SmartcardExtension);
//
// Check for timeout first. If the card did not reply
// we need to send a resend request
//
if (status != STATUS_TIMEOUT) {
if (status != STATUS_SUCCESS) {
leave;
}
//
// The third byte contains the length of the data in the packet
// and we additinally want to have the EDC bytes which
// is one for LRC and 2 for CRC
//
*replyLength =
replyBuffer[2] +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -