1953 lines
57 KiB
C
1953 lines
57 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
tdi.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which assists the process of writing an NT
|
||
TDI client.
|
||
|
||
Author:
|
||
|
||
David Beaver (dbeaver) 15 June 1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
|
||
#include <ntosp.h>
|
||
#include <zwapi.h>
|
||
#include <ndis.h>
|
||
#include <tdikrnl.h>
|
||
#include "tdipnp.h"
|
||
|
||
#if DBG
|
||
|
||
#include "tdidebug.h"
|
||
|
||
ULONG TdiDebug;
|
||
|
||
#define IF_TDIDBG(sts) \
|
||
if ((TdiDebug & sts) != 0)
|
||
|
||
#define TDI_DEBUG_NAMES 0x00000001
|
||
#define TDI_DEBUG_DISPATCH 0x00000002
|
||
#define TDI_DEBUG_MAP 0x00000004
|
||
|
||
#else
|
||
|
||
#define IF_TDIDBG(sts) \
|
||
if (0)
|
||
#endif
|
||
|
||
ULONG TdiInitializationCount;
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Temporary entry point needed to initialize the TDI wrapper driver.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object created by the system.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Note: This function isn't called but is needed to keep the
|
||
// linker happy.
|
||
//
|
||
|
||
UNREFERENCED_PARAMETER(DriverObject);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // DriverEntry
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
TdiMapUserRequest(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine maps a user request from the NtDeviceIoControlFile format
|
||
to the kernel mode request format. It does this by probing and locking all
|
||
buffers of interest, copying parameter sets to the stack pointer as
|
||
appropriate, and generally preparing for the kernel IO form.
|
||
|
||
Arguments:
|
||
|
||
Irp - pointer to the irp containing this request.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation. STATUS_UNSUCCESSFUL if the request could
|
||
not be mapped, STATUS_NOT_IMPLEMENTED if the IOCTL is not recognized
|
||
(allowing driver writers to extend the supported IOCTLs if needed), and
|
||
STATUS_SUCCESS if the request was mapped successfully.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
|
||
DeviceObject;
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
||
|
||
case IOCTL_TDI_ACCEPT:
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_ACCEPT;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IOCTL_TDI_ACTION:
|
||
|
||
#if defined(_WIN64)
|
||
if (IoIs32bitProcess(Irp)) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
#endif // _WIN64
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_ACTION;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IOCTL_TDI_CONNECT:
|
||
{
|
||
PTDI_REQUEST_CONNECT userRequest;
|
||
PTDI_REQUEST_KERNEL_CONNECT request;
|
||
PTDI_CONNECTION_INFORMATION connInfo;
|
||
PCHAR ptr;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_CONNECT) ) {
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_CONNECT;
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_CONNECT)Irp->AssociatedIrp.SystemBuffer;
|
||
connInfo = userRequest->RequestConnectionInformation;
|
||
|
||
ptr = (PCHAR)(connInfo + 1);
|
||
|
||
connInfo->UserData = ptr;
|
||
ptr += connInfo->UserDataLength;
|
||
connInfo->Options = ptr;
|
||
ptr += connInfo->OptionsLength;
|
||
connInfo->RemoteAddress = ptr;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_CONNECT)&IrpSp->Parameters;
|
||
request->RequestConnectionInformation = connInfo;
|
||
|
||
request->ReturnConnectionInformation = NULL;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_DISCONNECT:
|
||
{
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_DISCONNECT;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_LISTEN:
|
||
{
|
||
PTDI_REQUEST_LISTEN userRequest;
|
||
PTDI_REQUEST_KERNEL_LISTEN request;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
//
|
||
// fix for 123633
|
||
//
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_LISTEN)) {
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_LISTEN)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_LISTEN;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_LISTEN)&IrpSp->Parameters;
|
||
request->RequestFlags = userRequest->ListenFlags;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_QUERY_INFORMATION:
|
||
{
|
||
PTDI_REQUEST_QUERY_INFORMATION userRequest;
|
||
PTDI_REQUEST_KERNEL_QUERY_INFORMATION request;
|
||
PTDI_CONNECTION_INFORMATION connInfo;
|
||
UINT RemainingSize;
|
||
PCHAR ptr;
|
||
|
||
#if defined(_WIN64)
|
||
if (IoIs32bitProcess(Irp)) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
#endif // _WIN64
|
||
|
||
RemainingSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
//
|
||
// 123634
|
||
//
|
||
if (RemainingSize >= sizeof(TDI_REQUEST_QUERY_INFORMATION)) {
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_QUERY_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_QUERY_INFORMATION;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
|
||
request->QueryType = userRequest->QueryType;
|
||
RemainingSize -= sizeof(TDI_REQUEST_QUERY_INFORMATION);
|
||
|
||
if (RemainingSize >= sizeof(TDI_CONNECTION_INFORMATION))
|
||
{
|
||
connInfo = (PTDI_CONNECTION_INFORMATION)(userRequest + 1);
|
||
ptr = (PCHAR)(connInfo + 1);
|
||
connInfo->UserData = ptr;
|
||
ptr += connInfo->UserDataLength;
|
||
connInfo->Options = ptr;
|
||
ptr += connInfo->OptionsLength;
|
||
connInfo->RemoteAddress = ptr;
|
||
request->RequestConnectionInformation = connInfo;
|
||
}
|
||
else
|
||
{
|
||
request->RequestConnectionInformation = NULL;
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_RECEIVE:
|
||
{
|
||
PTDI_REQUEST_RECEIVE userRequest;
|
||
PTDI_REQUEST_KERNEL_RECEIVE request;
|
||
ULONG receiveLength;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
//
|
||
// 123635
|
||
//
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_RECEIVE)) {
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_RECEIVE)Irp->AssociatedIrp.SystemBuffer;
|
||
receiveLength =
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_RECEIVE;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_RECEIVE)&IrpSp->Parameters;
|
||
request->ReceiveLength = receiveLength;
|
||
request->ReceiveFlags = userRequest->ReceiveFlags;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_RECEIVE_DATAGRAM:
|
||
{
|
||
PTDI_REQUEST_RECEIVE_DATAGRAM userRequest;
|
||
PTDI_REQUEST_KERNEL_RECEIVEDG request;
|
||
ULONG receiveLength;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
//
|
||
// 123636
|
||
//
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_RECEIVE_DATAGRAM)) {
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_RECEIVE_DATAGRAM)Irp->AssociatedIrp.SystemBuffer;
|
||
receiveLength =
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_RECEIVE_DATAGRAM;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_RECEIVEDG)&IrpSp->Parameters;
|
||
request->ReceiveLength = receiveLength;
|
||
request->ReceiveFlags = userRequest->ReceiveFlags;
|
||
request->ReceiveDatagramInformation = userRequest->ReceiveDatagramInformation;
|
||
request->ReturnDatagramInformation = userRequest->ReturnInformation;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_SEND:
|
||
{
|
||
PTDI_REQUEST_SEND userRequest;
|
||
PTDI_REQUEST_KERNEL_SEND request;
|
||
ULONG sendLength;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_SEND)) {
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_SEND)Irp->AssociatedIrp.SystemBuffer;
|
||
sendLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_SEND;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_SEND)&IrpSp->Parameters;
|
||
request->SendLength = sendLength;
|
||
request->SendFlags = userRequest->SendFlags;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_SEND_DATAGRAM:
|
||
{
|
||
PTDI_REQUEST_SEND_DATAGRAM userRequest;
|
||
PTDI_REQUEST_KERNEL_SENDDG request;
|
||
ULONG sendLength;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_SEND_DATAGRAM)) {
|
||
|
||
sendLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_SEND_DATAGRAM;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_SENDDG)&IrpSp->Parameters;
|
||
request->SendLength = sendLength;
|
||
|
||
userRequest = (PTDI_REQUEST_SEND_DATAGRAM)Irp->AssociatedIrp.SystemBuffer;
|
||
request->SendDatagramInformation = userRequest->SendDatagramInformation;
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_SET_EVENT_HANDLER:
|
||
|
||
//
|
||
// Because this request will enable direct callouts from the
|
||
// transport provider at DISPATCH_LEVEL to a client-specified
|
||
// routine, this request is only valid in kernel mode, denying
|
||
// access to this request in user mode.
|
||
//
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
|
||
case IOCTL_TDI_SET_INFORMATION:
|
||
{
|
||
PTDI_REQUEST_SET_INFORMATION userRequest;
|
||
PTDI_REQUEST_KERNEL_SET_INFORMATION request;
|
||
|
||
#if defined(_WIN64)
|
||
if (IoIs32bitProcess(Irp)) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
#endif // _WIN64
|
||
|
||
//
|
||
// 123637
|
||
//
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_SET_INFORMATION)) {
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_SET_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_SET_INFORMATION;
|
||
|
||
request = (PTDI_REQUEST_KERNEL_SET_INFORMATION)&IrpSp->Parameters;
|
||
request->SetType = userRequest->SetType;
|
||
request->RequestConnectionInformation = NULL;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_ASSOCIATE_ADDRESS:
|
||
{
|
||
PTDI_REQUEST_ASSOCIATE_ADDRESS userRequest;
|
||
PTDI_REQUEST_KERNEL_ASSOCIATE request;
|
||
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
//
|
||
// 123637
|
||
//
|
||
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(TDI_REQUEST_ASSOCIATE_ADDRESS)) {
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_ASSOCIATE_ADDRESS;
|
||
|
||
userRequest =
|
||
(PTDI_REQUEST_ASSOCIATE_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
|
||
request = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
|
||
request->AddressHandle = userRequest->AddressHandle;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IOCTL_TDI_DISASSOCIATE_ADDRESS:
|
||
{
|
||
if (Irp->RequestorMode == UserMode) {
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
IrpSp->MinorFunction = TDI_DISASSOCIATE_ADDRESS;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultConnectHandler(
|
||
IN PVOID TdiEventContext,
|
||
IN LONG RemoteAddressLength,
|
||
IN PVOID RemoteAddress,
|
||
IN LONG UserDataLength,
|
||
IN PVOID UserData,
|
||
IN LONG OptionsLength,
|
||
IN PVOID Options,
|
||
OUT CONNECTION_CONTEXT *ConnectionContext,
|
||
OUT PIRP *AcceptIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when a connect request has completed. The connection
|
||
is fully functional when the indication occurs.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - the context value passed in by the user in the Set Event Handler call
|
||
|
||
RemoteAddressLength,
|
||
|
||
RemoteAddress,
|
||
|
||
UserDataLength,
|
||
|
||
UserData,
|
||
|
||
OptionsLength,
|
||
|
||
Options,
|
||
|
||
ConnectionId
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (RemoteAddressLength);
|
||
UNREFERENCED_PARAMETER (RemoteAddress);
|
||
UNREFERENCED_PARAMETER (UserDataLength);
|
||
UNREFERENCED_PARAMETER (UserData);
|
||
UNREFERENCED_PARAMETER (OptionsLength);
|
||
UNREFERENCED_PARAMETER (Options);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES; // do nothing
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultDisconnectHandler(
|
||
IN PVOID TdiEventContext,
|
||
IN CONNECTION_CONTEXT ConnectionContext,
|
||
IN LONG DisconnectDataLength,
|
||
IN PVOID DisconnectData,
|
||
IN LONG DisconnectInformationLength,
|
||
IN PVOID DisconnectInformation,
|
||
IN ULONG DisconnectFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default disconnect event handler
|
||
for the transport endpoint. It is pointed to by a field in the
|
||
TP_ENDPOINT structure for an endpoint when the endpoint is
|
||
created, and also whenever the TdiSetEventHandler request is
|
||
submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TransportEndpoint - Pointer to open file object.
|
||
|
||
Context - Typeless pointer specifying connection context.
|
||
|
||
DisconnectIndicators - Value indicating reason for disconnection indication.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
UNREFERENCED_PARAMETER (DisconnectDataLength);
|
||
UNREFERENCED_PARAMETER (DisconnectData);
|
||
UNREFERENCED_PARAMETER (DisconnectInformationLength);
|
||
UNREFERENCED_PARAMETER (DisconnectInformation);
|
||
UNREFERENCED_PARAMETER (DisconnectFlags);
|
||
|
||
return STATUS_SUCCESS; // do nothing but return successfully.
|
||
|
||
} /* DefaultDisconnectHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultErrorHandler(
|
||
IN PVOID TdiEventContext, // the endpoint's file object.
|
||
IN NTSTATUS Status // status code indicating error type.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default error event handler for
|
||
the transport endpoint. It is pointed to by a field in the
|
||
TP_ENDPOINT structure for an endpoint when the endpoint is
|
||
created, and also whenever the TdiSetEventHandler request is
|
||
submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TransportEndpoint - Pointer to open file object.
|
||
|
||
Status - Status code indicated by this event.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (Status);
|
||
|
||
return STATUS_SUCCESS; // do nothing but return successfully.
|
||
|
||
} /* DefaultErrorHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultReceiveHandler(
|
||
IN PVOID TdiEventContext,
|
||
IN CONNECTION_CONTEXT ConnectionContext,
|
||
IN ULONG ReceiveFlags,
|
||
IN ULONG BytesIndicated,
|
||
IN ULONG BytesAvailable,
|
||
OUT ULONG *BytesTaken,
|
||
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
|
||
OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default receive event handler for
|
||
the transport endpoint. It is pointed to by a field in the
|
||
TP_ENDPOINT structure for an endpoint when the endpoint is
|
||
created, and also whenever the TdiSetEventHandler request is
|
||
submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - Pointer to the client-provided context value specified
|
||
in the TdiSetEventHandler call for TDI_EVENT_RECEIVE.
|
||
|
||
ConnectionContext - The client-supplied context associated with
|
||
the connection on which this connection-oriented TSDU was received.
|
||
|
||
ReceiveFlags - Bitflags which indicate the circumstances surrounding
|
||
this TSDU's reception.
|
||
|
||
BytesIndicated - The number of bytes of this TSDU that are being presented
|
||
to the client in this indication.This value is always less than
|
||
or equal to BytesAvailable.
|
||
|
||
BytesAvailable - The total number of bytes of this TSDU presently
|
||
available from the transport.
|
||
|
||
BytesTaken - Return value indicating the number of bytes of data that the
|
||
client copied from the indication data.
|
||
|
||
Tsdu - Pointer to an MDL chain that describes the (first) part of the
|
||
(partially) received Transport Service Data Unit, less headers.
|
||
|
||
IoRequestPacket - Pointer to a location where the event handler may
|
||
chose to return a pointer to an I/O Request Packet (IRP) to satisfy
|
||
the incoming data. If returned, this IRP must be formatted as a
|
||
valid TdiReceive request, except that the ConnectionId field of
|
||
the TdiRequest is ignored and is automatically filled in by the
|
||
transport provider.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
UNREFERENCED_PARAMETER (ReceiveFlags);
|
||
UNREFERENCED_PARAMETER (BytesIndicated);
|
||
UNREFERENCED_PARAMETER (BytesAvailable);
|
||
UNREFERENCED_PARAMETER (BytesTaken);
|
||
UNREFERENCED_PARAMETER (Tsdu);
|
||
UNREFERENCED_PARAMETER (IoRequestPacket);
|
||
|
||
return STATUS_DATA_NOT_ACCEPTED; // no handler in place.
|
||
|
||
} /* DefaultReceiveHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultRcvDatagramHandler(
|
||
IN PVOID TdiEventContext, // the event context
|
||
IN LONG SourceAddressLength, // length of the originator of the datagram
|
||
IN PVOID SourceAddress, // string describing the originator of the datagram
|
||
IN LONG OptionsLength, // options for the receive
|
||
IN PVOID Options, //
|
||
IN ULONG ReceiveDatagramFlags, //
|
||
IN ULONG BytesIndicated, // number of bytes this indication
|
||
IN ULONG BytesAvailable, // number of bytes in complete Tsdu
|
||
OUT ULONG *BytesTaken, // number of bytes used
|
||
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
|
||
OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default receive datagram event
|
||
handler for the transport endpoint. It is pointed to by a
|
||
field in the TP_ENDPOINT structure for an endpoint when the
|
||
endpoint is created, and also whenever the TdiSetEventHandler
|
||
request is submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - Pointer to the client-provided context value specified
|
||
in the TdiSetEventHandler call for TDI_EVENT_RECEIVE_DATAGRAM.
|
||
|
||
DestinationAddress - Pointer to the network name of the destination
|
||
to which the datagram was directed.
|
||
|
||
SourceAddress - Pointer to the network name of the source from which
|
||
the datagram originated.
|
||
|
||
Tsap - Transport service access point on which this datagram was received.
|
||
|
||
ReceiveIndicators - Bitflags which indicate the circumstances surrounding
|
||
this TSDU's reception.
|
||
|
||
Tsdu - Pointer to an MDL chain that describes the (first) part of the
|
||
(partially) received Transport Service Data Unit, less headers.
|
||
|
||
IoRequestPacket - Pointer to a location where the event handler may
|
||
chose to return a pointer to an I/O Request Packet (IRP) to satisfy
|
||
the incoming data. If returned, this IRP must be formatted as a
|
||
valid TdiReceiveDatagram request.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (SourceAddressLength);
|
||
UNREFERENCED_PARAMETER (SourceAddress);
|
||
UNREFERENCED_PARAMETER (OptionsLength);
|
||
UNREFERENCED_PARAMETER (Options);
|
||
UNREFERENCED_PARAMETER (BytesIndicated);
|
||
UNREFERENCED_PARAMETER (BytesAvailable);
|
||
UNREFERENCED_PARAMETER (BytesTaken);
|
||
UNREFERENCED_PARAMETER (Tsdu);
|
||
UNREFERENCED_PARAMETER (IoRequestPacket);
|
||
|
||
return STATUS_DATA_NOT_ACCEPTED; // no handler in place.
|
||
|
||
} /* DefaultRcvDatagramHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultRcvExpeditedHandler(
|
||
IN PVOID TdiEventContext,
|
||
IN CONNECTION_CONTEXT ConnectionContext,
|
||
IN ULONG ReceiveFlags, //
|
||
IN ULONG BytesIndicated, // number of bytes in this indication
|
||
IN ULONG BytesAvailable, // number of bytes in complete Tsdu
|
||
OUT ULONG *BytesTaken, // number of bytes used by indication routine
|
||
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
|
||
OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default expedited receive event handler
|
||
for the transport endpoint. It is pointed to by a field in the
|
||
TP_ENDPOINT structure for an endpoint when the endpoint is
|
||
created, and also whenever the TdiSetEventHandler request is
|
||
submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - Pointer to the client-provided context value specified
|
||
in the TdiSetEventHandler call for TDI_EVENT_RECEIVE.
|
||
|
||
ConnectionContext - The client-supplied context associated with
|
||
the connection on which this connection-oriented TSDU was received.
|
||
|
||
ReceiveFlags - Bitflags which indicate the circumstances surrounding
|
||
this TSDU's reception.
|
||
|
||
BytesIndicated - The number of bytes of this TSDU that are being presented
|
||
to the client in this indication.This value is always less than
|
||
or equal to BytesAvailable.
|
||
|
||
BytesAvailable - The total number of bytes of this TSDU presently
|
||
available from the transport.
|
||
|
||
BytesTaken - Return value indicating the number of bytes of data that the
|
||
client copied from the indication data.
|
||
|
||
Tsdu - Pointer to an MDL chain that describes the (first) part of the
|
||
(partially) received Transport Service Data Unit, less headers.
|
||
|
||
IoRequestPacket - Pointer to a location where the event handler may
|
||
chose to return a pointer to an I/O Request Packet (IRP) to satisfy
|
||
the incoming data. If returned, this IRP must be formatted as a
|
||
valid TdiReceive request, except that the ConnectionId field of
|
||
the TdiRequest is ignored and is automatically filled in by the
|
||
transport provider.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
UNREFERENCED_PARAMETER (ReceiveFlags);
|
||
UNREFERENCED_PARAMETER (BytesIndicated);
|
||
UNREFERENCED_PARAMETER (BytesAvailable);
|
||
UNREFERENCED_PARAMETER (BytesTaken);
|
||
UNREFERENCED_PARAMETER (Tsdu);
|
||
UNREFERENCED_PARAMETER (IoRequestPacket);
|
||
|
||
return STATUS_DATA_NOT_ACCEPTED;
|
||
|
||
} /* DefaultRcvExpeditedHandler */
|
||
|
||
NTSTATUS
|
||
TdiDefaultChainedReceiveHandler (
|
||
IN PVOID TdiEventContext,
|
||
IN CONNECTION_CONTEXT ConnectionContext,
|
||
IN ULONG ReceiveFlags,
|
||
IN ULONG ReceiveLength,
|
||
IN ULONG StartingOffset,
|
||
IN PMDL Tsdu,
|
||
IN PVOID TsduDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default chanied receive event handler
|
||
for the transport endpoint. It is pointed to by a field in the
|
||
TP_ENDPOINT structure for an endpoint when the endpoint is
|
||
created, and also whenever the TdiSetEventHandler request is
|
||
submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - Pointer to the client-provided context value specified
|
||
in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE.
|
||
|
||
ConnectionContext - The client-supplied context associated with
|
||
the connection on which this connection-oriented TSDU was received.
|
||
|
||
ReceiveFlags - Bitflags which indicate the circumstances surrounding
|
||
this TSDU's reception.
|
||
|
||
ReceiveLength - The length in bytes of client data in the TSDU.
|
||
|
||
StartingOffset - The offset, in bytes from the beginning of the TSDU,
|
||
at which the client data begins.
|
||
|
||
Tsdu - Pointer to an MDL chain that describes the entire received
|
||
Transport Service Data Unit.
|
||
|
||
TsduDescriptor - A descriptor for the TSDU which must be passed to
|
||
TdiReturnChainedReceives in order to return the TSDU for reuse.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
UNREFERENCED_PARAMETER (ReceiveFlags);
|
||
UNREFERENCED_PARAMETER (ReceiveLength);
|
||
UNREFERENCED_PARAMETER (StartingOffset);
|
||
UNREFERENCED_PARAMETER (Tsdu);
|
||
UNREFERENCED_PARAMETER (TsduDescriptor);
|
||
|
||
return STATUS_DATA_NOT_ACCEPTED;
|
||
|
||
} /* DefaultChainedReceiveHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultChainedRcvDatagramHandler(
|
||
IN PVOID TdiEventContext,
|
||
IN LONG SourceAddressLength,
|
||
IN PVOID SourceAddress,
|
||
IN LONG OptionsLength,
|
||
IN PVOID Options,
|
||
IN ULONG ReceiveDatagramFlags,
|
||
IN ULONG ReceiveDatagramLength,
|
||
IN ULONG StartingOffset,
|
||
IN PMDL Tsdu,
|
||
IN PVOID TsduDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default chained receive datagram
|
||
event handler for the transport endpoint. It is pointed to by
|
||
a field in the TP_ENDPOINT structure for an endpoint when the
|
||
endpoint is created, and also whenever the TdiSetEventHandler
|
||
request is submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - Pointer to the client-provided context value specified
|
||
in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE_DATAGRAM.
|
||
|
||
SourceAddressLength - The length of the source network address.
|
||
|
||
SourceAddress - Pointer to the network address of the source from which
|
||
the datagram originated.
|
||
|
||
OptionsLength - The length of the transport options accompanying this TSDU.
|
||
|
||
Options - Pointer to the transport options accompanying this TSDU.
|
||
|
||
ReceiveDatagramFlags - Bitflags which indicate the circumstances
|
||
surrounding this TSDU's reception.
|
||
|
||
ReceiveDatagramLength - The length, in bytes, of the client data in
|
||
this TSDU.
|
||
|
||
StartingOffset - The offset, in bytes from the start of the TSDU, at
|
||
which the client data begins.
|
||
|
||
Tsdu - Pointer to an MDL chain that describes the received Transport
|
||
Service Data Unit.
|
||
|
||
TsduDescriptor - A descriptor for the TSDU which must be passed to
|
||
TdiReturnChainedReceives in order to return the TSDU for reuse.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (SourceAddressLength);
|
||
UNREFERENCED_PARAMETER (SourceAddress);
|
||
UNREFERENCED_PARAMETER (OptionsLength);
|
||
UNREFERENCED_PARAMETER (Options);
|
||
UNREFERENCED_PARAMETER (ReceiveDatagramLength);
|
||
UNREFERENCED_PARAMETER (StartingOffset);
|
||
UNREFERENCED_PARAMETER (Tsdu);
|
||
UNREFERENCED_PARAMETER (TsduDescriptor);
|
||
|
||
return STATUS_DATA_NOT_ACCEPTED;
|
||
|
||
} /* DefaultChainedRcvDatagramHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultChainedRcvExpeditedHandler(
|
||
IN PVOID TdiEventContext,
|
||
IN CONNECTION_CONTEXT ConnectionContext,
|
||
IN ULONG ReceiveFlags,
|
||
IN ULONG ReceiveLength,
|
||
IN ULONG StartingOffset,
|
||
IN PMDL Tsdu,
|
||
IN PVOID TsduDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used as the default chained expedited receive event
|
||
handler for the transport endpoint. It is pointed to by a field
|
||
in the TP_ENDPOINT structure for an endpoint when the endpoint is
|
||
created, and also whenever the TdiSetEventHandler request is
|
||
submitted with a NULL EventHandler field.
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - Pointer to the client-provided context value specified
|
||
in the TdiSetEventHandler call for TDI_EVENT_CHAINED_RECEIVE_EXPEDITED.
|
||
|
||
ConnectionContext - The client-supplied context associated with
|
||
the connection on which this connection-oriented TSDU was received.
|
||
|
||
ReceiveFlags - Bitflags which indicate the circumstances surrounding
|
||
this TSDU's reception.
|
||
|
||
ReceiveLength - The length in bytes of client data in the TSDU.
|
||
|
||
StartingOffset - The offset, in bytes from the beginning of the TSDU,
|
||
at which the client data begins.
|
||
|
||
Tsdu - Pointer to an MDL chain that describes the entire received
|
||
Transport Service Data Unit.
|
||
|
||
TsduDescriptor - A descriptor for the TSDU which must be passed to
|
||
TdiReturnChainedReceives in order to return the TSDU for reuse.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
UNREFERENCED_PARAMETER (ReceiveFlags);
|
||
UNREFERENCED_PARAMETER (ReceiveLength);
|
||
UNREFERENCED_PARAMETER (StartingOffset);
|
||
UNREFERENCED_PARAMETER (Tsdu);
|
||
UNREFERENCED_PARAMETER (TsduDescriptor);
|
||
|
||
return STATUS_DATA_NOT_ACCEPTED;
|
||
|
||
} /* DefaultRcvExpeditedHandler */
|
||
|
||
|
||
NTSTATUS
|
||
TdiDefaultSendPossibleHandler (
|
||
IN PVOID TdiEventContext,
|
||
IN PVOID ConnectionContext,
|
||
IN ULONG BytesAvailable)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
TdiEventContext - the context value passed in by the user in the Set Event Handler call
|
||
|
||
ConnectionContext - connection context of connection which can be sent on
|
||
|
||
BytesAvailable - number of bytes which can now be sent
|
||
|
||
Return Value:
|
||
|
||
ignored by the transport
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER (TdiEventContext);
|
||
UNREFERENCED_PARAMETER (ConnectionContext);
|
||
UNREFERENCED_PARAMETER (BytesAvailable);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
TdiBuildNetbiosAddress(
|
||
IN PUCHAR NetbiosName,
|
||
IN BOOLEAN IsGroupName,
|
||
IN OUT PTA_NETBIOS_ADDRESS NetworkName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds a TA_NETBIOS_ADDRESS structure in the locations pointed
|
||
to by NetworkName. All fields are filled out.
|
||
|
||
Arguments:
|
||
|
||
NetbiosName - Pointer to a 16-byte buffer where the a netbios name is
|
||
supplied.
|
||
|
||
IsGroupName - TRUE if this name is a group name, false otherwise.
|
||
|
||
NetworkName - A pointer to a TA_NETBIOS_ADDRESS structure that is to
|
||
receive the buid TDI address.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
//IF_TDIDBG (TDI_DEBUG_NAMES) {
|
||
// DbgPrint ("TdiBuildNetBIOSAddress: Entered.\n");
|
||
//}
|
||
|
||
NetworkName->TAAddressCount = 1;
|
||
NetworkName->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
NetworkName->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
|
||
|
||
if (IsGroupName) {
|
||
NetworkName->Address[0].Address[0].NetbiosNameType =
|
||
TDI_ADDRESS_NETBIOS_TYPE_GROUP;
|
||
} else {
|
||
NetworkName->Address[0].Address[0].NetbiosNameType =
|
||
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
}
|
||
|
||
RtlCopyMemory (
|
||
NetworkName->Address[0].Address[0].NetbiosName,
|
||
NetbiosName,
|
||
16);
|
||
|
||
} /* TdiBuildNetbiosAddress */
|
||
|
||
|
||
NTSTATUS
|
||
TdiBuildNetbiosAddressEa (
|
||
IN PUCHAR Buffer,
|
||
IN BOOLEAN IsGroupName,
|
||
IN PUCHAR NetbiosName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Builds an EA describing a Netbios address in the buffer supplied by the
|
||
user.
|
||
|
||
Arguments:
|
||
|
||
Buffer - pointer to a buffer that the ea is to be built in. This buffer
|
||
must be at least 40 bytes long.
|
||
|
||
IsGroupName - true if the netbios name is a group name, false otherwise.
|
||
|
||
NetbiosName - the netbios name to be inserted in the EA to be built.
|
||
|
||
Return Value:
|
||
|
||
An informative error code if something goes wrong. STATUS_SUCCESS if the
|
||
ea is built properly.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFILE_FULL_EA_INFORMATION EaBuffer;
|
||
PTA_NETBIOS_ADDRESS TAAddress;
|
||
ULONG Length;
|
||
|
||
IF_TDIDBG (TDI_DEBUG_NAMES) {
|
||
DbgPrint ("TdiBuildNetbiosAddressEa: Entered\n ");
|
||
}
|
||
|
||
try {
|
||
Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof (TA_NETBIOS_ADDRESS);
|
||
EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
|
||
|
||
if (EaBuffer == NULL) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
EaBuffer->NextEntryOffset = 0;
|
||
EaBuffer->Flags = 0;
|
||
EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
||
EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
|
||
|
||
RtlCopyMemory (
|
||
EaBuffer->EaName,
|
||
TdiTransportAddress,
|
||
EaBuffer->EaNameLength + 1);
|
||
|
||
TAAddress = (PTA_NETBIOS_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
|
||
|
||
TdiBuildNetbiosAddress (
|
||
NetbiosName,
|
||
IsGroupName,
|
||
TAAddress);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
//
|
||
// Couldn't touch the passed parameters; just return an error
|
||
// status.
|
||
//
|
||
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} /* TdiBuildNetbiosAddressEa */
|
||
|
||
|
||
NTSTATUS
|
||
TdiCopyMdlToBuffer(
|
||
IN PMDL SourceMdlChain,
|
||
IN ULONG SourceOffset,
|
||
IN PVOID DestinationBuffer,
|
||
IN ULONG DestinationOffset,
|
||
IN ULONG DestinationBufferSize,
|
||
OUT PULONG BytesCopied
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies data described by the source MDL chain starting at
|
||
the source offset, into a flat buffer specified by the SVA starting at
|
||
the destination offset. A maximum of DestinationBufferSize bytes can
|
||
be copied. The actual number of bytes copied is returned in BytesCopied.
|
||
|
||
Arguments:
|
||
|
||
SourceMdlChain - Pointer to a chain of MDLs describing the source data.
|
||
|
||
SourceOffset - Number of bytes to skip in the source data.
|
||
|
||
DestinationBuffer - Pointer to a flat buffer to copy the data to.
|
||
|
||
DestinationOffset - Number of leading bytes to skip in the destination buffer.
|
||
|
||
DestinationBufferSize - Size of the output buffer, including the offset.
|
||
|
||
BytesCopied - Pointer to a longword where the actual number of bytes
|
||
transferred will be returned.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR Dest, Src;
|
||
ULONG SrcBytesLeft, DestBytesLeft, BytesSkipped=0;
|
||
|
||
// IF_TDIDBG (TDI_DEBUG_MAP) {
|
||
// DbgPrint ("TdiCopyMdlToBuffer: Entered.\n");
|
||
// }
|
||
|
||
ASSERT( DestinationBufferSize >= DestinationOffset );
|
||
|
||
*BytesCopied = 0;
|
||
|
||
//
|
||
// Skip source bytes.
|
||
//
|
||
|
||
if ((Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
while (BytesSkipped < SourceOffset) {
|
||
if (SrcBytesLeft > (SourceOffset - BytesSkipped)) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Skipping part of this MDL.\n");
|
||
SrcBytesLeft -= (SourceOffset - BytesSkipped);
|
||
Src += (SourceOffset - BytesSkipped);
|
||
BytesSkipped = SourceOffset;
|
||
break;
|
||
} else if (SrcBytesLeft == (SourceOffset - BytesSkipped)) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Skipping this exact MDL.\n");
|
||
SourceMdlChain = SourceMdlChain->Next;
|
||
if (SourceMdlChain == NULL) {
|
||
//PANIC ("TdiCopyMdlToBuffer: MDL chain was all header.\n");
|
||
return STATUS_SUCCESS; // no bytes copied.
|
||
}
|
||
BytesSkipped = SourceOffset;
|
||
if ((Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
break;
|
||
} else {
|
||
// PANIC ("TdiCopyMdlToBuffer: Skipping all of this MDL & more.\n");
|
||
BytesSkipped += SrcBytesLeft;
|
||
SourceMdlChain = SourceMdlChain->Next;
|
||
if (SourceMdlChain == NULL) {
|
||
//PANIC ("TdiCopyMdlToBuffer: Premature end of MDL chain.\n");
|
||
return STATUS_SUCCESS; // no bytes copied.
|
||
}
|
||
if ((Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
}
|
||
}
|
||
|
||
// PANIC ("TdiCopyMdlToBuffer: done skipping source bytes.\n");
|
||
|
||
//
|
||
// Skip destination bytes.
|
||
//
|
||
|
||
Dest = (PUCHAR)DestinationBuffer + DestinationOffset;
|
||
DestBytesLeft = DestinationBufferSize - DestinationOffset;
|
||
|
||
//
|
||
// Copy source data into the destination buffer until it's full or
|
||
// we run out of data, whichever comes first.
|
||
//
|
||
|
||
while (DestBytesLeft && SourceMdlChain) {
|
||
if (SrcBytesLeft == 0) {
|
||
// PANIC ("TdiCopyMdlToBuffer: MDL is empty, skipping to next one.\n");
|
||
SourceMdlChain = SourceMdlChain->Next;
|
||
if (SourceMdlChain == NULL) {
|
||
// PANIC ("TdiCopyMdlToBuffer: But there are no more MDLs.\n");
|
||
return STATUS_SUCCESS;
|
||
}
|
||
if ((Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
continue; // skip 0-length MDL's.
|
||
}
|
||
// PANIC ("TdiCopyMdlToBuffer: Copying a chunk.\n");
|
||
if (DestBytesLeft == SrcBytesLeft) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Copying exact amount.\n");
|
||
RtlCopyBytes (Dest, Src, DestBytesLeft);
|
||
*BytesCopied += DestBytesLeft;
|
||
return STATUS_SUCCESS;
|
||
} else if (DestBytesLeft < SrcBytesLeft) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Buffer overflow, copying some.\n");
|
||
RtlCopyBytes (Dest, Src, DestBytesLeft);
|
||
*BytesCopied += DestBytesLeft;
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
// PANIC ("TdiCopyMdlToBuffer: Copying all of this MDL, & more.\n");
|
||
RtlCopyBytes (Dest, Src, SrcBytesLeft);
|
||
*BytesCopied += SrcBytesLeft;
|
||
DestBytesLeft -= SrcBytesLeft;
|
||
Dest += SrcBytesLeft;
|
||
SrcBytesLeft = 0;
|
||
}
|
||
}
|
||
|
||
return SourceMdlChain == NULL ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
|
||
} /* TdiCopyMdlToBuffer */
|
||
|
||
|
||
NTSTATUS
|
||
TdiCopyBufferToMdl (
|
||
IN PVOID SourceBuffer,
|
||
IN ULONG SourceOffset,
|
||
IN ULONG SourceBytesToCopy,
|
||
IN PMDL DestinationMdlChain,
|
||
IN ULONG DestinationOffset,
|
||
IN PULONG BytesCopied
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies data described by the source buffer to the MDL chain
|
||
described by the DestinationMdlChain. The
|
||
|
||
Arguments:
|
||
|
||
SourceBuffer - pointer to the source buffer
|
||
|
||
SourceOffset - Number of bytes to skip in the source data.
|
||
|
||
SourceBytesToCopy - number of bytes to copy from the source buffer
|
||
|
||
DestinationMdlChain - Pointer to a chain of MDLs describing the
|
||
destination buffers.
|
||
|
||
DestinationOffset - Number of bytes to skip in the destination data.
|
||
|
||
BytesCopied - Pointer to a longword where the actual number of bytes
|
||
transferred will be returned.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR Dest, Src;
|
||
ULONG DestBytesLeft, BytesSkipped=0;
|
||
|
||
//IF_TDIDBG (TDI_DEBUG_MAP) {
|
||
// DbgPrint ("TdiCopyBufferToMdl: Entered.\n");
|
||
//}
|
||
|
||
*BytesCopied = 0;
|
||
|
||
if (SourceBytesToCopy == 0) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
if (DestinationMdlChain == NULL) {
|
||
// No MDL to copy to. Output buffer was zero length.
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
//
|
||
// Skip Destination bytes.
|
||
//
|
||
|
||
if ((Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
while (BytesSkipped < DestinationOffset) {
|
||
if (DestBytesLeft > (DestinationOffset - BytesSkipped)) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Skipping part of this MDL.\n");
|
||
DestBytesLeft -= (DestinationOffset - BytesSkipped);
|
||
Dest += (DestinationOffset - BytesSkipped);
|
||
BytesSkipped = DestinationOffset;
|
||
break;
|
||
} else if (DestBytesLeft == (DestinationOffset - BytesSkipped)) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Skipping this exact MDL.\n");
|
||
DestinationMdlChain = DestinationMdlChain->Next;
|
||
if (DestinationMdlChain == NULL) {
|
||
//PANIC ("TdiCopyMdlToBuffer: MDL chain was all header.\n");
|
||
return STATUS_BUFFER_OVERFLOW; // no bytes copied.
|
||
}
|
||
BytesSkipped = DestinationOffset;
|
||
if ((Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
break;
|
||
} else {
|
||
// PANIC ("TdiCopyMdlToBuffer: Skipping all of this MDL & more.\n");
|
||
BytesSkipped += DestBytesLeft;
|
||
DestinationMdlChain = DestinationMdlChain->Next;
|
||
if (DestinationMdlChain == NULL) {
|
||
//PANIC ("TdiCopyMdlToBuffer: Premature end of MDL chain.\n");
|
||
return STATUS_BUFFER_OVERFLOW; // no bytes copied.
|
||
}
|
||
if ((Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
}
|
||
}
|
||
|
||
// PANIC ("TdiCopyMdlToBuffer: done skipping source bytes.\n");
|
||
|
||
//
|
||
// Skip source bytes.
|
||
//
|
||
|
||
Src = (PUCHAR)SourceBuffer + SourceOffset;
|
||
|
||
//
|
||
// Copy source data into the destination buffer until it's full or
|
||
// we run out of data, whichever comes first.
|
||
//
|
||
|
||
while ((SourceBytesToCopy != 0) && (DestinationMdlChain != NULL)) {
|
||
if (DestBytesLeft == 0) {
|
||
// PANIC ("TdiCopyMdlToBuffer: MDL is empty, skipping to next one.\n");
|
||
DestinationMdlChain = DestinationMdlChain->Next;
|
||
if (DestinationMdlChain == NULL) {
|
||
// PANIC ("TdiCopyMdlToBuffer: But there are no more MDLs.\n");
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority);
|
||
if (Dest == NULL) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
continue; // skip 0-length MDL's.
|
||
}
|
||
|
||
// PANIC ("TdiCopyMdlToBuffer: Copying a chunk.\n");
|
||
if (DestBytesLeft >= SourceBytesToCopy) {
|
||
// PANIC ("TdiCopyMdlToBuffer: Copying exact amount.\n");
|
||
RtlCopyBytes (Dest, Src, SourceBytesToCopy);
|
||
*BytesCopied += SourceBytesToCopy;
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
// PANIC ("TdiCopyMdlToBuffer: Copying all of this MDL, & more.\n");
|
||
RtlCopyBytes (Dest, Src, DestBytesLeft);
|
||
*BytesCopied += DestBytesLeft;
|
||
SourceBytesToCopy -= DestBytesLeft;
|
||
Src += DestBytesLeft;
|
||
DestBytesLeft = 0;
|
||
}
|
||
}
|
||
|
||
return SourceBytesToCopy == 0 ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
|
||
|
||
} /* TdiCopyBufferToMdl */
|
||
|
||
|
||
NTSTATUS
|
||
TdiCopyMdlChainToMdlChain (
|
||
IN PMDL SourceMdlChain,
|
||
IN ULONG SourceOffset,
|
||
IN PMDL DestinationMdlChain,
|
||
IN ULONG DestinationOffset,
|
||
OUT PULONG BytesCopied
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies data described by the source MDL chain to the MDL chain
|
||
described by the DestinationMdlChain.
|
||
|
||
Arguments:
|
||
|
||
SourceMdlChain - Pointer to a chain of MDLs describing the source buffers.
|
||
|
||
SourceOffset - Number of initial bytes to skip in the source data.
|
||
|
||
DestinationMdlChain - Pointer to a chain of MDLs describing the
|
||
destination buffers.
|
||
|
||
DestinationOffset - Number of initial bytes to skip in the destination data.
|
||
|
||
BytesCopied - Pointer to a longword where the actual number of bytes
|
||
transferred will be returned.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR Dest, Src;
|
||
ULONG DestBytesLeft, SrcBytesLeft, BytesSkipped;
|
||
ULONG CopyAmount;
|
||
|
||
*BytesCopied = 0;
|
||
|
||
if (DestinationMdlChain == NULL) {
|
||
// No MDL to copy to.
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
//
|
||
// Skip Destination bytes.
|
||
//
|
||
BytesSkipped = 0;
|
||
if ((Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
|
||
while (BytesSkipped < DestinationOffset) {
|
||
|
||
if (DestBytesLeft > (DestinationOffset - BytesSkipped)) {
|
||
// the desired offset resides within this MDL.
|
||
Dest += (DestinationOffset - BytesSkipped);
|
||
DestBytesLeft -= (DestinationOffset - BytesSkipped);
|
||
break;
|
||
}
|
||
|
||
// skip over this MDL
|
||
BytesSkipped += DestBytesLeft;
|
||
DestinationMdlChain = DestinationMdlChain->Next;
|
||
if (DestinationMdlChain == NULL) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
if ((Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
}
|
||
|
||
//
|
||
// Skip source bytes.
|
||
//
|
||
BytesSkipped = 0;
|
||
if ((Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
|
||
while (BytesSkipped < SourceOffset) {
|
||
|
||
if (SrcBytesLeft > (SourceOffset - BytesSkipped)) {
|
||
// the desired offset resides within this MDL.
|
||
Src += (SourceOffset - BytesSkipped);
|
||
SrcBytesLeft -= (SourceOffset - BytesSkipped);
|
||
break;
|
||
}
|
||
|
||
// skip over this MDL
|
||
BytesSkipped += SrcBytesLeft;
|
||
SourceMdlChain = SourceMdlChain->Next;
|
||
if (SourceMdlChain == NULL) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if ((Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority)) == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
}
|
||
|
||
|
||
//
|
||
// Copy source data into the destination buffer until it's full or
|
||
// we run out of data, whichever comes first.
|
||
//
|
||
|
||
while ((SourceMdlChain != NULL) && (DestinationMdlChain != NULL)) {
|
||
if (SrcBytesLeft == 0)
|
||
{
|
||
SourceMdlChain = SourceMdlChain->Next;
|
||
if (SourceMdlChain == NULL) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
Src = MmGetSystemAddressForMdlSafe (SourceMdlChain, NormalPagePriority);
|
||
if (Src == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
SrcBytesLeft = MmGetMdlByteCount (SourceMdlChain);
|
||
continue;
|
||
}
|
||
|
||
if (DestBytesLeft == 0) {
|
||
DestinationMdlChain = DestinationMdlChain->Next;
|
||
if (DestinationMdlChain == NULL) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
Dest = MmGetSystemAddressForMdlSafe (DestinationMdlChain, NormalPagePriority);
|
||
if (Dest == NULL) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
DestBytesLeft = MmGetMdlByteCount (DestinationMdlChain);
|
||
continue;
|
||
}
|
||
|
||
CopyAmount = ((DestBytesLeft > SrcBytesLeft)? SrcBytesLeft: DestBytesLeft);
|
||
RtlCopyBytes (Dest, Src, CopyAmount);
|
||
|
||
SrcBytesLeft -= CopyAmount;
|
||
Src += CopyAmount;
|
||
|
||
DestBytesLeft -= CopyAmount;
|
||
Dest += CopyAmount;
|
||
|
||
*BytesCopied += CopyAmount;
|
||
}
|
||
|
||
return SourceMdlChain == NULL ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
|
||
|
||
} /* TdiCopyMdlChainToMdlChain */
|
||
|
||
|
||
NTSTATUS
|
||
TdiOpenNetbiosAddress (
|
||
IN OUT PHANDLE FileHandle,
|
||
IN PUCHAR Buffer,
|
||
IN PVOID DeviceName,
|
||
IN PVOID Address)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens an address on the given file handle and device.
|
||
|
||
Arguments:
|
||
|
||
FileHandle - the returned handle to the file object that is opened.
|
||
|
||
Buffer - pointer to a buffer that the ea is to be built in. This buffer
|
||
must be at least 40 bytes long.
|
||
|
||
DeviceName - the Unicode string that points to the device object.
|
||
|
||
Name - the address to be registered. If this pointer is NULL, the routine
|
||
will attempt to open a "control channel" to the device; that is, it
|
||
will attempt to open the file object with a null ea pointer, and if the
|
||
transport provider allows for that, will return that handle.
|
||
|
||
Return Value:
|
||
|
||
An informative error code if something goes wrong. STATUS_SUCCESS if the
|
||
returned file handle is valid.
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
PFILE_FULL_EA_INFORMATION EaBuffer;
|
||
TA_NETBIOS_ADDRESS NetbiosAddress;
|
||
PSZ Name;
|
||
ULONG Length;
|
||
|
||
IF_TDIDBG (TDI_DEBUG_NAMES) {
|
||
DbgPrint ("TdiOpenNetbiosAddress: Opening ");
|
||
if (Address == NULL) {
|
||
DbgPrint (" Control Channel");
|
||
} else {
|
||
DbgPrint (Address);
|
||
}
|
||
DbgPrint (".\n");
|
||
}
|
||
|
||
if (Address != NULL) {
|
||
Name = (PSZ)Address;
|
||
try {
|
||
Length = FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
|
||
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
|
||
sizeof(TA_NETBIOS_ADDRESS);
|
||
EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
|
||
|
||
if (EaBuffer == NULL) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
EaBuffer->NextEntryOffset = 0;
|
||
EaBuffer->Flags = 0;
|
||
EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
|
||
EaBuffer->EaValueLength = sizeof (TA_NETBIOS_ADDRESS);
|
||
|
||
RtlCopyMemory(
|
||
EaBuffer->EaName,
|
||
TdiTransportAddress,
|
||
EaBuffer->EaNameLength + 1
|
||
);
|
||
|
||
//
|
||
// Create a copy of the NETBIOS address descriptor in a local
|
||
// first, in order to avoid alignment problems.
|
||
//
|
||
|
||
NetbiosAddress.TAAddressCount = 1;
|
||
NetbiosAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
|
||
NetbiosAddress.Address[0].AddressLength =
|
||
sizeof (TDI_ADDRESS_NETBIOS);
|
||
NetbiosAddress.Address[0].Address[0].NetbiosNameType =
|
||
TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
|
||
RtlCopyMemory(
|
||
NetbiosAddress.Address[0].Address[0].NetbiosName,
|
||
Name,
|
||
16
|
||
);
|
||
|
||
RtlCopyMemory (
|
||
&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
|
||
&NetbiosAddress,
|
||
sizeof(TA_NETBIOS_ADDRESS)
|
||
);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
//
|
||
// Couldn't touch the passed parameters; just return an error
|
||
// status.
|
||
//
|
||
|
||
return GetExceptionCode();
|
||
}
|
||
} else {
|
||
EaBuffer = NULL;
|
||
Length = 0;
|
||
}
|
||
|
||
InitializeObjectAttributes (
|
||
&ObjectAttributes,
|
||
DeviceName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
Status = NtCreateFile (
|
||
FileHandle,
|
||
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access.
|
||
&ObjectAttributes, // object attributes.
|
||
&IoStatusBlock, // returned status information.
|
||
0, // block size (unused).
|
||
0, // file attributes.
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access.
|
||
FILE_CREATE, // create disposition.
|
||
0, // create options.
|
||
EaBuffer, // EA buffer.
|
||
Length); // EA length.
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
IF_TDIDBG (TDI_DEBUG_NAMES) {
|
||
DbgPrint ("TdiOpenNetbiosEndpoint: FAILURE, NtCreateFile returned status %lx.\n", Status);
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
Status = IoStatusBlock.Status;
|
||
|
||
if (!(NT_SUCCESS( Status ))) {
|
||
IF_TDIDBG (TDI_DEBUG_NAMES) {
|
||
DbgPrint ("TdiOpenNetbiosEndpoint: FAILURE, IoStatusBlock.Status contains status code=%lx.\n", Status);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
} /* TdiOpenNetbiosAddress */
|
||
|
||
|
||
|
||
VOID
|
||
TdiReturnChainedReceives(
|
||
IN PVOID *TsduDescriptors,
|
||
IN ULONG NumberOfTsdus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Used by a TDI client to return ownership of a set of chained receive TSDUs
|
||
to the NDIS layer. This routine may only be called if the client took
|
||
ownership of the TSDUs by returning STATUS_PENDING to one of the
|
||
CHAINED_RECEIVE indications.
|
||
|
||
Arguments:
|
||
|
||
TsduDescriptors - An array of TSDU descriptors. Each descriptor was
|
||
provided in one of the CHAINED_RECEIVE indications. The descriptors
|
||
are actually pointers to the NDIS_PACKETS containing the TSDUs.
|
||
|
||
NumberOfTsdus - The count of TSDU descriptors in the TsduDescriptors array.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
--*/
|
||
|
||
{
|
||
NdisReturnPackets(
|
||
(PNDIS_PACKET *) TsduDescriptors,
|
||
(UINT) NumberOfTsdus
|
||
);
|
||
}
|
||
|
||
VOID
|
||
TdiInitialize(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The TDI initialization routine, since our DriverEntry isn't called.
|
||
If we're not already initialized we'll initialize our lists heads.
|
||
|
||
Arguments:
|
||
|
||
Nothing.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
// See if we're already initialized. If we're not,
|
||
// we won't have an initalized spinlock so we can't use that
|
||
// to serialize this. Instead, we interlocked increment a counter
|
||
// that is initially 0. If the counter goes to 1, we're the
|
||
// first one through here, so we'll do the initialization. Otherwise
|
||
// it's already been done, so we'll decrement the counter back
|
||
// to it's original state.
|
||
|
||
if (InterlockedIncrement(&TdiInitializationCount) == 1) {
|
||
|
||
// We're the first ones.
|
||
// Initialize the variables the register/deregister code uses.
|
||
|
||
KeInitializeSpinLock(&TDIListLock);
|
||
|
||
InitializeListHead(&PnpHandlerClientList);
|
||
|
||
InitializeListHead(&PnpHandlerProviderList);
|
||
|
||
InitializeListHead(&PnpHandlerRequestList);
|
||
|
||
NdisRegisterTdiCallBack(TdiRegisterDeviceObject, TdiPnPHandler);
|
||
|
||
#if DBG
|
||
//
|
||
// If a debug build store a limited number of messages.
|
||
//
|
||
|
||
DbgMsgInit();
|
||
|
||
#endif
|
||
|
||
|
||
} else {
|
||
|
||
// Already been done, just decrement the counter.
|
||
InterlockedDecrement(&TdiInitializationCount);
|
||
}
|
||
}
|
||
|