|
|
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
ksacapi.c
Abstract:
Kernel mode SAC api
Author:
Brian Guarraci (briangu), 2001
Revision History:
--*/
#include "ksacapip.h"
#include <ksacapi.h>
#include <ntddsac.h>
//
// Machine Information table and routines.
//
#define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
\ RtlInitUnicodeString((UnicodeString),(UnicodeText)); \ \ InitializeObjectAttributes( \ (Obja), \ (UnicodeString), \ OBJ_CASE_INSENSITIVE, \ NULL, \ NULL \ )
//
// Memory management routine aliases
//
#define KSAC_API_ALLOCATE_MEMORY(_s)
#define KSAC_API_FREE_MEMORY(_p)
#define KSAC_API_ASSERT(c,s)\
ASSERT(c);\ if (!(c)) {\ return s;\ }
#define KSAC_VALIDATE_CHANNEL_HANDLE(_h)\
KSAC_API_ASSERT( \ _h->ChannelHandle->DriverHandle, \ STATUS_INVALID_PARAMETER_1 \ ); \ KSAC_API_ASSERT( \ _h->ChannelHandle->DriverHandle != INVALID_HANDLE_VALUE, \ STATUS_INVALID_PARAMETER_1 \ ); \ KSAC_API_ASSERT( \ _h->SacEventHandle != INVALID_HANDLE_VALUE, \ STATUS_INVALID_PARAMETER_1 \ ); \ KSAC_API_ASSERT( \ _h->SacEvent != NULL, \ STATUS_INVALID_PARAMETER_1 \ );
NTSTATUS KSacHandleOpen( OUT HANDLE* SacHandle, OUT HANDLE* SacEventHandle, OUT PKEVENT* SacEvent )
/*++
Routine Description:
This routine opens a handle to the SAC driver and creates and initializes an associated syncrhonization event.
Arguments:
SacHandle - the driver handle SacEventHandle - the event handle SacEvent - the sac event
Return Value:
Status --*/
{ NTSTATUS Status; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; KSAC_API_ASSERT(SacHandle == NULL, STATUS_INVALID_PARAMETER_1); KSAC_API_ASSERT(SacEventHandle == NULL, STATUS_INVALID_PARAMETER_2); KSAC_API_ASSERT(SacEvent == NULL, STATUS_INVALID_PARAMETER_3);
//
// Open the SAC driver
//
INIT_OBJA(&ObjAttr, &UnicodeString, L"\\Device\\SAC");
Status = ZwCreateFile( *SacHandle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &ObjAttr, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0 );
if (!NT_SUCCESS(Status)) { return Status; }
//
// Initialize the SAC Kernel event
//
RtlInitUnicodeString(&UnicodeString, L"\\SetupDDSacEvent");
*SacEvent = IoCreateSynchronizationEvent( &UnicodeString, SacEventHandle );
if (*SacEvent == NULL) { ZwClose(*SacHandle); return STATUS_UNSUCCESSFUL; }
return STATUS_SUCCESS; }
NTSTATUS KSacHandleClose( IN OUT HANDLE* SacHandle, IN OUT HANDLE* SacEventHandle, IN OUT PKEVENT* SacEvent )
/*++
Routine Description:
This routine closes a handle to the SAC driver and closes the associated syncrhonization event.
Arguments:
SacHandle - the driver handle SacEventHandle - the event handle SacEvent - the sac event
Return Value:
Status
--*/
{ KSAC_API_ASSERT(*SacHandle != NULL, STATUS_INVALID_PARAMETER_1); KSAC_API_ASSERT(*SacEventHandle != NULL, STATUS_INVALID_PARAMETER_2);
UNREFERENCED_PARAMETER(SacEvent);
ZwClose(*SacHandle); ZwClose(*SacEventHandle); //
// Null the handles
//
*SacEventHandle = NULL; *SacHandle = NULL;
return STATUS_SUCCESS; }
NTSTATUS KSacChannelOpen( OUT PKSAC_CHANNEL_HANDLE SacChannelHandle, IN PSAC_CHANNEL_OPEN_ATTRIBUTES SacChannelAttributes )
/*++
Routine Description:
This routine opens a SAC channel with the specified attributes.
Arguments:
SacChannelHandle - on success, contains the handle to the new channel SacChannelAttributes - the attributes of the new channel
Return Value:
Status --*/
{ NTSTATUS Status; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; ULONG OpenChannelCmdSize; PSAC_CMD_OPEN_CHANNEL OpenChannelCmd; SAC_RSP_OPEN_CHANNEL OpenChannelRsp; HANDLE DriverHandle; HANDLE SacEventHandle; PKEVENT SacEvent;
KSAC_API_ASSERT(SacChannelHandle != NULL, STATUS_INVALID_PARAMETER_1); KSAC_API_ASSERT(SacChannelAttributes != NULL, STATUS_INVALID_PARAMETER_2); //
// default: we didn't get a valid handle
//
RtlZeroMemory(SacChannelHandle, sizeof(KSAC_CHANNEL_HANDLE)); //
// Verify that if the user wants to use the CLOSE_EVENT, we received one to use
//
KSAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) && SacChannelAttributes->CloseEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) && !SacChannelAttributes->CloseEvent), STATUS_INVALID_PARAMETER_2 );
//
// Verify that if the user wants to use the HAS_NEW_DATA_EVENT, we received one to use
//
KSAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) && SacChannelAttributes->HasNewDataEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) && !SacChannelAttributes->HasNewDataEvent), STATUS_INVALID_PARAMETER_2 );
#if ENABLE_CHANNEL_LOCKING
//
// Verify that if the user wants to use the LOCK_EVENT, we received one to use
//
KSAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_LOCK_EVENT) && SacChannelAttributes->LockEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_LOCK_EVENT) && !SacChannelAttributes->LockEvent), STATUS_INVALID_PARAMETER_2 ); #endif
//
// Verify that if the user wants to use the REDRAW_EVENT, we received one to use
//
KSAC_API_ASSERT( ((SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT) && SacChannelAttributes->RedrawEvent) || (!(SacChannelAttributes->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT) && !SacChannelAttributes->RedrawEvent), STATUS_INVALID_PARAMETER_2 );
//
// If the channel type isn't cmd,
// then make sure they sent us a name.
//
if (SacChannelAttributes->Type != ChannelTypeCmd) {
KSAC_API_ASSERT(SacChannelAttributes->Name, STATUS_INVALID_PARAMETER_2);
} else {
//
// Make sure they didn't pass us a name or description.
//
KSAC_API_ASSERT(SacChannelAttributes->Name == NULL, STATUS_INVALID_PARAMETER_2); KSAC_API_ASSERT(SacChannelAttributes->Description == NULL, STATUS_INVALID_PARAMETER_2);
}
//
// create the Open Channel message structure
//
OpenChannelCmdSize = sizeof(SAC_CMD_OPEN_CHANNEL); OpenChannelCmd = (PSAC_CMD_OPEN_CHANNEL)KSAC_API_ALLOCATE_MEMORY(OpenChannelCmdSize); ASSERT(OpenChannelCmd); if (!OpenChannelCmd) { return STATUS_NO_MEMORY; }
RtlZeroMemory(OpenChannelCmd, OpenChannelCmdSize);
//
// default: we failed
//
Status = STATUS_UNSUCCESSFUL;
//
// Attempt to open the new channel
//
do {
//
// initialize the Open Channel message structure
//
OpenChannelCmd->Attributes = SacChannelAttributes;
//
// Get a handle to the SAC driver
//
Status = KSacHandleOpen( &DriverHandle, &SacEventHandle, &SacEvent );
if (!NT_SUCCESS(Status)) { break; }
//
// Send down an IOCTL for opening a channel
//
Status = ZwDeviceIoControlFile( DriverHandle, SacEventHandle, NULL, NULL, &IoStatusBlock, IOCTL_SAC_OPEN_CHANNEL, OpenChannelCmd, OpenChannelCmdSize, &OpenChannelRsp, sizeof(OpenChannelRsp) );
if (Status == STATUS_PENDING) {
LARGE_INTEGER TimeOut;
TimeOut.QuadPart = Int32x32To64((LONG)90000, -1000);
Status = KeWaitForSingleObject( SacEvent, Executive, KernelMode, FALSE, &TimeOut );
if (Status == STATUS_SUCCESS) { Status = IoStatusBlock.Status; }
}
if (!NT_SUCCESS(Status)) {
KSacClose( &DriverHandle, &SacEventHandle, &SacEvent );
break;
}
//
// the new channel was created, so pass back the handle to it
//
SacChannelHandle->ChannelHandle->DriverHandle = DriverHandle; SacChannelHandle->ChannelHandle->ChannelHandle = OpenChannelRsp.Handle; SacChannelHandle->SacEventHandle = SacEventHandle; SacChannelHandle->SacEvent = SacEvent;
} while ( FALSE ); //
// we are done with the cmd structure
//
FREE_POOL(OpenChannelCmd); return Status; }
NTSTATUS KSacChannelClose( IN OUT PKSAC_CHANNEL_HANDLE SacChannelHandle ) /*++
Routine Description:
Arguments:
None.
Return Value:
None.
--*/ { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; SAC_CMD_CLOSE_CHANNEL CloseChannelCmd; KSAC_VALIDATE_CHANNEL_HANDLE(SacChannelHandle);
//
// Get the channel handle
//
CloseChannelCmd.Handle.ChannelHandle = SacChannelHandle->ChannelHandle->ChannelHandle; //
// Send down an IOCTL for closing a channel
//
Status = ZwDeviceIoControlFile( SacChannelHandle->ChannelHandle->DriverHandle, SacChannelHandle->SacEventHandle, NULL, NULL, &IoStatusBlock, IOCTL_SAC_CLOSE_CHANNEL, &CloseChannelCmd, sizeof(CloseChannelCmd), NULL, 0 ); if (Status == STATUS_PENDING) { LARGE_INTEGER TimeOut; TimeOut.QuadPart = Int32x32To64((LONG)90000, -1000); Status = KeWaitForSingleObject( SacChannelHandle->SacEvent, Executive, KernelMode, FALSE, &TimeOut ); if (Status == STATUS_SUCCESS) { Status = IoStatusBlock.Status; } }
//
// Close the driver handle
//
KSacHandleClose( &SacChannelHandle->ChannelHandle->DriverHandle, &SacChannelHandle->SacEventHandle, &SacChannelHandle->SacEvent );
//
// Null the channel handle since it is no longer valid
//
RtlZeroMemory(SacChannelHandle, sizeof(KSAC_CHANNEL_HANDLE));
return Status; }
NTSTATUS KSacChannelWrite( IN PKSAC_CHANNEL_HANDLE SacChannelHandle, IN PCBYTE Buffer, IN ULONG BufferSize )
/*++
Routine Description:
Write the given buffer to the specified SAC Channel
Arguments:
SacChannelHandle - The channel to write the buffer to Buffer - data buffer BufferSize - size of the buffer
Return Value:
Status
--*/ { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; ULONG WriteChannelCmdSize; PSAC_CMD_WRITE_CHANNEL WriteChannelCmd; KSAC_VALIDATE_CHANNEL_HANDLE(SacChannelHandle); KSAC_API_ASSERT(Buffer, STATUS_INVALID_PARAMETER_2); //
// initialize the Write To Channel message structure
//
WriteChannelCmdSize = sizeof(SAC_CMD_WRITE_CHANNEL) + (BufferSize * sizeof(UCHAR)); WriteChannelCmd = (PSAC_CMD_WRITE_CHANNEL)KSAC_API_ALLOCATE_MEMORY(WriteChannelCmdSize); KSAC_API_ASSERT(WriteChannelCmd, FALSE);
//
// Zero the command structure
//
RtlZeroMemory(WriteChannelCmd, WriteChannelCmdSize);
//
// Set the length of the string to send
//
// Note: Size does not include the terminating NULL,
// becase we don't want to send that.
//
WriteChannelCmd->Size = BufferSize;
//
// Set the buffer to be written
//
WriteChannelCmd->Buffer = Buffer;
//
// Indicate which channel this command is for
//
WriteChannelCmd->Handle.ChannelHandle = SacChannelHandle->ChannelHandle->ChannelHandle;
//
// Send the string to the channel
//
Status = ZwDeviceIoControlFile( SacChannelHandle->ChannelHandle->DriverHandle, SacChannelHandle->SacEventHandle, NULL, NULL, &IoStatusBlock, IOCTL_SAC_WRITE_CHANNEL, WriteChannelCmd, WriteChannelCmdSize, NULL, 0 );
if (Status == STATUS_PENDING) {
LARGE_INTEGER TimeOut; TimeOut.QuadPart = Int32x32To64((LONG)90000, -1000);
Status = KeWaitForSingleObject( SacChannelHandle->SacEvent, Executive, KernelMode, FALSE, &TimeOut );
if (Status == STATUS_SUCCESS) { Status = IoStatusBlock.Status; }
}
return Status; }
NTSTATUS KSacChannelRawWrite( IN KSAC_CHANNEL_HANDLE SacChannelHandle, IN PCBYTE Buffer, IN ULONG BufferSize )
/*++
Routine Description:
Write the given buffer to the specified SAC Channel
Arguments:
SacChannelHandle - The channel to write the buffer to Buffer - data buffer BufferSize - size of the buffer
Return Value:
Status
--*/ { //
// relay the write to the actual write routine
//
return KSacChannelWrite( SacChannelHandle, Buffer, BufferSize );
}
NTSTATUS KSacChannelVTUTF8WriteString( IN KSAC_CHANNEL_HANDLE SacChannelHandle, IN PCWSTR String )
/*++
Routine Description:
This routine writes a null-terminated Unicode String to the specified Channel.
Arguments:
SacChannelHandle - The channel to write the buffer to String - A null-terminated Unicode string
Return Value:
Status
TRUE --> the buffer was sent
--*/ { BOOL Status; ULONG BufferSize;
//
// Treating the String as a data buffer, we calculate it's size
// not including the null termination
//
BufferSize = wcslen(String) * sizeof(WCHAR);
KSAC_API_ASSERT(BufferSize > 0, FALSE);
//
// Write the data to the channel
//
Status = SacChannelWrite( SacChannelHandle, (PCBYTE)String, BufferSize );
return Status;
}
NTSTATUS KSacChannelVTUTF8Write( IN KSAC_CHANNEL_HANDLE SacChannelHandle, IN PCWCHAR Buffer, IN ULONG BufferSize )
/*++
Routine Description:
This routines writes an array of WCHAR to the VTUTF8 channel specified.
Arguments:
SacChannelHandle - The channel to write the buffer to Buffer - data buffer BufferSize - size of the buffer
Note: Buffer is not null-terminated BufferSize should not count a null-termination. Return Value:
Status
--*/ { //
// relay the write to the actual write routine
//
return KSacChannelWrite( SacChannelHandle, (PCBYTE)Buffer, BufferSize ); }
NTSTATUS KSacChannelHasNewData( IN PKSAC_CHANNEL_HANDLE SacChannelHandle, OUT PBOOLEAN InputWaiting )
/*++
Routine Description:
This routine checks to see if there is any waiting input for the channel specified by the handle
Arguments:
SacChannelHandle - the channel to write the string to InputWaiting - the input buffer status Return Value:
Status
--*/
{ HEADLESS_RSP_POLL Response; NTSTATUS Status; SIZE_T Length; IO_STATUS_BLOCK IoStatusBlock; SAC_CMD_POLL_CHANNEL PollChannelCmd; SAC_RSP_POLL_CHANNEL PollChannelRsp;
KSAC_VALIDATE_KSAC_CHANNEL_HANDLE(SacChannelHandle); //
// Initialize the Poll command
//
RtlZeroMemory(&PollChannelCmd, sizeof(SAC_RSP_POLL_CHANNEL)); PollChannelCmd.Handle.ChannelHandle = SacChannelHandle->ChannelHandle->ChannelHandle; //
// Send down an IOCTL for polling a channel
//
Status = ZwDeviceIoControlFile( SacChannelHandle->ChannelHandle->DriverHandle, SacChannelHandle->SacEventHandle, NULL, NULL, &IoStatusBlock, IOCTL_SAC_POLL_CHANNEL, &PollChannelCmd, sizeof(PollChannelCmd), &PollChannelRsp, sizeof(PollChannelRsp) );
if (Status == STATUS_PENDING) {
LARGE_INTEGER TimeOut; TimeOut.QuadPart = Int32x32To64((LONG)90000, -1000);
Status = KeWaitForSingleObject( SacChannelHandle->SacEvent, Executive, KernelMode, FALSE, &TimeOut );
if (Status == STATUS_SUCCESS) { Status = IoStatusBlock.Status; }
}
//
// Return the status to the user
//
if (NT_SUCCESS(Status)) { *InputWaiting = PollChannelRsp.InputWaiting; } else { *InputWaiting = FALSE; } return Status; }
NTSTATUS KSacChannelRead( IN PKSAC_CHANNEL_HANDLE SacChannelHandle, IN PCBYTE Buffer, IN ULONG BufferSize, OUT PULONG ByteCount )
/*++
Routine Description:
This routine reads data from the channel specified.
Arguments:
SacChannelHandle - the channel to read from Buffer - destination buffer BufferSize - size of the destination buffer (bytes) ByteCount - the actual # of byte read Return Value:
Status
--*/
{ UCHAR Byte; BOOLEAN Success; TIME_FIELDS StartTime; TIME_FIELDS EndTime; HEADLESS_RSP_GET_BYTE Response; SIZE_T Length; NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; SAC_CMD_READ_CHANNEL ReadChannelCmd; ULONG ReadChannelRspSize; PSAC_RSP_READ_CHANNEL ReadChannelRsp;
KSAC_VALIDATE_KSAC_CHANNEL_HANDLE(SacChannelHandle); KSAC_API_ASSERT(Buffer, STATUS_INVALID_PARAMETER_2); KSAC_API_ASSERT(BufferSize > 0, STATUS_INVALID_PARAMETER_2); //
// Initialize the IOCTL command
//
ReadChannelCmd.Handle.ChannelHandle = SacChannelHandle->ChannelHandle->ChannelHandle; //
// Initialize the IOCTL response
//
ReadChannelRsp = (PSAC_RSP_READ_CHANNEL)Buffer;
//
// Send down an IOCTL for reading a channel
//
Status = ZwDeviceIoControlFile( SacChannelHandle->ChannelHandle->DriverHandle, SacChannelHandle->SacEventHandle, NULL, NULL, &IoStatusBlock, IOCTL_SAC_READ_CHANNEL, &ReadChannelCmd, sizeof(ReadChannelCmd), ReadChannelRsp, ReadChannelRspSize );
if (Status == STATUS_PENDING) {
LARGE_INTEGER TimeOut; TimeOut.QuadPart = Int32x32To64((LONG)90000, -1000);
Status = KeWaitForSingleObject( SacChannelHandle->SacEvent, Executive, KernelMode, FALSE, &TimeOut );
if (Status == STATUS_SUCCESS) { Status = IoStatusBlock.Status; }
}
return Status; }
NTSTATUS KSacChannelVTUTF8Read( IN SAC_CHANNEL_HANDLE SacChannelHandle, OUT PWSTR Buffer, IN ULONG BufferSize, OUT PULONG ByteCount )
/*++
Routine Description:
This routine reads data from the channel specified.
Arguments:
SacChannelHandle - the channel to read from Buffer - destination buffer BufferSize - size of the destination buffer (bytes) ByteCount - the actual # of byte read Note: the Buffer upon return is NOT null terminated Return Value:
Status
--*/
{
return KSacChannelRead( SacChannelHandle, (PBYTE)Buffer, BufferSize, ByteCount );
}
NTSTATUS KSacChannelRawRead( IN KSAC_CHANNEL_HANDLE SacChannelHandle, OUT PBYTE Buffer, IN ULONG BufferSize, OUT PULONG ByteCount )
/*++
Routine Description:
This routine reads data from the channel specified.
Arguments:
SacChannelHandle - the channel to read from Buffer - destination buffer BufferSize - size of the destination buffer (bytes) ByteCount - the actual # of byte read Return Value:
Status
--*/
{ return KSacChannelRead( SacChannelHandle, Buffer, BufferSize, ByteCount );
}
|