Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1374 lines
35 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
smbctl.c
Abstract:
This module implements the IoControl and FsControl SMBs.
Transact2 Ioctl
Nt Transaction Io Control
Author:
Manny Weiser (mannyw) 10-Oct-91
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
NTSTATUS
ProcessOs2Ioctl (
IN PWORK_CONTEXT WorkContext,
IN USHORT Category,
IN USHORT Function,
IN PVOID Parameters,
IN ULONG InputParameterCount,
IN PULONG OutputParameterCount,
IN PVOID Data,
IN ULONG InputDataCount,
IN PULONG OutputDataCount
);
VOID SRVFASTCALL
RestartNtIoctl (
IN PWORK_CONTEXT WorkContext
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SrvSmbIoctl )
#pragma alloc_text( PAGE, SrvSmbIoctlSecondary )
#pragma alloc_text( PAGE, SrvSmbNtIoctl )
#pragma alloc_text( PAGE, RestartNtIoctl )
#pragma alloc_text( PAGE, SrvSmbIoctl2 )
#pragma alloc_text( PAGE, SrvSmbFsctl )
#pragma alloc_text( PAGE, ProcessOs2Ioctl )
#endif
SMB_PROCESSOR_RETURN_TYPE
SrvSmbIoctl (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
Processes a primary Ioctl SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PREQ_IOCTL request;
PRESP_IOCTL response;
PSMB_HEADER header;
NTSTATUS status;
PSESSION session;
PTREE_CONNECT treeConnect;
PRFCB rfcb;
CLONG parameterOffset;
CLONG parameterCount; // For input on this buffer
CLONG maxParameterCount; // For output
CLONG totalParameterCount; // For input
CLONG parameterSize; // Max of input and output parameter counts
CLONG dataOffset;
CLONG responseDataOffset;
CLONG dataCount; // For input on this buffer
CLONG maxDataCount; // For output
CLONG totalDataCount; // For input
CLONG dataSize; // Max of input and output data counts
CLONG smbLength;
CLONG numberOfPaddings = 0;
PAGED_CODE( );
request = (PREQ_IOCTL)WorkContext->RequestParameters;
response = (PRESP_IOCTL)WorkContext->ResponseParameters;
//
// Since we do I/O from the SMB buffer, verify that the request and
// response buffers are one and the same.
//
ASSERT( (PVOID)request == (PVOID)response );
header = WorkContext->RequestHeader;
IF_SMB_DEBUG(TRANSACTION1) {
KdPrint(( "Ioctl (primary) request\n" ));
}
//
// !!! Verify ioctl subcommand early?
//
parameterOffset = SmbGetUshort( &request->ParameterOffset );
parameterCount = SmbGetUshort( &request->ParameterCount );
maxParameterCount = SmbGetUshort( &request->MaxParameterCount );
totalParameterCount = SmbGetUshort( &request->TotalParameterCount );
dataOffset = SmbGetUshort( &request->DataOffset );
dataCount = SmbGetUshort( &request->DataCount );
maxDataCount = SmbGetUshort( &request->MaxDataCount );
totalDataCount = SmbGetUshort( &request->TotalDataCount );
smbLength = WorkContext->RequestBuffer->DataLength;
dataSize = MAX( dataCount, maxDataCount );
parameterSize = MAX( parameterCount, maxParameterCount );
if ( parameterCount != 0 ) {
responseDataOffset = parameterOffset + parameterSize;
} else {
//
// Some ioctls requests have data offset of zero like
// category 0x53, function 0x60. If this is the case,
// calculate the dataoffset by hand.
//
if ( dataOffset != 0 ) {
responseDataOffset = dataOffset;
} else {
responseDataOffset = (CLONG) ((PUCHAR) response->Buffer -
(PUCHAR) WorkContext->ResponseHeader);
numberOfPaddings = ( responseDataOffset & 0x01 );
responseDataOffset = responseDataOffset + numberOfPaddings;
}
}
//
// Verify the size of the smb buffer:
//
// Even though we know that WordCount and ByteCount are valid, it's
// still possible that the offsets and lengths of the Parameter and
// Data bytes are invalid. So we check them now.
//
// We need room in the smb buffer for the response. Ensure that
// there is enough room.
//
// No ioctl secondary is expected. Ensure that all data and
// parameters have arrrived.
//
// Check that the response will fit in a single buffer.
//
if ( ( (parameterOffset + parameterCount) > smbLength ) ||
( (dataOffset + dataCount) > smbLength ) ||
( (responseDataOffset + dataCount) >
WorkContext->ResponseBuffer->BufferLength ) ||
( dataCount != totalDataCount ) ||
( parameterCount != totalParameterCount ) ||
( (parameterOffset > dataOffset) && (dataCount != 0) ) ) {
IF_DEBUG(SMB_ERRORS) {
KdPrint(( "SrvSmbTransaction: Invalid parameter or data "
"offset+count: pOff=%ld,pCnt=%ld;",
parameterOffset, parameterCount ));
KdPrint(( "dOff=%ld,dCnt=%ld;", dataOffset, dataCount ));
KdPrint(( "smbLen=%ld", smbLength ));
}
SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
return SmbStatusSendResponse;
}
//
// If a session block has not already been assigned to the current
// work context, verify the UID. If verified, the address of the
// session block corresponding to this user is stored in the
// WorkContext block and the session block is referenced.
//
// If a tree connect block has not already been assigned to the
// current work context, find the tree connect corresponding to the
// given TID.
//
status = SrvVerifyUidAndTid(
WorkContext,
&session,
&treeConnect,
ShareTypeWild
);
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(SMB_ERRORS) {
KdPrint(( "SrvSmbIoctl: Invalid UID or TID\n" ));
}
SrvSetSmbError( WorkContext, status );
return SmbStatusSendResponse;
}
//
// Verify the FID. If verified, the RFCB block is referenced
// and its addresses is stored in the WorkContext block, and the
// RFCB address is returned.
//
rfcb = SrvVerifyFid(
WorkContext,
request->Fid,
TRUE,
SrvRestartSmbReceived, // serialize with raw write
&status
);
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
if ( !NT_SUCCESS( status ) ) {
//
// Invalid file ID or write behind error. Reject the request.
//
IF_DEBUG(ERRORS) {
KdPrint((
"SrvSmbIoctl: Status %X on FID: 0x%lx\n",
request->Fid,
status
));
}
SrvSetSmbError( WorkContext, status );
return SmbStatusSendResponse;
}
//
// The work item has been queued because a raw write is in
// progress.
//
return SmbStatusInProgress;
}
//
// Make room in the SMB buffer for return parameters by copying data
//
if ( dataOffset != responseDataOffset && dataCount != 0) {
RtlMoveMemory(
(PCHAR)header + responseDataOffset,
(PCHAR)header + dataOffset,
dataCount
);
}
//
// Process the ioctl. The response will overwrite the request buffer.
//
status = ProcessOs2Ioctl(
WorkContext,
request->Category,
request->Function,
(PCHAR)WorkContext->RequestHeader + parameterOffset,
totalParameterCount,
&maxParameterCount,
(PCHAR)WorkContext->RequestHeader + responseDataOffset,
totalDataCount,
&maxDataCount
);
//
// Format and send the response, the parameter and data bytes are
// already in place.
//
if ( !NT_SUCCESS( status ) ) {
SrvSetSmbError( WorkContext, status );
return SmbStatusSendResponse;
}
response->WordCount = 8;
SmbPutUshort( &response->TotalParameterCount, (USHORT)maxParameterCount );
SmbPutUshort( &response->TotalDataCount, (USHORT)maxDataCount );
SmbPutUshort( &response->ParameterCount, (USHORT)maxParameterCount );
SmbPutUshort( &response->ParameterOffset, (USHORT)parameterOffset );
SmbPutUshort( &response->ParameterDisplacement, 0);
SmbPutUshort( &response->DataCount, (USHORT)maxDataCount );
SmbPutUshort( &response->DataOffset, (USHORT)responseDataOffset );
SmbPutUshort( &response->DataDisplacement, 0 );
SmbPutUshort(
&response->ByteCount,
(USHORT)(maxDataCount + numberOfPaddings)
);
WorkContext->ResponseParameters = NEXT_LOCATION(
response,
RESP_IOCTL,
maxDataCount + numberOfPaddings
);
return SmbStatusSendResponse;
} // SrvSmbIoctl
SMB_PROCESSOR_RETURN_TYPE
SrvSmbIoctlSecondary (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
Processes a secondary Ioctl SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PAGED_CODE( );
//
// This SMB is not supported.
//
SrvSetSmbError( WorkContext, STATUS_NOT_IMPLEMENTED );
return SmbStatusSendResponse;
}
SMB_TRANS_STATUS
SrvSmbNtIoctl (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
Processes a Nt Ioctl SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
--*/
{
NTSTATUS status;
ULONG functionCode;
USHORT fid;
BOOLEAN isFsctl;
PREQ_NT_IO_CONTROL request;
PTRANSACTION transaction;
PRFCB rfcb;
PMDL mdl = NULL;
PAGED_CODE( );
transaction = WorkContext->Parameters.Transaction;
request = (PREQ_NT_IO_CONTROL)transaction->InSetup;
functionCode = SmbGetAlignedUlong( &request->FunctionCode );
fid = SmbGetAlignedUshort( &request->Fid );
isFsctl = request->IsFsctl;
//
// Verify the FID. If verified, the RFCB block is referenced
// and its addresses is stored in the WorkContext block, and the
// RFCB address is returned.
//
rfcb = SrvVerifyFid(
WorkContext,
fid,
TRUE,
SrvRestartExecuteTransaction, // serialize with raw write
&status
);
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
if ( !NT_SUCCESS( status ) ) {
//
// Invalid file ID or write behind error. Reject the request.
//
IF_DEBUG(ERRORS) {
KdPrint((
"SrvSmbNtIoctl: Status %X on FID: 0x%lx\n",
status,
fid
));
}
SrvSetSmbError( WorkContext, status );
return SmbTransStatusErrorWithoutData;
}
//
// The work item has been queued because a raw write is in
// progress.
//
return SmbTransStatusInProgress;
}
CHECK_FUNCTION_ACCESS(
rfcb->GrantedAccess,
(UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
0,
functionCode,
&status
);
if ( !NT_SUCCESS( status ) ) {
SrvStatistics.GrantedAccessErrors++;
SrvSetSmbError( WorkContext, status );
return SmbTransStatusErrorWithoutData;
}
//
// Since we are doing ioctls to this file, it doesn't seem like it's
// a "normal" file. We had better not cache its handle after the close.
// Specifically, remote setting of the file's compression state is
// not reflected to the directory entry until the file is closed. And
// setting a file's compression state is done with an ioctl
//
rfcb->IsCacheable = FALSE;
if ( (functionCode & 3) == METHOD_IN_DIRECT ||
(functionCode & 3) == METHOD_OUT_DIRECT ) {
//
// Need an mdl
//
mdl = IoAllocateMdl(
transaction->InData,
transaction->TotalDataCount,
FALSE,
FALSE,
NULL
);
if ( mdl == NULL ) {
SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
return SmbTransStatusErrorWithoutData;
}
//
// Build the mdl
//
MmProbeAndLockPages(
mdl,
KernelMode,
IoReadAccess
);
}
//
// Set the Restart Routine addresses in the work context block.
//
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
WorkContext->FspRestartRoutine = RestartNtIoctl;
//
// Build the IRP to start the I/O control.
// Pass this request to the filesystem.
//
SrvBuildIoControlRequest(
WorkContext->Irp,
rfcb->Lfcb->FileObject,
WorkContext,
(UCHAR)(isFsctl ? IRP_MJ_FILE_SYSTEM_CONTROL : IRP_MJ_DEVICE_CONTROL),
functionCode,
transaction->InData,
transaction->DataCount,
transaction->OutData,
transaction->MaxDataCount,
mdl,
NULL // Completion routine
);
(PVOID)IoCallDriver(
IoGetRelatedDeviceObject(rfcb->Lfcb->FileObject ),
WorkContext->Irp
);
//
// The call was successfully started, return InProgress to the caller
//
return SmbTransStatusInProgress;
} // SrvSmbNtIoctl
VOID SRVFASTCALL
RestartNtIoctl (
IN PWORK_CONTEXT WorkContext
)
/*++
Routine Description:
This function handles the completion of an NT Io control SMB.
Arguments:
WorkContext - A pointer to a WORK_CONTEXT block.
Return Value:
None.
--*/
{
NTSTATUS status;
ULONG length;
PTRANSACTION transaction;
PAGED_CODE( );
//
// Free the MDL if one was allocated.
//
if ( WorkContext->Irp->MdlAddress != NULL ) {
IoFreeMdl( WorkContext->Irp->MdlAddress );
}
//
// If the Io Control request failed, set an error status in the response
// header.
//
status = WorkContext->Irp->IoStatus.Status;
if ( NT_ERROR(status) ) {
IF_DEBUG(ERRORS) {
KdPrint(( "RestartNtIoctl: Io control failed: %X\n",
status ));
}
SrvSetSmbError( WorkContext, status );
SrvCompleteExecuteTransaction(
WorkContext,
SmbTransStatusErrorWithoutData
);
} else {
//
// Success. Prepare to generate and send the response.
//
transaction = WorkContext->Parameters.Transaction;
length = MIN( WorkContext->Irp->IoStatus.Information, transaction->MaxDataCount );
if ( transaction->MaxSetupCount > 0 ) {
transaction->SetupCount = 1;
SmbPutUshort( transaction->OutSetup, (USHORT)length );
}
transaction->ParameterCount = transaction->MaxParameterCount;
transaction->DataCount = length;
if (!NT_SUCCESS(status) ) {
IF_DEBUG(ERRORS) {
KdPrint(( "RestartNtIoctl: Io control failed: %lC\n",
status ));
}
SrvSetSmbError2( WorkContext, status, TRUE );
SrvCompleteExecuteTransaction(
WorkContext,
SmbTransStatusErrorWithData
);
} else {
SrvCompleteExecuteTransaction(
WorkContext,
SmbTransStatusSuccess);
}
}
return;
} // RestartNtIoctl
SMB_TRANS_STATUS
SrvSmbIoctl2 (
IN OUT PWORK_CONTEXT WorkContext
)
/*++
Routine Description:
Processes the Ioctl request. This request arrives in a Transaction2 SMB.
Arguments:
WorkContext - Supplies the address of a Work Context Block
describing the current request. See smbtypes.h for a more
complete description of the valid fields.
Return Value:
SMB_TRANS_STATUS - Indicates whether an error occurred, and, if so,
whether data should be returned to the client. See smbtypes.h
for a more complete description.
--*/
{
NTSTATUS status;
PTRANSACTION transaction;
PRFCB rfcb;
PAGED_CODE( );
transaction = WorkContext->Parameters.Transaction;
IF_SMB_DEBUG(TRANSACTION2) {
KdPrint(( "Ioctl2 entered; transaction 0x%lx\n",
transaction ));
}
//request = (PREQ_IOCTL2)transaction->InSetup;
//
// Verify the setup count.
//
if ( transaction->SetupCount != 4 * sizeof( USHORT ) ) {
SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
return SmbTransStatusErrorWithoutData;
}
//
// Verify the FID. If verified, the RFCB block is referenced
// and its addresses is stored in the WorkContext block, and the
// RFCB address is returned.
//
rfcb = SrvVerifyFid(
WorkContext,
transaction->InSetup[1],
TRUE,
SrvRestartExecuteTransaction, // serialize with raw write
&status
);
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
if ( !NT_SUCCESS( status ) ) {
//
// Invalid file ID or write behind error. Reject the request.
//
IF_DEBUG(ERRORS) {
KdPrint((
"SrvSmbIoctl2: Status %X on FID: 0x%lx\n",
transaction->InSetup[1],
status
));
}
SrvSetSmbError( WorkContext, status );
return SmbTransStatusErrorWithoutData;
}
//
// The work item has been queued because a raw write is in
// progress.
//
return SmbTransStatusInProgress;
}
transaction->Category = transaction->InSetup[2];
transaction->Function = transaction->InSetup[3];
//
// Perform the Ioctl
//
status = ProcessOs2Ioctl(
WorkContext,
transaction->InSetup[2],
transaction->InSetup[3],
transaction->InParameters,
transaction->ParameterCount,
&transaction->MaxParameterCount,
transaction->OutData,
transaction->DataCount,
&transaction->MaxDataCount
);
//
// If an error occurred, return an appropriate response.
//
if ( !NT_SUCCESS(status) ) {
SrvSetSmbError( WorkContext, status );
return SmbTransStatusErrorWithoutData;
}
transaction->SetupCount = 0;
transaction->ParameterCount = transaction->MaxParameterCount;
transaction->DataCount = transaction->MaxDataCount;
IF_DEBUG(TRACE2) KdPrint(( "SrvSmbIoctl2 complete.\n" ));
return SmbTransStatusSuccess;
} // SrvSmbIoctl2
SMB_TRANS_STATUS
SrvSmbFsctl (
IN OUT PWORK_CONTEXT WorkContext
)
{
PAGED_CODE( );
//
// The OS/2 redirector never sends a remote FS control request.
// If we get one, simply reply that we cannot handle it.
//
return SrvTransactionNotImplemented( WorkContext );
} // SrvSmbFsctl
//
// !!! MOVE THESE
//
#define SERIAL_DEVICE 0x1
#define PRINTER_DEVICE 0x5
#define GENERAL_DEVICE 0xB
#define SPOOLER_DEVICE 0x53
//
// Serial device functions supported
//
#define SET_BAUD_RATE 0x41
#define SET_LINE_CONTROL 0x42
#define SET_TRANSMIT_TIMEOUT 0x44
#define SET_BREAK_OFF 0x45
#define SET_MODEM_CONTROL 0x46
#define SET_BREAK_ON 0x4B
#define STOP_TRANSMIT 0x47
#define START_TRANSMIT 0x48
#define SET_DCB_INFORMATION 0x53
#define GET_BAUD_RATE 0x61
#define GET_LINE_CONTROL 0x62
#define GET_COMM_STATUS 0x64
#define GET_LINE_STATUS 0x65
#define GET_MODEM_OUTPUT 0x66
#define GET_MODEM_INPUT 0x67
#define GET_INQUEUE_COUNT 0x68
#define GET_OUTQUEUE_COUNT 0x69
#define GET_COMM_ERROR 0x6D
#define GET_COMM_EVENT 0x72
#define GET_DCB_INFORMATION 0x73
//
// Print device function supported.
//
// *** Note: The OS/2 server supports 2 additional Ioctl functions.
// ActivateFont (0x48) and QueryActiveFont (0x69). Since these
// were designed only to support IBM proplus printer from OS/2
// and we can't correctly support these function, we don't.
//
#define GET_PRINTER_ID 0x60
#define GET_PRINTER_STATUS 0x66
#define OS2_STATUS_PRINTER_HAPPY 0x90
typedef struct _SMB_IOCTL_LINECONTROL {
UCHAR DataBits;
UCHAR Parity;
UCHAR StopBits;
UCHAR TransBreak;
} SMB_IOCTL_LINE_CONTROL, *PSMB_IOCTL_LINE_CONTROL;
typedef struct _SMB_IOCTL_BAUD_RATE {
USHORT BaudRate;
} SMB_IOCTL_BAUD_RATE, *PSMB_IOCTL_BAUD_RATE;
typedef struct _SMB_IOCTL_DEVICE_CONTROL {
USHORT WriteTimeout;
USHORT ReadTimeout;
UCHAR ControlHandShake;
UCHAR FlowReplace;
UCHAR Timeout;
UCHAR ErrorReplacementChar;
UCHAR BreakReplacementChar;
UCHAR XonChar;
UCHAR XoffChar;
} SMB_IOCTL_DEVICE_CONTROL, *PSMB_IOCTL_DEVICE_CONTROL;
typedef struct _SMB_IOCTL_COMM_ERROR {
USHORT Error;
} SMB_IOCTL_COMM_ERROR, *PSMB_IOCTL_COMM_ERROR;
typedef struct _SMB_IOCTL_PRINTER_ID {
USHORT JobId;
UCHAR Buffer[1]; // server name and share name
} SMB_IOCTL_PRINTER_ID;
typedef SMB_IOCTL_PRINTER_ID SMB_UNALIGNED *PSMB_IOCTL_PRINTER_ID;
NTSTATUS
ProcessOs2Ioctl (
IN PWORK_CONTEXT WorkContext,
IN USHORT Category,
IN USHORT Function,
IN PVOID Parameters,
IN ULONG InputParameterCount,
IN OUT PULONG OutputParameterCount,
IN PVOID Data,
IN ULONG InputDataCount,
IN OUT PULONG OutputDataCount
)
/*++
Routine Description:
This function handles an OS/2 ioctl. It convert the Ioctl SMB data
into an NT ioctl call, makes the call, and format the returned data
into Ioctl SMB return data.
Arguments:
WorkContext
Category
Function
Parameters
InputParameterCount
OutputParameterCount
Data
InputDataCount
OutputDataCount
Return Value:
NTSTATUS
--*/
{
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
PCHAR buffer;
PLFCB lfcb = WorkContext->Rfcb->Lfcb;
HANDLE Handle = lfcb->FileHandle;
union NT_PARAMTERS {
SERIAL_BAUD_RATE BaudRate;
SERIAL_LINE_CONTROL LineControl;
SERIAL_TIMEOUTS Timeouts;
SERIAL_QUEUE_SIZE QueueSize;
ULONG WaitMask;
ULONG PurgeMask;
UCHAR ImmediateChar;
UCHAR Reserved[3];
SERIAL_CHARS Chars;
SERIAL_HANDFLOW Handflow;
SERIAL_STATUS SerialStatus;
} ntBuffer;
union SMB_PARAMETERS {
PSMB_IOCTL_BAUD_RATE BaudRate;
PSMB_IOCTL_LINE_CONTROL LineControl;
PSMB_IOCTL_DEVICE_CONTROL DeviceControl;
PSMB_IOCTL_COMM_ERROR CommError;
PSMB_IOCTL_PRINTER_ID PrinterId;
} smbParameters, smbData;
PAGED_CODE( );
InputParameterCount, InputDataCount;
switch ( Category ) {
case SERIAL_DEVICE:
switch ( Function ) {
case GET_BAUD_RATE:
status = NtDeviceIoControlFile(
Handle,
0,
NULL,
NULL,
&ioStatusBlock,
IOCTL_SERIAL_GET_BAUD_RATE,
NULL,
0,
&ntBuffer,
sizeof( SERIAL_BAUD_RATE )
);
//
// Convert the response to OS/2 format.
//
// !!! ULONG to USHORT conversion.
//
smbData.BaudRate = (PSMB_IOCTL_BAUD_RATE)Data;
if ( NT_SUCCESS( status ) ) {
smbData.BaudRate->BaudRate = (USHORT) ntBuffer.BaudRate.BaudRate;
*OutputParameterCount = 0;
*OutputDataCount = sizeof( SMB_IOCTL_BAUD_RATE );
}
break;
case SET_BAUD_RATE:
//
// Convert the request to NT format.
//
smbParameters.BaudRate =
(PSMB_IOCTL_BAUD_RATE)Parameters;
ntBuffer.BaudRate.BaudRate = smbParameters.BaudRate->BaudRate;
status = NtDeviceIoControlFile(
Handle,
0,
NULL,
NULL,
&ioStatusBlock,
IOCTL_SERIAL_SET_BAUD_RATE,
&ntBuffer,
sizeof( SERIAL_BAUD_RATE ),
NULL,
0
);
*OutputParameterCount = 0;
*OutputDataCount = 0;
break;
case SET_LINE_CONTROL:
//
// Convert the request to NT format.
//
smbParameters.LineControl =
(PSMB_IOCTL_LINE_CONTROL)Parameters;
ntBuffer.LineControl.StopBits = smbParameters.LineControl->StopBits;
ntBuffer.LineControl.Parity = smbParameters.LineControl->Parity;
ntBuffer.LineControl.WordLength = smbParameters.LineControl->DataBits;
// !!! What about TransmitBreak?
status = NtDeviceIoControlFile(
Handle,
0,
NULL,
NULL,
&ioStatusBlock,
IOCTL_SERIAL_SET_LINE_CONTROL,
&ntBuffer,
sizeof( SERIAL_LINE_CONTROL ),
NULL,
0
);
*OutputParameterCount = 0;
*OutputDataCount = 0;
break;
case GET_LINE_CONTROL:
smbData.LineControl = (PSMB_IOCTL_LINE_CONTROL)Data;
status = NtDeviceIoControlFile(
Handle,
0,
NULL,
NULL,
&ioStatusBlock,
IOCTL_SERIAL_GET_LINE_CONTROL,
NULL,
0,
&ntBuffer,
sizeof( SERIAL_LINE_CONTROL )
);
//
// Convert the response to OS/2 format.
//
if ( NT_SUCCESS( status ) ) {
smbData.LineControl->DataBits = ntBuffer.LineControl.WordLength;
smbData.LineControl->Parity = ntBuffer.LineControl.Parity;
smbData.LineControl->StopBits = ntBuffer.LineControl.StopBits;
smbData.LineControl->TransBreak = 0; // !!!
*OutputParameterCount = 0;
*OutputDataCount = sizeof( SMB_IOCTL_LINE_CONTROL );
}
break;
case GET_DCB_INFORMATION:
smbData.DeviceControl =
(PSMB_IOCTL_DEVICE_CONTROL)Data;
status = NtDeviceIoControlFile(
Handle,
0,
NULL,
NULL,
&ioStatusBlock,
IOCTL_SERIAL_GET_TIMEOUTS,
NULL,
0,
&ntBuffer,
sizeof( SERIAL_TIMEOUTS )
);
//
// Convert the response to OS/2 format.
//
// !!! Verify units are correct
if ( NT_SUCCESS( status ) ) {
smbData.DeviceControl->WriteTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout; // !!!
smbData.DeviceControl->ReadTimeout = (USHORT)ntBuffer.Timeouts.ReadIntervalTimeout;
} else {
break;
}
status = NtDeviceIoControlFile(
Handle,
0,
NULL,
NULL,
&ioStatusBlock,
IOCTL_SERIAL_GET_TIMEOUTS,
NULL,
0,
&ntBuffer,
sizeof( SERIAL_TIMEOUTS )
);
//
// Convert the response to OS/2 format.
//
if ( NT_SUCCESS( status ) ) {
smbData.DeviceControl->XonChar = ntBuffer.Chars.XonChar;
smbData.DeviceControl->XoffChar = ntBuffer.Chars.XoffChar;
smbData.DeviceControl->ErrorReplacementChar = ntBuffer.Chars.ErrorChar;
smbData.DeviceControl->BreakReplacementChar = ntBuffer.Chars.BreakChar;
} else {
break;
}
smbData.DeviceControl->ControlHandShake = 0; // !!!
smbData.DeviceControl->FlowReplace = 0; // !!!
smbData.DeviceControl->Timeout = 0; // !!!
*OutputParameterCount = 0;
*OutputDataCount = sizeof( SMB_IOCTL_DEVICE_CONTROL );
break;
case SET_DCB_INFORMATION:
//
// Lie. Pretend this succeeded.
//
status = STATUS_SUCCESS;
*OutputParameterCount = 0;
*OutputDataCount = 0;
break;
case GET_COMM_ERROR:
//
// Pretend that there is no comm error.
//
smbData.CommError = (PSMB_IOCTL_COMM_ERROR)Data;
status = STATUS_SUCCESS;
if ( NT_SUCCESS( status ) ) {
smbData.CommError->Error = 0;
*OutputParameterCount = 0;
*OutputDataCount = sizeof( SMB_IOCTL_COMM_ERROR );
}
break;
case SET_TRANSMIT_TIMEOUT:
case SET_BREAK_OFF:
case SET_MODEM_CONTROL:
case SET_BREAK_ON:
case STOP_TRANSMIT:
case START_TRANSMIT:
case GET_COMM_STATUS:
case GET_LINE_STATUS:
case GET_MODEM_OUTPUT:
case GET_MODEM_INPUT:
case GET_INQUEUE_COUNT:
case GET_OUTQUEUE_COUNT:
case GET_COMM_EVENT:
status = STATUS_NOT_IMPLEMENTED;
break;
default:
status = STATUS_INVALID_PARAMETER;
}
break;
case PRINTER_DEVICE:
IF_SMB_DEBUG( TRANSACTION2 ) {
KdPrint(( "ProcessOs2Ioctl: print IOCTL function %lx received.\n",
Function ));
}
switch ( Function ) {
case GET_PRINTER_STATUS:
*OutputParameterCount = 0;
*OutputDataCount = 0;
if ( *(PCHAR)Parameters != 0 ) {
status = STATUS_INVALID_PARAMETER;
} else {
//
// Always return STATUS_PRINTER_HAPPY
//
*(PCHAR)Data = (CHAR)OS2_STATUS_PRINTER_HAPPY;
*OutputParameterCount = 0;
*OutputDataCount = sizeof( CHAR );
status = STATUS_SUCCESS;
break;
}
default:
*OutputParameterCount = 0;
*OutputDataCount = 0;
status = STATUS_NOT_SUPPORTED;
}
status = STATUS_SUCCESS;
*OutputParameterCount = 0;
*OutputDataCount = 0;
break;
case SPOOLER_DEVICE:
IF_SMB_DEBUG( TRANSACTION2 ) {
KdPrint(( "ProcessOs2Ioctl: spool IOCTL function %lx received.\n",
Function ));
}
switch ( Function ) {
case GET_PRINTER_ID:
{
PUNICODE_STRING shareName = &WorkContext->TreeConnect->Share->ShareName;
OEM_STRING ansiShare;
smbData.PrinterId = (PSMB_IOCTL_PRINTER_ID) Data;
smbData.PrinterId->JobId = (USHORT)lfcb->JobId;
buffer = (PCHAR)smbData.PrinterId->Buffer;
if ( WorkContext->Connection->Endpoint->TransportAddress.Buffer != NULL ) {
RtlCopyMemory(
buffer,
WorkContext->Connection->Endpoint->TransportAddress.Buffer,
MIN(WorkContext->Connection->Endpoint->TransportAddress.Length+1,LM20_CNLEN)
);
} else {
*buffer = '\0';
}
buffer += LM20_CNLEN;
*buffer++ = '\0';
status = RtlUnicodeStringToOemString(
&ansiShare,
shareName,
TRUE
);
if ( NT_SUCCESS(status) ) {
if ( ansiShare.Length >= LM20_NNLEN ) {
RtlCopyMemory(
buffer,
ansiShare.Buffer,
LM20_NNLEN
);
} else {
RtlCopyMemory(
buffer,
ansiShare.Buffer,
ansiShare.Length + 1
);
}
RtlFreeAnsiString(&ansiShare);
} else {
*buffer = '\0';
}
status = STATUS_SUCCESS;
buffer += LM20_NNLEN;
*buffer++ = '\0';
*OutputParameterCount = 0;
//
// data length is equal to the job id +
// the computer name + the share name + 1
// I don't know what the last + 1 is for but OS/2
// sends it.
//
*OutputDataCount = sizeof(USHORT) + LM20_CNLEN + 1 +
LM20_NNLEN + 2;
}
break;
default:
*OutputParameterCount = 0;
*OutputDataCount = 0;
status = STATUS_NOT_SUPPORTED;
}
break;
case GENERAL_DEVICE:
status = STATUS_NOT_IMPLEMENTED;
break;
default:
// for OS/2 1.x compatibility
status = STATUS_SUCCESS;
*OutputParameterCount = 0;
*OutputDataCount = 0;
}
IF_SMB_DEBUG( TRANSACTION2 ) {
KdPrint( (
"Category %x, Function %x returns %lx\n",
Category,
Function,
status
));
}
return status;
} // ProcessOs2Ioctl