/*++ 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