|
|
/*++
Copyright (c) 1997 - 1999 SCM Microsystems, Inc.
Module Name:
PscrCmd.c
Abstract:
Basic command functions for SCM PSCR smartcard reader
Author:
Andreas Straub
Environment:
Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and Pscr95Wrap.h macros, resp.
NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and PscrNTWrap.h macros, resp.
Revision History:
Andreas Straub 8/18/1997 1.00 Initial Version Andreas Straub 9/24/1997 1.02 delay for read/write removed
--*/
#if defined( SMCLIB_VXD )
#include <Pscr95.h>
#else // SMCLIB_VXD
#include <PscrNT.h>
#endif // SMCLIB_VXD
#include <PscrRdWr.h>
#include <PscrCmd.h>
NTSTATUS CmdResetInterface( PREADER_EXTENSION ReaderExtension ) /*++
CmdResetInterface:
Performs a reset of the reader interface (NOT of the PCMCIA controller) - flush available data - set RESET bit - perform a buffer size exchange between reader & host - enables interrupts for freeze events - disables default PTS
Arguments: ReaderExtension context of call
Return Value: STATUS_SUCCESS STATUS_IO_DEVICE_ERROR
--*/ {
NTSTATUS NTStatus = STATUS_SUCCESS; ULONG IOBytes; UCHAR Len, Tag, Cnt, InData[ TLV_BUFFER_SIZE ]; PPSCR_REGISTERS IOBase; UCHAR EnableInterrupts[] = { 0x28, 0x01, 0x01 };
IOBase = ReaderExtension->IOBase;
// discard any data
PscrFlushInterface( ReaderExtension );
// reset reader
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_RESET_BIT ); SysDelay( DELAY_WRITE_PSCR_REG ); WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT );
NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT );
// read & check vendor string
if( NT_SUCCESS( NTStatus )) {
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); SysDelay( DELAY_WRITE_PSCR_REG ); //
// get actual len from TLV list
//
READ_PORT_UCHAR( &IOBase->SizeMSReg ); READ_PORT_UCHAR( &IOBase->SizeLSReg );
Tag = READ_PORT_UCHAR( &IOBase->DataReg ); Len = READ_PORT_UCHAR( &IOBase->DataReg ); //
// avoid overwrite of buffer
//
if( Len > TLV_BUFFER_SIZE ) { Len = TLV_BUFFER_SIZE; } for ( Cnt = 0; Cnt < Len; Cnt++ ) { InData[ Cnt ] = READ_PORT_UCHAR( &IOBase->DataReg ); } WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); //
// check vendor string
//
if( SysCompareMemory( InData, PSCR_ID_STRING, sizeof( PSCR_ID_STRING ) )) { NTStatus = STATUS_IO_DEVICE_ERROR; } else { //
// vendor string was correct, check buffer size
//
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_READ_BIT ); NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT ); //
// reader ready to transfer interface buffer size
//
if( NT_SUCCESS( NTStatus )) { //
// set size read & host control
//
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_READ_BIT | PSCR_HOST_CONTROL_BIT );
SysDelay( DELAY_WRITE_PSCR_REG ); //
// read buffer length
//
Len = READ_PORT_UCHAR( &IOBase->SizeMSReg ); Len = READ_PORT_UCHAR( &IOBase->SizeLSReg ); for ( Cnt = 0; Cnt < Len; Cnt++ ) { InData[ Cnt ] = READ_PORT_UCHAR( &IOBase->DataReg ); } //
// transfer of interface buffer size okay
//
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); SysDelay( DELAY_WRITE_PSCR_REG ); //
// notify the reader about the supported buffer size
//
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); SysDelay( DELAY_WRITE_PSCR_REG );
WRITE_PORT_UCHAR( &IOBase->SizeMSReg, 0 ); WRITE_PORT_UCHAR( &IOBase->SizeLSReg, 2 ); //
// Write the same data buffer size as the one we just got.
//
WRITE_PORT_UCHAR( &IOBase->DataReg, InData[ 0 ] ); WRITE_PORT_UCHAR( &IOBase->DataReg, InData[ 1 ] ); //
// store the size to report to the lib
// The maximum buffer size of the reader is to betrieved with
// ((ULONG)InData[ 1 ] << 8) | InData[ 0 ]
//
ReaderExtension->MaxIFSD = 254;
//
// let the reader process the size write command
//
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_WRITE_BIT ); NTStatus = PscrWait( ReaderExtension, PSCR_FREE_BIT ); } } } //
// clean up any host control settings
//
WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); //
// enable interrupts
//
CmdSetInterfaceParameter( ReaderExtension, ReaderExtension->Device, EnableInterrupts, sizeof( EnableInterrupts ) );
return ( NTStatus ); }
NTSTATUS CmdReset( PREADER_EXTENSION ReaderExtension, UCHAR Device, BOOLEAN WarmReset, PUCHAR pATR, PULONG pATRLength ) /*++
CmdReset: performs a reset of the reader / ICC
Arguments: ReaderExtension context of call Device device requested ( ICC_1, ICC_2, PSCR ) WarmReset kind of ICC reset pATR ptr to ATR buffer, NULL if no ATR required pATRLength size of ATR buffer / length of ATR
Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_UNRECOGNIZED_MEDIA error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR IOData[ MAX_T1_BLOCK_SIZE ], P2; USHORT ICCStatus; ULONG IOBytes;
// ATR from the smartcard requestet? P2 = 1
P2 = 0; if(( pATR != NULL ) && ( pATRLength != NULL )) { if( *pATRLength > 0 ) P2 = 0x01; }
// build the RESET command.
IOData[ PSCR_NAD ] = NAD_TO_PSCR; IOData[ PSCR_PCB ] = PCB_DEFAULT; IOData[ PSCR_LEN ] = 0x05;
if( WarmReset == TRUE ) { IOData[ PSCR_INF+0 ] = CLA_WARM_RESET; IOData[ PSCR_INF+1 ] = INS_WARM_RESET; } else { IOData[ PSCR_INF+0 ] = CLA_RESET; IOData[ PSCR_INF+1 ] = INS_RESET; } IOData[ PSCR_INF+2 ] = Device; IOData[ PSCR_INF+3 ] = P2; IOData[ PSCR_INF+4 ] = 0x00;
// write command
NTStatus = PscrWrite( ReaderExtension, IOData, 8, &IOBytes );
if( NT_SUCCESS( NTStatus )) { // read data
IOBytes = 0; NTStatus = PscrRead( ReaderExtension, IOData, MAX_T1_BLOCK_SIZE, &IOBytes );
// error detection
if( NT_SUCCESS( NTStatus )) { //
// the location of the error code in the buffer
// is: ( data ) - STATUS_MSB - STATUS_LSB - EPILOGUE
//
ICCStatus = (( USHORT )IOData[ IOBytes-PSCR_EPILOGUE_LENGTH-2 ]) << 8; ICCStatus |= ( USHORT )IOData[ IOBytes-PSCR_EPILOGUE_LENGTH-1 ];
switch( ICCStatus ) { case PSCR_SW_SYNC_ATR_SUCCESS: case PSCR_SW_ASYNC_ATR_SUCCESS: break;
case PSCR_SW_NO_ICC: NTStatus = STATUS_NO_MEDIA; break;
case PSCR_SW_NO_PROTOCOL: case PSCR_SW_NO_ATR: case PSCR_SW_NO_ATR_OR_PROTOCOL: case PSCR_SW_NO_ATR_OR_PROTOCOL2: case PSCR_SW_ICC_NOT_ACTIVE: case PSCR_SW_NON_SUPPORTED_PROTOCOL: case PSCR_SW_PROTOCOL_ERROR: default: NTStatus = STATUS_UNRECOGNIZED_MEDIA; } //
// copy ATR if required
//
if( NT_SUCCESS( NTStatus )) { if( P2 == 0x01 ) { IOBytes -= PSCR_PROLOGUE_LENGTH + PSCR_EPILOGUE_LENGTH; if( IOBytes > *pATRLength ) { IOBytes = *pATRLength; } SysCopyMemory( pATR, &IOData[ PSCR_PROLOGUE_LENGTH ], IOBytes ); *pATRLength = IOBytes; } } } } return( NTStatus ); }
NTSTATUS CmdDeactivate( PREADER_EXTENSION ReaderExtension, UCHAR Device ) /*++
CmdDeactivate: Deactivates the requested device
Arguments: ReaderExtension context of call Device requested device
Return Value: STATUS_SUCCESS error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; ULONG IOBytes;
//
// build the DEACTIVATE command.
//
IOData[ PSCR_NAD ] = NAD_TO_PSCR; IOData[ PSCR_PCB ] = PCB_DEFAULT; IOData[ PSCR_LEN ] = 0x05;
IOData[ PSCR_INF+0 ] = CLA_DEACTIVATE; IOData[ PSCR_INF+1 ] = INS_DEACTIVATE; IOData[ PSCR_INF+2 ] = Device; IOData[ PSCR_INF+3 ] = 0x00; IOData[ PSCR_INF+4 ] = 0x00; //
// write command
//
NTStatus = PscrWrite( ReaderExtension, IOData, 8, &IOBytes );
if( NT_SUCCESS( NTStatus )) { //
// read data to trap communication errors
//
IOBytes = 0; NTStatus = PscrRead( ReaderExtension, IOData, MAX_T1_BLOCK_SIZE, &IOBytes ); } return( NTStatus ); }
NTSTATUS CmdReadBinary( PREADER_EXTENSION ReaderExtension, USHORT Offset, PUCHAR pBuffer, PULONG pBufferLength ) /*++
CmdReadBinary: read binary data from an PSCR data file
Arguments: ReaderExtension context of call Offset offset in file pBuffer ptr to data buffer pBufferLength length of buffer / number of bytes read
Return Value:
STATUS_SUCCESS STATUS_UNSUCCESSFUL error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; USHORT ICCStatus; ULONG IOBytes; //
// check parameters
//
if(( pBuffer == NULL ) || ( pBufferLength == NULL)) { NTStatus = STATUS_INVALID_PARAMETER; } else { //
// build the READ BINARY command
//
IOData[ PSCR_NAD] = NAD_TO_PSCR; IOData[ PSCR_PCB] = PCB_DEFAULT; IOData[ PSCR_LEN] = 0x05;
IOData[ PSCR_INF+0 ] = CLA_READ_BINARY; IOData[ PSCR_INF+1 ] = INS_READ_BINARY; IOData[ PSCR_INF+2 ] = HIBYTE( Offset ); IOData[ PSCR_INF+3 ] = LOBYTE( Offset ); IOData[ PSCR_INF+4 ] = 0x00; //
// write command
//
NTStatus = PscrWrite( ReaderExtension, IOData, 8, &IOBytes );
if( NT_SUCCESS( NTStatus )) { //
// read data
//
IOBytes = 0; NTStatus = PscrRead( ReaderExtension, IOData, MAX_T1_BLOCK_SIZE, &IOBytes );
if( NT_SUCCESS( NTStatus )) { //
// error check
//
ICCStatus = ((USHORT)IOData[ IOBytes-2-PSCR_EPILOGUE_LENGTH ]) << 8; ICCStatus |= (USHORT)IOData[ IOBytes-1-PSCR_EPILOGUE_LENGTH ];
switch( ICCStatus ) { case PSCR_SW_FILE_NO_ACCEPPTED_AUTH: case PSCR_SW_FILE_NO_ACCESS: case PSCR_SW_FILE_BAD_OFFSET: case PSCR_SW_END_OF_FILE_READ: NTStatus = STATUS_UNSUCCESSFUL; break; default: break; } //
// copy data
//
if( NT_SUCCESS( NTStatus )) { if( *pBufferLength < IOBytes-PSCR_PROLOGUE_LENGTH-PSCR_STATUS_LENGTH ) { NTStatus = STATUS_BUFFER_TOO_SMALL; } else { ( *pBufferLength ) = IOBytes-PSCR_PROLOGUE_LENGTH-PSCR_STATUS_LENGTH; SysCopyMemory( pBuffer, &IOData[ PSCR_PROLOGUE_LENGTH ], *pBufferLength ); } } } } } return( NTStatus ); }
NTSTATUS CmdSelectFile( PREADER_EXTENSION ReaderExtension, USHORT FileId ) /*++
CmdSelectFile: selects a file/directoy of the reader
Arguments: ReaderExtension context of call FileId ID of file
Return Value: STATUS_SUCCESS STATUS_UNSUCCESSFUL error values from PscrRead / PscrWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; USHORT ICCStatus; ULONG IOBytes;
//
// build the SELECT FILE command
//
IOData[ PSCR_NAD ] = NAD_TO_PSCR; IOData[ PSCR_PCB ] = PCB_DEFAULT; IOData[ PSCR_LEN ] = 0x07;
IOData[ PSCR_INF+0 ] = CLA_SELECT_FILE; IOData[ PSCR_INF+1 ] = INS_SELECT_FILE; IOData[ PSCR_INF+2 ] = 0x00; IOData[ PSCR_INF+3 ] = 0x00; IOData[ PSCR_INF+4 ] = 0x02; IOData[ PSCR_INF+5 ] = HIBYTE( FileId ); IOData[ PSCR_INF+6 ] = LOBYTE( FileId ); //
// write command
//
NTStatus = PscrWrite( ReaderExtension, IOData, 10, &IOBytes );
if( NT_SUCCESS( NTStatus )) { //
// get the response of the reader
//
IOBytes = 0; NTStatus = PscrRead( ReaderExtension, IOData, MAX_T1_BLOCK_SIZE, &IOBytes );
if( NT_SUCCESS( NTStatus )) { //
// check errors
//
ICCStatus = ((USHORT)IOData[ IOBytes-2-PSCR_EPILOGUE_LENGTH ]) << 8; ICCStatus |= (USHORT)IOData[ IOBytes-1-PSCR_EPILOGUE_LENGTH ];
if( ICCStatus == PSCR_SW_FILE_NOT_FOUND ) { NTStatus = STATUS_UNSUCCESSFUL; } } } return( NTStatus ); }
NTSTATUS CmdSetInterfaceParameter( PREADER_EXTENSION ReaderExtension, UCHAR Device, PUCHAR pTLVList, UCHAR TLVListLen ) /*++
CmdSetInterfaceParameter: Sets the interface pareameter of the ICC interface to the values specified in the TLV list
Arguments: ReaderExtension context of call Device device pTLVList ptr to list of tag-len-value's specified by caller TLVListLen length of list
Return Value: STATUS_SUCCESS STATUS_INVALID_PARAMETER STATUS_INVALID_DEVICE_STATE error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; USHORT ICCStatus; ULONG IOBytes;
//
// check parameter
//
if( pTLVList == NULL ) { NTStatus = STATUS_INVALID_PARAMETER; } else { //
// build the SET INTERFACE PARAMETER command
//
IOData[ PSCR_NAD ] = NAD_TO_PSCR; IOData[ PSCR_PCB ] = PCB_DEFAULT; IOData[ PSCR_LEN ] = 0x05 + TLVListLen;
IOData[ PSCR_INF+0 ] = CLA_SET_INTERFACE_PARAM; IOData[ PSCR_INF+1 ] = INS_SET_INTERFACE_PARAM; IOData[ PSCR_INF+2 ] = Device; IOData[ PSCR_INF+3 ] = 0x00; IOData[ PSCR_INF+4 ] = TLVListLen;
SysCopyMemory( &IOData[ PSCR_INF+5 ], pTLVList, TLVListLen ); //
// write command
//
NTStatus = PscrWrite( ReaderExtension, IOData, 8 + TLVListLen, &IOBytes );
if( NT_SUCCESS( NTStatus )) {
// do an dummy read to catch errors.
IOBytes = 0; NTStatus = PscrRead( ReaderExtension, IOData, MAX_T1_BLOCK_SIZE, &IOBytes );
if( NT_SUCCESS( NTStatus )) {
// check error
ICCStatus = ((USHORT)IOData[ IOBytes - 2 - PSCR_EPILOGUE_LENGTH ]) << 8; ICCStatus |= (USHORT)IOData[ IOBytes - 1 - PSCR_EPILOGUE_LENGTH ];
if( ICCStatus != 0x9000 ) { NTStatus = STATUS_INVALID_DEVICE_STATE; } } } } return( NTStatus ); }
NTSTATUS CmdReadStatusFile ( PREADER_EXTENSION ReaderExtension, UCHAR Device, PUCHAR pTLVList, PULONG pTLVListLen ) /*++
CmdReadStatusFile: read the status file of the requested device from the reader filesystem
Arguments: ReaderExtension context of call Device requested device pTLVList ptr to list (i.e. the status file) pTLVListLen length of buffer / returned list
Return Value: STATUS_SUCCESS STATUS_BUFFER_TOO_SMALL error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; ULONG IOBytes;
// select ICC status file if it's not the active file
if( ReaderExtension->StatusFileSelected == FALSE ) {
// select master file on reader
NTStatus = CmdSelectFile( ReaderExtension, FILE_MASTER );
// select ICC directory
if( NT_SUCCESS( NTStatus )) { if( Device != DEVICE_ICC1 ) { NTStatus = STATUS_UNSUCCESSFUL; } else { NTStatus = CmdSelectFile( ReaderExtension, FILE_ICC1_DIR );
// select status file
if( NT_SUCCESS( NTStatus )) { NTStatus = CmdSelectFile( ReaderExtension, FILE_ICC1_DIR_STATUS ); if( NT_SUCCESS( NTStatus )) { ReaderExtension->StatusFileSelected = TRUE; } } } } }
// read status file if successful selected
if( ReaderExtension->StatusFileSelected == TRUE ) { IOBytes = MAX_T1_BLOCK_SIZE; NTStatus = CmdReadBinary( ReaderExtension, 0, IOData, &IOBytes );
// copy data to user buffer
if( NT_SUCCESS( NTStatus )) { if(( pTLVList != NULL ) && ( IOBytes < *pTLVListLen )) { *pTLVListLen = IOBytes; SysCopyMemory( pTLVList, IOData, IOBytes ); } else { NTStatus = STATUS_BUFFER_TOO_SMALL; } } } return( NTStatus ); }
NTSTATUS CmdGetFirmwareRevision ( PREADER_EXTENSION ReaderExtension ) /*++
CmdGetFirmwareRevision: get the firmware revision of the reader. Ther firmware revision is found in the PSCR configuration file (ID 0x0020) in the master directory. The tag of the revision is 0x0F, and the value is coded as an ASCII string, p.E. "2.20"
Arguments: ReaderExtension context of call
Return Value: STATUS_SUCCESS error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR TLVList[ MAX_T1_BLOCK_SIZE ], Len; char Revision[ 0x10 ], UpdateKey[ 0x10 ]; ULONG IOBytes; //
// select master file on reader
//
NTStatus = CmdSelectFile( ReaderExtension, FILE_MASTER ); //
// select pscr configuration file
//
if( NT_SUCCESS( NTStatus )) { NTStatus = CmdSelectFile( ReaderExtension, FILE_PSCR_CONFIG ); //
// read confiuration file
//
if( NT_SUCCESS( NTStatus )) { IOBytes = MAX_T1_BLOCK_SIZE; NTStatus = CmdReadBinary( ReaderExtension, 0, TLVList, &IOBytes ); //
// get the value of revison
//
if( NT_SUCCESS( NTStatus )) { CmdGetTagValue( TAG_SOFTWARE_REV, TLVList, IOBytes, &Len, Revision ); //
// the coding is always X.YY (in ASCII), so we can get the numeric
// values hardcoded by taking the low nibbles of the char's.
//
ReaderExtension->FirmwareMajor = Revision[0] & 0x0F; ReaderExtension->FirmwareMinor = ( Revision[2] & 0x0F ) << 4; ReaderExtension->FirmwareMinor |= Revision[3] & 0x0F; //
// get value of update key
//
CmdGetTagValue( TAG_UPDATE_KEY, TLVList, IOBytes, &Len, UpdateKey );
ReaderExtension->UpdateKey = UpdateKey[0]; } } } ReaderExtension->StatusFileSelected = FALSE; return( NTStatus ); }
NTSTATUS CmdPscrCommand ( PREADER_EXTENSION ReaderExtension, PUCHAR pInData, ULONG InDataLen, PUCHAR pOutData, ULONG OutDataLen, PULONG pNBytes ) /*++
CmdPscrCommand: send a command transparent to the reader
Arguments: ReaderExtension context of call pInData, ptr to input buffer InDataLen, len of input buffer pOutData, ptr to output buffer OutDataLen, len of output buffer pNBytes number of bytes transferred
Return Value: STATUS_SUCCESS STATUS_INVALID_PARAMETER error values from PscrRead / PscrWrite
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR IOData[ MAX_T1_BLOCK_SIZE ] = { 0 }; ULONG IOBytes; //
// the function is used for generic ioctl's, so carful ALL
// parametes will be checked!
//
if( ( pInData == NULL ) || ( pOutData == NULL ) || ( pNBytes == NULL ) || (InDataLen == 0 ) || (OutDataLen == 0 ) ) { NTStatus = STATUS_INVALID_PARAMETER; } else { IOBytes = 0; NTStatus = PscrWriteDirect( ReaderExtension, pInData, InDataLen, &IOBytes );
if( NT_SUCCESS( NTStatus )) { //
// get result. ignore all reader errors
//
IOBytes = 0; NTStatus = PscrRead( ReaderExtension, IOData, MAX_T1_BLOCK_SIZE, &IOBytes ); //
// tranfer data
//
if( IOBytes > OutDataLen ) { NTStatus = STATUS_BUFFER_TOO_SMALL; } else { *pNBytes = IOBytes; SysCopyMemory( pOutData, IOData, IOBytes ); } } } return( NTStatus ); }
NTSTATUS CmdGetTagValue ( UCHAR Tag, PUCHAR pTLVList, ULONG TLVListLen, PUCHAR pTagLen, PVOID pTagVal ) /*++
CmdGetTagValue: scans a TLV list for the value of a user specified tag it is assumed, the caller knows the kind of the requested field, so only the ptr to the buffer will be checked
Arguments: Tag requested Tag pTLVList ptr to list TLVListLen length of list pTagLen ptr to length pTagVal ptr to value
Return Value: STATUS_SUCCESS STATUS_UNSUCCESSFUL STATUS_INVALID_PARAMETER
--*/ { NTSTATUS NTStatus = STATUS_SUCCESS; ULONG Idx; //
// step through the given list
//
if(( pTLVList != NULL ) && ( pTagVal != NULL ) && ( pTagLen != NULL )) { //
// look for requested tag
//
Idx = 0; while( Idx < TLVListLen ) { if( pTLVList[ Idx ] == Tag ) { //
// ASSUMED THE CALLER KNOWS KIND OF FIELD!!!
//
*pTagLen = pTLVList[ Idx + 1 ]; SysCopyMemory( pTagVal, &pTLVList[ Idx+2 ], pTLVList[ Idx+1 ] );
break; } Idx += pTLVList[ Idx+1 ] + 2; } if( Idx >= TLVListLen ) { NTStatus = STATUS_UNSUCCESSFUL; } } else { NTStatus = STATUS_INVALID_PARAMETER; } return( NTStatus ); }
// ------------------------------- END OF FILE -------------------------------
|