summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/wrapper/tdi.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/wrapper/tdi.c1737
1 files changed, 1737 insertions, 0 deletions
diff --git a/private/ntos/tdi/wrapper/tdi.c b/private/ntos/tdi/wrapper/tdi.c
new file mode 100644
index 000000000..b2a1805f7
--- /dev/null
+++ b/private/ntos/tdi/wrapper/tdi.c
@@ -0,0 +1,1737 @@
+/*++
+
+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 <ntos.h>
+#include <status.h>
+#include <tdikrnl.h>
+#include <ndis.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
+
+--*/
+
+{
+ //
+ // BUGBUG This should not be needed!
+ //
+
+ 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:
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->MinorFunction = TDI_ACCEPT;
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ case IOCTL_TDI_ACTION:
+
+ 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;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ 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;
+
+ //
+ // BUGBUG: Fill this in too?
+ //
+
+ request->ReturnConnectionInformation = NULL;
+
+ Status = STATUS_SUCCESS;
+
+ }
+ break;
+ }
+
+ case IOCTL_TDI_DISCONNECT:
+ {
+ 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->AssociatedIrp.SystemBuffer) {
+
+ 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;
+ PCHAR ptr;
+
+ if (Irp->AssociatedIrp.SystemBuffer) {
+
+ 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;
+ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >
+ sizeof (TDI_REQUEST_QUERY_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->AssociatedIrp.SystemBuffer) {
+
+ 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->AssociatedIrp.SystemBuffer) {
+
+ 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->AssociatedIrp.SystemBuffer) {
+
+ 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->AssociatedIrp.SystemBuffer) {
+
+ 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 (Irp->AssociatedIrp.SystemBuffer) {
+
+ 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->AssociatedIrp.SystemBuffer) {
+
+ 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:
+ {
+ 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 */
+
+
+VOID
+TdiMapBuffer(
+ IN PMDL MdlChain
+ )
+
+/*++
+
+Routine Description:
+
+ This routine ensures that the MappedSystemVa field of every MDL in an
+ MDL chain is valid; calling MmMapLockedPages where necessary.
+
+ !!! This routine no longer does anything, and should be removed!
+
+Arguments:
+
+ MdlChain - Pointer to a chain of MDLs describing the data to be mapped.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ MdlChain;
+
+ return;
+
+} /* TdiMapBuffer */
+
+
+VOID
+TdiUnmapBuffer(
+ IN PMDL MdlChain
+ )
+
+/*++
+
+Routine Description:
+
+ This routine restores the mapped status of every MDL in an MDL chain
+ where the MappedSystemVa field is equal to StartVa+ByteOffset.
+
+ !!! This routine no longer does anything, and should be removed!
+
+Arguments:
+
+ MdlChain - Pointer to a chain of MDLs describing the data to be unmapped.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ MdlChain;
+
+ return;
+
+} /* TdiUnmapBuffer */
+
+
+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.
+ //
+
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ 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;
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ 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.
+ }
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ 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;
+ }
+ Src = MmGetSystemAddressForMdl (SourceMdlChain);
+ 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;
+
+ //
+ // Skip Destination bytes.
+ //
+
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ 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;
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ 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.
+ }
+ Dest = MmGetSystemAddressForMdl (DestinationMdlChain);
+ 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 = MmGetSystemAddressForMdl (DestinationMdlChain);
+ 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
+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,
+ 0,
+ 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(&BindClientList);
+
+ InitializeListHead(&NetAddressClientList);
+
+ InitializeListHead(&BindProviderList);
+
+ InitializeListHead(&NetAddressProviderList);
+
+ InitializeListHead(&BindRequestList);
+
+ InitializeListHead(&NetAddressRequestList);
+
+ NdisRegisterTdiCallBack(TdiRegisterDeviceObject);
+
+ } else {
+
+ // Already been done, just decrement the counter.
+ InterlockedDecrement(&TdiInitializationCount);
+ }
+}
+