4376 lines
126 KiB
C
4376 lines
126 KiB
C
/*++
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tdipnp.c
|
|
|
|
Abstract:
|
|
|
|
TDI routines for supporting PnP in transports and transport clients.
|
|
|
|
Author:
|
|
|
|
Henry Sanders (henrysa) Oct. 10, 1995
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
henrysa 10-10-95 created
|
|
shreem 01-23-97 bug #33975
|
|
adube 01-01-01 maintenance mode - windows xp
|
|
|
|
Notes:
|
|
|
|
Change from the previous approach:
|
|
|
|
1. Processing the TDI_REQUEST is done in a different function.
|
|
2. Requests can be queued while another thread is notifying its clients/providers
|
|
3. These are then dequeued by the and run on a different thread using CTE functions.
|
|
|
|
--*/
|
|
|
|
#include <ntddk.h>
|
|
#include <ndis.h>
|
|
#include <tdi.h>
|
|
#include <tdikrnl.h>
|
|
#include <cxport.h>
|
|
#include <ndispnp.h>
|
|
#include "tdipnp.h"
|
|
#include "tdidebug.h"
|
|
|
|
#ifdef DBG
|
|
|
|
CHAR DbgMsgs[LOG_MSG_CNT][MAX_MSG_LEN];
|
|
UINT First, Last;
|
|
CTELock DbgLock;
|
|
|
|
ULONG TdiDebugEx = TDI_DEBUG_ERROR;
|
|
|
|
|
|
ULONG TdiMemLog =
|
|
//LOG_NOTIFY |
|
|
//LOG_REGISTER |
|
|
//LOG_POWER |
|
|
0;
|
|
|
|
ULONG TdiLogOutput = LOG_OUTPUT_BUFFER /*| LOG_OUTPUT_DEBUGGER*/;
|
|
|
|
#endif
|
|
|
|
KSPIN_LOCK TDIListLock;
|
|
|
|
|
|
LIST_ENTRY PnpHandlerRequestList;
|
|
LIST_ENTRY PnpHandlerProviderList;
|
|
LIST_ENTRY PnpHandlerClientList;
|
|
PTDI_OPEN_BLOCK OpenList = NULL;
|
|
BOOLEAN PnpHandlerRequestInProgress;
|
|
PETHREAD PnpHandlerRequestThread;
|
|
UINT PrevRequestType = 0;
|
|
ULONG ProvidersRegistered = 0;
|
|
ULONG ProvidersReady = 0;
|
|
ULONG EventScheduled = 0;
|
|
|
|
|
|
// structure private to tdipnp.c. used to marshall parms to a CTE event
|
|
|
|
typedef struct _TDI_EXEC_PARAMS {
|
|
LIST_ENTRY Linkage;
|
|
UINT Signature;
|
|
PLIST_ENTRY ClientList;
|
|
PLIST_ENTRY ProviderList;
|
|
PLIST_ENTRY RequestList;
|
|
TDI_SERIALIZED_REQUEST Request;
|
|
PETHREAD *CurrentThread;
|
|
CTEEvent *RequestCTEEvent;
|
|
PBOOLEAN SerializeFlag;
|
|
BOOLEAN ResetSerializeFlag;
|
|
PVOID pCallersAddress;
|
|
PVOID pCallersCaller;
|
|
PETHREAD pCallerThread;
|
|
|
|
} TDI_EXEC_PARAMS, *PTDI_EXEC_PARAMS;
|
|
|
|
typedef struct {
|
|
PVOID ExecParm;
|
|
UINT Type;
|
|
PVOID Element;
|
|
PVOID Thread;
|
|
} EXEC_PARM;
|
|
|
|
// Keep a short list of current and last few requests that TDI has processed.
|
|
// (Debug purposes only. Current request isn't store anyware during processing)
|
|
#define EXEC_CNT 8
|
|
EXEC_PARM TrackExecs[EXEC_CNT];
|
|
int NextExec;
|
|
|
|
EXEC_PARM TrackExecCompletes[EXEC_CNT];
|
|
int NextExecComplete;
|
|
|
|
CTEEvent BindEvent;
|
|
CTEEvent AddressEvent;
|
|
|
|
CTEEvent PnpHandlerEvent;
|
|
|
|
PWSTR StrRegTdiBindList = L"Bind";
|
|
PWSTR StrRegTdiLinkage = L"\\Linkage";
|
|
PWSTR StrRegTdiBindingsBasicPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
|
|
|
|
#define MAX_UNICODE_BUFLEN 256
|
|
|
|
// private function prototypes
|
|
|
|
NTSYSAPI NTSTATUS NTAPI
|
|
NtClose(
|
|
IN HANDLE Handle
|
|
);
|
|
|
|
NTSTATUS
|
|
TdiExecuteRequest(
|
|
CTEEvent *Event,
|
|
PVOID pTdiExecParams
|
|
);
|
|
|
|
BOOLEAN
|
|
TdipIsSzInMultiSzSafe (
|
|
IN PCWSTR pszSearchString,
|
|
IN PCWSTR pmsz);
|
|
|
|
VOID
|
|
TdipRemoveMultiSzFromSzArray (
|
|
IN PWSTR pmszToRemove,
|
|
IN OUT PWSTR* pszArray,
|
|
IN ULONG ItemsInArray,
|
|
OUT ULONG* pRemainingItems);
|
|
|
|
VOID
|
|
TdipRemoveMultiSzFromMultiSz (
|
|
IN PCWSTR pmszToRemove,
|
|
IN OUT PWSTR pmszToModify);
|
|
|
|
NTSTATUS
|
|
TdipAddMultiSzToMultiSz(
|
|
IN PUNICODE_STRING pmszAdd,
|
|
IN PCWSTR pmszModify,
|
|
OUT PWSTR* ppmszOut);
|
|
|
|
|
|
VOID
|
|
TdipGetMultiSZList(
|
|
PWSTR **ListPointer,
|
|
PWSTR BaseKeyName,
|
|
PUNICODE_STRING DeviceName,
|
|
PWSTR Linkage,
|
|
PWSTR ParameterKeyName,
|
|
PUINT NumEntries
|
|
);
|
|
|
|
BOOLEAN
|
|
TdipMultiSzStrStr(
|
|
PWSTR *TdiClientBindingList,
|
|
PUNICODE_STRING DeviceName
|
|
);
|
|
|
|
BOOLEAN
|
|
TdipBuildProviderList(
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyElement
|
|
);
|
|
|
|
PTDI_PROVIDER_RESOURCE
|
|
LocateProviderContext(
|
|
PUNICODE_STRING ProviderName
|
|
);
|
|
|
|
|
|
// end private protos
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
TdipPrintMultiSz (
|
|
IN PCWSTR pmsz);
|
|
|
|
VOID
|
|
TdiDumpAddress(
|
|
IN PTA_ADDRESS Addr
|
|
)
|
|
{
|
|
int j;
|
|
|
|
TDI_DEBUG(ADDRESS, ("len %d ", Addr->AddressLength));
|
|
|
|
if (Addr->AddressType == TDI_ADDRESS_TYPE_IP) {
|
|
TDI_DEBUG(ADDRESS, ("IP %d.%d.%d.%d\n",
|
|
Addr->Address[2],
|
|
Addr->Address[3],
|
|
Addr->Address[4],
|
|
Addr->Address[5]));
|
|
} else if (Addr->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
|
|
if (Addr->Address[2] == '\0') {
|
|
TDI_DEBUG(ADDRESS, ("NETBIOS reserved %2x %2x %2x %2x %2x %2x\n",
|
|
(ULONG)(Addr->Address[12]),
|
|
(ULONG)(Addr->Address[13]),
|
|
(ULONG)(Addr->Address[14]),
|
|
(ULONG)(Addr->Address[15]),
|
|
(ULONG)(Addr->Address[16]),
|
|
(ULONG)(Addr->Address[17])));
|
|
} else {
|
|
TDI_DEBUG(ADDRESS, ("NETBIOS %.16s\n", Addr->Address+2));
|
|
}
|
|
} else {
|
|
TDI_DEBUG(ADDRESS, ("type %d ", Addr->AddressType));
|
|
for (j = 0; j < Addr->AddressLength; j++) {
|
|
TDI_DEBUG(ADDRESS, ("%2x ", (ULONG)(Addr->Address[j])));
|
|
}
|
|
TDI_DEBUG(ADDRESS, ("\n"));
|
|
}
|
|
}
|
|
#else
|
|
#define TdiDumpAddress(d) (0)
|
|
#define TdipPrintMultiSz(p)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
TdiNotifyPnpClientList (
|
|
PLIST_ENTRY ListHead,
|
|
PVOID Info,
|
|
BOOLEAN Added
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
ListHead - Head of list to walk.
|
|
Info - Information describing the provider that changed.
|
|
Added - True if a provider was added, false otherwise
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY Current;
|
|
PTDI_PROVIDER_COMMON ProviderCommon;
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
|
|
PTDI_PROVIDER_RESOURCE Provider;
|
|
NTSTATUS Status, ReturnStatus = STATUS_SUCCESS;
|
|
BOOLEAN bStatus = FALSE;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiNotifyPnpClientList\n"));
|
|
|
|
Current = ListHead->Flink;
|
|
|
|
// The Info parameter is actually a pointer to a PROVIDER_COMMON
|
|
// structure, so get back to that so that we can find out what kind of
|
|
// provider this is.
|
|
|
|
ProviderCommon = (PTDI_PROVIDER_COMMON)Info;
|
|
|
|
Provider = CONTAINING_RECORD(
|
|
ProviderCommon,
|
|
TDI_PROVIDER_RESOURCE,
|
|
Common
|
|
);
|
|
|
|
if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
|
|
TDI_DEBUG(PROVIDERS, ("Got new (de)registration for device %wZ\n", &Provider->Specific.Device.DeviceName));
|
|
} else if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
|
|
TDI_DEBUG(PROVIDERS, ("Got new (de)registration for address "));
|
|
TdiDumpAddress(&Provider->Specific.NetAddress.Address);
|
|
}
|
|
|
|
|
|
// Walk the input client list, and for every element in it
|
|
// notify the client.
|
|
|
|
while (Current != ListHead) {
|
|
|
|
NotifyPnpElement = CONTAINING_RECORD(
|
|
Current,
|
|
TDI_NOTIFY_PNP_ELEMENT,
|
|
Common.Linkage
|
|
);
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
Provider->Common.pNotifyElement = NotifyPnpElement; //Debugging info
|
|
|
|
if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
|
|
|
|
|
|
if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
|
|
|
|
if (Added) {
|
|
|
|
if (NotifyPnpElement->Bind.BindHandler) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("V1 bind %wZ to %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->Bind.BindHandler))(
|
|
&Provider->Specific.Device.DeviceName
|
|
);
|
|
}
|
|
} else {
|
|
if (NotifyPnpElement->Bind.UnbindHandler) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("V1 unbind %wZ from %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->Bind.UnbindHandler))(
|
|
&Provider->Specific.Device.DeviceName
|
|
);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
if (NULL != NotifyPnpElement->BindingHandler) {
|
|
// Remove any providers from the list that we are supposed
|
|
// to ignore.
|
|
//
|
|
TdipRemoveMultiSzFromSzArray (
|
|
NotifyPnpElement->ListofBindingsToIgnore,
|
|
NotifyPnpElement->ListofProviders,
|
|
NotifyPnpElement->NumberofEntries,
|
|
&NotifyPnpElement->NumberofEntries);
|
|
|
|
// This is a device object provider.
|
|
// This must be a notify bind element.
|
|
|
|
if (TdipMultiSzStrStr (
|
|
NotifyPnpElement->ListofProviders,
|
|
&Provider->Specific.Device.DeviceName
|
|
)) {
|
|
|
|
if (Added) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Bind %wZ to %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_ADD,
|
|
&Provider->Specific.Device.DeviceName,
|
|
(PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
|
|
);
|
|
} else {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Unbind %wZ from %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_DEL,
|
|
&Provider->Specific.Device.DeviceName,
|
|
(PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(BIND, ("The Client %wZ wasnt interested in this Provider %wZ!\r\n",
|
|
&NotifyPnpElement->ElementName, &Provider->Specific.Device.DeviceName));
|
|
}
|
|
}
|
|
}
|
|
} else if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
|
|
|
|
// This is a notify net address element. If this is
|
|
// an address coming in, call the add address handler,
|
|
// otherwise call delete address handler.
|
|
|
|
|
|
if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
|
|
|
|
if (Added && (NULL != NotifyPnpElement->AddressElement.AddHandler)) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Add address v1 %wZ to %wZ\n",
|
|
&Provider->DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->AddressElement.AddHandler))(
|
|
&Provider->Specific.NetAddress.Address
|
|
);
|
|
|
|
} else if (NULL != NotifyPnpElement->AddressElement.DeleteHandler) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Del address v1 %wZ from %wZ\n",
|
|
&Provider->DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->AddressElement.DeleteHandler))(
|
|
&Provider->Specific.NetAddress.Address
|
|
);
|
|
}
|
|
} else {
|
|
|
|
|
|
if (Added && (NULL != NotifyPnpElement->AddressElement.AddHandlerV2)) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Add address %wZ to %wZ\n",
|
|
&Provider->DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->AddressElement.AddHandlerV2))(
|
|
&Provider->Specific.NetAddress.Address,
|
|
&Provider->DeviceName,
|
|
Provider->Context2
|
|
);
|
|
|
|
TDI_DEBUG(ADDRESS, ("Address Handler Called: ADD!\n"));
|
|
|
|
} else if (NULL != NotifyPnpElement->AddressElement.DeleteHandlerV2) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Del address %wZ from %wZ\n",
|
|
&Provider->DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->AddressElement.DeleteHandlerV2))(
|
|
&Provider->Specific.NetAddress.Address,
|
|
&Provider->DeviceName,
|
|
Provider->Context2 );
|
|
}
|
|
}
|
|
|
|
} else if (Provider->Common.Type == TDI_RESOURCE_POWER) {
|
|
|
|
// RESOURCE_POWER
|
|
|
|
if (NotifyPnpElement->PnpPowerHandler) {
|
|
|
|
TDI_DEBUG(POWER, ("PnPPower Handler Called!\n"));
|
|
|
|
TDI_LOG(LOG_NOTIFY | LOG_POWER,
|
|
("Power event %d to %wZ\n",
|
|
Provider->PnpPowerEvent->NetEvent,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
Status = (*(NotifyPnpElement->PnpPowerHandler)) (
|
|
&Provider->Specific.Device.DeviceName,
|
|
Provider->PnpPowerEvent,
|
|
Provider->Context1,
|
|
Provider->Context2
|
|
);
|
|
if (STATUS_PENDING == Status) {
|
|
|
|
TDI_DEBUG(POWER, ("Client returned PENDING (%d) ++\n", Provider->PowerHandlers));
|
|
ReturnStatus = STATUS_PENDING;
|
|
|
|
} else {
|
|
//
|
|
// Record the return value only if it is not SUCCESS or PENDING.
|
|
//
|
|
if (STATUS_SUCCESS != Status) {
|
|
Provider->Status = Status;
|
|
TDI_DEBUG(POWER, ("Client: %wZ returned %x\n", &NotifyPnpElement->ElementName, Provider->Status));
|
|
//
|
|
// For easier routing of failures.
|
|
//
|
|
DbgPrint("Client: %wZ returned %x\n", &NotifyPnpElement->ElementName, Provider->Status);
|
|
}
|
|
|
|
InterlockedDecrement(&Provider->PowerHandlers);
|
|
|
|
TDI_DEBUG(POWER, ("Client returned Immediately (%d) : ++\n", Provider->PowerHandlers));
|
|
|
|
}
|
|
|
|
}
|
|
} else if (Provider->Common.Type == TDI_RESOURCE_PROVIDER && Provider->ProviderReady) {
|
|
//
|
|
// First inform the clients about this provider and then if
|
|
// ProvidersRegistered == ProvidersReady call again with NULL.
|
|
//
|
|
|
|
if ((TDI_VERSION_ONE != NotifyPnpElement->TdiVersion) &&
|
|
(NULL != NotifyPnpElement->BindingHandler)) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("%wZ ready, notify %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_PROVIDERREADY,
|
|
&Provider->Specific.Device.DeviceName,
|
|
NULL
|
|
);
|
|
|
|
if (ProvidersReady == ProvidersRegistered) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("NETREADY to %wZ\n", &NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_NETREADY,
|
|
NULL,
|
|
NULL
|
|
);
|
|
} else {
|
|
|
|
TDI_DEBUG(BIND, ("************** Registered:%d + Ready %d\n", ProvidersRegistered, ProvidersReady));
|
|
|
|
}
|
|
} else {
|
|
|
|
TDI_DEBUG(PROVIDERS, ("%wZ has a NULL BindHandler\n", &NotifyPnpElement->ElementName));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// Get the next one.
|
|
|
|
Current = Current->Flink;
|
|
|
|
Provider->Common.pNotifyElement = NULL; //Debugging info
|
|
Provider->Common.ReturnStatus = ReturnStatus; // Debugging info
|
|
|
|
}
|
|
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiNotifyPnpClientList : %lx\n", ReturnStatus));
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
TdiNotifyNewPnpClient(
|
|
PLIST_ENTRY ListHead,
|
|
PVOID Info
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a new client is added and we want to notify it of existing
|
|
providers. The client can be for either binds or net addresses. We
|
|
walk the specified input list, and notify the client about each entry in
|
|
it.
|
|
|
|
Arguments:
|
|
|
|
ListHead - Head of list to walk.
|
|
Info - Information describing the new client to be notified.
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
PTDI_NOTIFY_COMMON NotifyCommon;
|
|
PTDI_PROVIDER_RESOURCE Provider;
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
|
|
PWSTR MultiSZBindList = NULL;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiNotifyNewPnpClient\n"));
|
|
|
|
CurrentEntry = ListHead->Flink;
|
|
|
|
// The info is actually a pointer to a client notify element. Cast
|
|
// it to the common type.
|
|
|
|
NotifyCommon = (PTDI_NOTIFY_COMMON)Info;
|
|
|
|
NotifyPnpElement = CONTAINING_RECORD(
|
|
NotifyCommon,
|
|
TDI_NOTIFY_PNP_ELEMENT,
|
|
Common
|
|
);
|
|
|
|
TDI_DEBUG(CLIENTS, ("New handler set registered by %wZ\n", &NotifyPnpElement->ElementName));
|
|
|
|
// Walk the input provider list, and for every element in it notify
|
|
// the new client.
|
|
|
|
while (CurrentEntry != ListHead) {
|
|
|
|
// If the new client is for bind notifys, set up to call it's bind
|
|
// handler.
|
|
|
|
// Put the current provider element into the proper form.
|
|
|
|
Provider = CONTAINING_RECORD(
|
|
CurrentEntry,
|
|
TDI_PROVIDER_RESOURCE,
|
|
Common.Linkage
|
|
);
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
|
|
if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion ) {
|
|
|
|
if (NotifyPnpElement->Bind.BindHandler) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("V1 bind %wZ to %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->Bind.BindHandler))(
|
|
&Provider->Specific.Device.DeviceName
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (NULL != NotifyPnpElement->BindingHandler) {
|
|
|
|
// This is a bind notify client.
|
|
if (TdipMultiSzStrStr(
|
|
NotifyPnpElement->ListofProviders,
|
|
&Provider->Specific.Device.DeviceName
|
|
)) {
|
|
|
|
|
|
TDI_DEBUG(BIND, ("Telling new handlers to bind to %wZ\n", &Provider->Specific.Device.DeviceName));
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("bind(new) %wZ to %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_ADD,
|
|
&Provider->Specific.Device.DeviceName,
|
|
(PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
|
|
);
|
|
|
|
} else {
|
|
TDI_DEBUG(BIND, ("The Client %wZ wasnt interested in this Provider %wZ!\r\n",
|
|
&NotifyPnpElement->ElementName, &Provider->Specific.Device.DeviceName));
|
|
}
|
|
|
|
} else {
|
|
TDI_DEBUG(BIND, ("The client %wZ has a NULL Binding Handler\n", &NotifyPnpElement->ElementName));
|
|
}
|
|
}
|
|
|
|
} else if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
|
|
// This is an address notify client.
|
|
// cant be TDI_RESOURCE_POWER coz we never put it on the list! - ShreeM
|
|
|
|
if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
|
|
|
|
if (NULL != NotifyPnpElement->AddressElement.AddHandler) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Add address v1 %wZ to %wZ\n",
|
|
&Provider->DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->AddressElement.AddHandler))(
|
|
&Provider->Specific.NetAddress.Address
|
|
);
|
|
}
|
|
} else {
|
|
|
|
|
|
|
|
if (NotifyPnpElement->AddressElement.AddHandlerV2) {
|
|
|
|
TdiDumpAddress(&Provider->Specific.NetAddress.Address);
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Add address(2) %wZ to %wZ\n",
|
|
&Provider->DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->AddressElement.AddHandlerV2))(
|
|
&Provider->Specific.NetAddress.Address,
|
|
&Provider->DeviceName,
|
|
Provider->Context2
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// And do the next one.
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
|
|
}
|
|
|
|
//
|
|
// Now the providers who are ready.
|
|
//
|
|
|
|
if (NULL == NotifyPnpElement->BindingHandler) {
|
|
//
|
|
// If the Bindhandler is NULL, further action is pointless.
|
|
//
|
|
TDI_DEBUG(PROVIDERS, ("%wZ has a NULL BindHandler!!\n", &NotifyPnpElement->ElementName));
|
|
TDI_DEBUG(FUNCTION, ("-- TdiNotifyNewPnpClient\n"));
|
|
return;
|
|
|
|
}
|
|
|
|
if (TDI_VERSION_ONE == NotifyPnpElement->TdiVersion) {
|
|
//
|
|
// If the Bindhandler is NULL, further action is pointless.
|
|
//
|
|
TDI_DEBUG(PROVIDERS, ("This is a TDI v.1 client!\n"));
|
|
TDI_DEBUG(FUNCTION, ("-- TdiNotifyNewPnpClient\n"));
|
|
return;
|
|
}
|
|
|
|
// Otherwise, we can start the loop again.
|
|
// Yes, maintaining different lists for addresses, providers, and devices
|
|
// might be more efficient and I will do this later.
|
|
|
|
CurrentEntry = ListHead->Flink;
|
|
|
|
while (CurrentEntry != ListHead) {
|
|
|
|
Provider = CONTAINING_RECORD(
|
|
CurrentEntry,
|
|
TDI_PROVIDER_RESOURCE,
|
|
Common.Linkage
|
|
);
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
|
|
|
|
if (Provider->Common.Type == TDI_RESOURCE_PROVIDER && Provider->ProviderReady) {
|
|
|
|
//
|
|
// First inform the clients about this provider and then if
|
|
// ProvidersRegistered == ProvidersReady call again with NULL.
|
|
//
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("%wZ ready2, notify %wZ\n",
|
|
&Provider->Specific.Device.DeviceName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_PROVIDERREADY,
|
|
&Provider->Specific.Device.DeviceName,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
// And do the next one.
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
|
|
}
|
|
|
|
if (ProvidersReady == ProvidersRegistered) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("NETREADY2 to %wZ\n", &NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_NETREADY,
|
|
NULL,
|
|
NULL
|
|
);
|
|
} else {
|
|
|
|
TDI_DEBUG(PROVIDERS, ("Provider Ready Status: Registered:%d + Ready:%d\n", ProvidersRegistered, ProvidersReady));
|
|
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiNotifyNewPnpClient\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TdiNotifyAddresses(
|
|
PLIST_ENTRY ListHead,
|
|
PVOID Info
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a client wants to know about all the TDI Addresses
|
|
|
|
Arguments:
|
|
|
|
ListHead - Head of list to walk.
|
|
Info - Information describing the new client to be notified.
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
PTDI_NOTIFY_COMMON NotifyCommon;
|
|
PTDI_PROVIDER_RESOURCE Provider;
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiNotifyAddresses\n"));
|
|
|
|
CurrentEntry = ListHead->Flink;
|
|
|
|
// The info is actually a pointer to a client notify element. Cast
|
|
// it to the common type.
|
|
|
|
NotifyCommon = (PTDI_NOTIFY_COMMON)Info;
|
|
|
|
NotifyPnpElement = CONTAINING_RECORD(
|
|
NotifyCommon,
|
|
TDI_NOTIFY_PNP_ELEMENT,
|
|
Common
|
|
);
|
|
|
|
TDI_DEBUG(CLIENTS, ("%wZ wants to know about all the addresses\n", &NotifyPnpElement->ElementName));
|
|
|
|
// Walk the input provider list, and for every element in it notify
|
|
// the new client.
|
|
|
|
while (CurrentEntry != ListHead) {
|
|
|
|
// If the new client is for bind notifys, set up to call it's bind
|
|
// handler.
|
|
|
|
// Put the current provider element into the proper form.
|
|
|
|
Provider = CONTAINING_RECORD(
|
|
CurrentEntry,
|
|
TDI_PROVIDER_RESOURCE,
|
|
Common.Linkage
|
|
);
|
|
|
|
if (Provider->Common.Type == TDI_RESOURCE_NET_ADDRESS) {
|
|
|
|
if (NotifyPnpElement->AddressElement.AddHandlerV2) {
|
|
|
|
TDI_DEBUG(ADDRESS, ("Add Address Handler\n"));
|
|
|
|
TDI_DEBUG(CLIENTS, ("Telling new handlers about address: "));
|
|
TdiDumpAddress(&Provider->Specific.NetAddress.Address);
|
|
|
|
(*(NotifyPnpElement->AddressElement.AddHandlerV2))(
|
|
&Provider->Specific.NetAddress.Address,
|
|
&Provider->DeviceName,
|
|
Provider->Context2
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
// And do the next one.
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiNotifyAddresses\n"));
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
TdiHandlePnpOperation(
|
|
PLIST_ENTRY ListHead,
|
|
PVOID Info
|
|
)
|
|
{
|
|
PLIST_ENTRY Current;
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
|
|
PTDI_PROVIDER_RESOURCE ProviderElement;
|
|
PTDI_NCPA_BINDING_INFO NCPABindingInfo;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NET_PNP_EVENT NetEvent;
|
|
ULONG Operation;
|
|
BOOLEAN DeviceRegistered = FALSE;
|
|
BOOLEAN ClientFound = FALSE;
|
|
UINT NumberofEntries = 0;
|
|
|
|
TDI_DEBUG(FUNCTION, ("---------------------------> ++ TdiHandlePnpOperation!!\n"));
|
|
|
|
ASSERT(NULL != Info);
|
|
ASSERT(NULL != ListHead);
|
|
|
|
Current = ListHead->Flink;
|
|
|
|
// The Info parameter is actually a pointer to TDI_NCPA_BINDING_INFO
|
|
// structure.
|
|
|
|
NCPABindingInfo = (PTDI_NCPA_BINDING_INFO) Info;
|
|
Operation = (ULONG) NCPABindingInfo->PnpOpcode;
|
|
|
|
// Walk the input client list, and see if that is the client we are looking for.
|
|
|
|
while (Current != ListHead) {
|
|
|
|
NotifyPnpElement = CONTAINING_RECORD(
|
|
Current,
|
|
TDI_NOTIFY_PNP_ELEMENT,
|
|
Common.Linkage
|
|
);
|
|
|
|
|
|
if (!RtlCompareUnicodeString(
|
|
NCPABindingInfo->TdiClientName,
|
|
&NotifyPnpElement->ElementName,
|
|
TRUE)
|
|
) {
|
|
TDI_DEBUG(NCPA, ("Found the TDI client for the message from NCPA\n"));
|
|
ClientFound = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
Current = Current->Flink;
|
|
|
|
}
|
|
|
|
if (!ClientFound) {
|
|
//
|
|
// Cant do much if the client's handlers are not registered.
|
|
//
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Let's update the ListofProviders for this client.
|
|
// Add a new provider to the Client's list of Providers...
|
|
//
|
|
if (NotifyPnpElement->ListofProviders) {
|
|
|
|
TDI_DEBUG(NCPA, ("Before this BIND - Client %wZ was interested in %lx Providers\n", &NotifyPnpElement->ElementName,
|
|
NotifyPnpElement->NumberofEntries));
|
|
|
|
ExFreePool(NotifyPnpElement->ListofProviders);
|
|
|
|
TDI_DEBUG(NCPA, ("Freed the previous List of Providers\n"));
|
|
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(NCPA, ("List of providers was NULL for %wZ\n", &NotifyPnpElement->ElementName));
|
|
|
|
}
|
|
|
|
TdipBuildProviderList(
|
|
(PTDI_NOTIFY_PNP_ELEMENT) NotifyPnpElement
|
|
);
|
|
|
|
TDI_DEBUG(NCPA, ("Built New BindList - %wZ is interested in %lx Providers after BIND\n", &NotifyPnpElement->ElementName,
|
|
NotifyPnpElement->NumberofEntries));
|
|
|
|
}
|
|
|
|
//
|
|
// If it is a reconfigure, or an add or delete ignore binding,
|
|
// don't see if device (provider) is registered.
|
|
//
|
|
if ((RECONFIGURE == Operation) || (ADD_IGNORE_BINDING == Operation) ||
|
|
(DEL_IGNORE_BINDING == Operation))
|
|
{
|
|
goto DeviceNotRequired;
|
|
}
|
|
|
|
//
|
|
// If we are here, the client exists. Check if the provider has registered the device
|
|
//
|
|
|
|
Current = PnpHandlerProviderList.Flink;
|
|
|
|
while (Current != &PnpHandlerProviderList) {
|
|
|
|
ProviderElement = CONTAINING_RECORD(
|
|
Current,
|
|
TDI_PROVIDER_RESOURCE,
|
|
Common.Linkage
|
|
);
|
|
|
|
if (ProviderElement->Common.Type != TDI_RESOURCE_DEVICE) {
|
|
Current = Current->Flink;
|
|
continue;
|
|
}
|
|
|
|
if (!RtlCompareUnicodeString(NCPABindingInfo->TdiProviderName,
|
|
&ProviderElement->Specific.Device.DeviceName,
|
|
TRUE)) {
|
|
TDI_DEBUG(NCPA, ("Provider is registered with TDI\n"));
|
|
DeviceRegistered = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
Current = Current->Flink;
|
|
|
|
}
|
|
|
|
if (!DeviceRegistered) {
|
|
|
|
if (NULL != NotifyPnpElement->BindingHandler) {
|
|
TDI_LOG(LOG_NOTIFY,
|
|
("Device is not registered, doing OP_UPDATE, %wZ to %wZ\n",
|
|
NCPABindingInfo->TdiProviderName,
|
|
&NotifyPnpElement->ElementName));
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_UPDATE,
|
|
NCPABindingInfo->TdiProviderName,
|
|
(PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
|
|
);
|
|
} else {
|
|
TDI_DEBUG(NCPA, ("Device is not registered, the BindHandler was NULL\n"));
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DeviceNotRequired:
|
|
|
|
//
|
|
// We need to manufacture a NET_PNP_EVENT here.
|
|
//
|
|
RtlZeroMemory (NetEvent.TdiReserved, sizeof(NetEvent.TdiReserved));
|
|
|
|
//
|
|
// Depending on the NetEvent, we call a different handler.
|
|
//
|
|
switch (Operation) {
|
|
|
|
case BIND:
|
|
//
|
|
// First check if the TDI Client is interested in the Provider
|
|
//
|
|
|
|
if (TdipMultiSzStrStr(
|
|
NotifyPnpElement->ListofProviders,
|
|
&ProviderElement->Specific.Device.DeviceName
|
|
)) {
|
|
TDI_DEBUG(NCPA, ("The Client %wZ is interested in provider %wZ\n", &NotifyPnpElement->ElementName,
|
|
&ProviderElement->Specific.Device.DeviceName
|
|
));
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(NCPA, ("RANDOM BIND CALL!!!\n"));
|
|
TDI_DEBUG(NCPA, ("The Client %wZ is NOT interested in provider %wZ\n", &NotifyPnpElement->ElementName,
|
|
&ProviderElement->Specific.Device.DeviceName
|
|
));
|
|
}
|
|
|
|
|
|
if (NULL != NotifyPnpElement->BindingHandler) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Pnp Bind %wZ to %wZ\n",
|
|
NCPABindingInfo->TdiProviderName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_ADD,
|
|
NCPABindingInfo->TdiProviderName,
|
|
(PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
|
|
);
|
|
//
|
|
// Here we should also update the NotifyElement's buffer.
|
|
//
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(NCPA, ("The BindHandler was NULL\n"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UNBIND:
|
|
|
|
//
|
|
// The plan is to do a QueryRemove first and then call UnBind.
|
|
//
|
|
|
|
if (NotifyPnpElement->PnpPowerHandler) {
|
|
|
|
TDI_DEBUG(POWER, ("UNBind Handler Called!: First QueryRemoveDevice\n"));
|
|
|
|
NetEvent.NetEvent = NetEventQueryRemoveDevice;
|
|
NetEvent.Buffer = NULL;
|
|
NetEvent.BufferLength = 0;
|
|
|
|
// The TDI Client should look at the OpCode in NetEvent and decide how to use the buffer.
|
|
Status = (*(NotifyPnpElement->PnpPowerHandler)) (
|
|
NCPABindingInfo->TdiProviderName,
|
|
&NetEvent,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (STATUS_PENDING == Status) {
|
|
TDI_DEBUG(POWER, ("Client returned PENDING for QueryPower!\n"));
|
|
//DbgBreakPoint();
|
|
}
|
|
} else {
|
|
TDI_DEBUG(NCPA, ("The PnpPowerHandler was NULL\n"));
|
|
|
|
}
|
|
|
|
//
|
|
// OK, now call the UNBIND HANDLER anyway
|
|
//
|
|
|
|
case UNBIND_FORCE:
|
|
|
|
// RDR returns PENDING all the time, we need a mechanism to fix this.
|
|
// if (((STATUS_PENDING == Status) || (STATUS_SUCCESS == Status)) && (NULL != NotifyPnpElement->BindingHandler)) {
|
|
if ((STATUS_SUCCESS == Status) && (NULL != NotifyPnpElement->BindingHandler)) {
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Pnp Unbind %wZ from %wZ\n",
|
|
NCPABindingInfo->TdiProviderName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
(*(NotifyPnpElement->BindingHandler))(
|
|
TDI_PNP_OP_DEL,
|
|
NCPABindingInfo->TdiProviderName,
|
|
(PWSTR) (NotifyPnpElement->ListofProviders + NotifyPnpElement->NumberofEntries)
|
|
);
|
|
} else {
|
|
TDI_DEBUG(NCPA, ("The BindHandler was NULL\n"));
|
|
}
|
|
|
|
break;
|
|
|
|
case RECONFIGURE:
|
|
|
|
//
|
|
// If the Reconfigure Buffer is NULL, we are notifying it of a NetEventBindList
|
|
// Otherwise we are notifying it of a NetEventReconfig. Need to do the dirty work
|
|
// of setting up the NET_PNP_EVENT accordingly.
|
|
//
|
|
TDI_DEBUG(POWER, ("Reconfigure Called.\n"));
|
|
|
|
//
|
|
// If the ReconfigBufferLength greater than 0, its Reconfig
|
|
//
|
|
if (NCPABindingInfo->ReconfigBufferSize) {
|
|
|
|
NetEvent.BufferLength = NCPABindingInfo->ReconfigBufferSize;
|
|
NetEvent.Buffer = NCPABindingInfo->ReconfigBuffer;
|
|
NetEvent.NetEvent = NetEventReconfigure;
|
|
|
|
} else {
|
|
//
|
|
// Else, its a BindOrder change
|
|
//
|
|
|
|
NetEvent.BufferLength = NCPABindingInfo->BindList->Length;
|
|
NetEvent.Buffer = NCPABindingInfo->BindList->Buffer;
|
|
NetEvent.NetEvent = NetEventBindList;
|
|
|
|
}
|
|
|
|
|
|
if (NotifyPnpElement->PnpPowerHandler) {
|
|
|
|
// The TDI Client should look at the OpCode in NetEvent and decide how to use the buffer.
|
|
|
|
TDI_LOG(LOG_NOTIFY, ("Pnp Reconfig %wZ to %wZ\n",
|
|
NCPABindingInfo->TdiProviderName,
|
|
&NotifyPnpElement->ElementName));
|
|
|
|
Status = (*(NotifyPnpElement->PnpPowerHandler)) (
|
|
NCPABindingInfo->TdiProviderName,
|
|
&NetEvent,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (STATUS_PENDING == Status) {
|
|
TDI_DEBUG(POWER, ("Client returned PENDING for QueryPower!\n"));
|
|
//DbgBreakPoint();
|
|
}
|
|
|
|
} else {
|
|
TDI_DEBUG(NCPA, ("The PnpPowerHandler was NULL\n"));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ADD_IGNORE_BINDING:
|
|
{
|
|
// We are being told to add a binding to a list of bindings
|
|
// to ignore for this client. These are bindings we will
|
|
// not indicate to the client.
|
|
//
|
|
PWSTR pmszNewIgnoreList;
|
|
|
|
ASSERT (NCPABindingInfo->BindList);
|
|
|
|
// If a non-null bindlist was given...
|
|
if (NCPABindingInfo->BindList)
|
|
{
|
|
TDI_DEBUG(BIND, ("Adding the following multi-sz to the ignore list\n"));
|
|
//TdipPrintMultiSz (NCPABindingInfo->BindList->Buffer);
|
|
|
|
// We need to add some bindings to our list of
|
|
// bindings to ignore.
|
|
//
|
|
TdipAddMultiSzToMultiSz (NCPABindingInfo->BindList,
|
|
NotifyPnpElement->ListofBindingsToIgnore,
|
|
&pmszNewIgnoreList);
|
|
|
|
if (pmszNewIgnoreList)
|
|
{
|
|
// If we have a new list, free the old one.
|
|
//
|
|
if (NotifyPnpElement->ListofBindingsToIgnore)
|
|
{
|
|
ExFreePool (NotifyPnpElement->ListofBindingsToIgnore);
|
|
}
|
|
NotifyPnpElement->ListofBindingsToIgnore = pmszNewIgnoreList;
|
|
|
|
TDI_DEBUG(BIND, ("Printing new ignore list\n"));
|
|
TdipPrintMultiSz (NotifyPnpElement->ListofBindingsToIgnore);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case DEL_IGNORE_BINDING:
|
|
|
|
// We are being told to remove bindings from a list of bindings
|
|
// to ignore for this client. These are bindings we will
|
|
// now indicate to the client if we need to.
|
|
//
|
|
|
|
// If we don't have a current list of bindings to ignore
|
|
// or the bindlist sent was NULL then there is no work to do.
|
|
// We assert on a NULL BindList because it shouldn't happen.
|
|
|
|
ASSERT(NCPABindingInfo->BindList);
|
|
if (NotifyPnpElement->ListofBindingsToIgnore &&
|
|
NCPABindingInfo->BindList)
|
|
{
|
|
TDI_DEBUG(BIND, ("Removing the following multi-sz from the ignore list\n"));
|
|
//TdipPrintMultiSz (NCPABindingInfo->BindList->Buffer);
|
|
|
|
// We need to remove some bindings from our list of bindings
|
|
// to ignore.
|
|
//
|
|
TdipRemoveMultiSzFromMultiSz (NCPABindingInfo->BindList->Buffer,
|
|
NotifyPnpElement->ListofBindingsToIgnore);
|
|
|
|
// If the list of bindings to ignore is now empty,
|
|
// free the memory.
|
|
//
|
|
if (*NotifyPnpElement->ListofBindingsToIgnore)
|
|
{
|
|
ExFreePool (NotifyPnpElement->ListofBindingsToIgnore);
|
|
NotifyPnpElement->ListofBindingsToIgnore = NULL;
|
|
}
|
|
|
|
TDI_DEBUG(BIND, ("Printing new ignore list\n"));
|
|
TdipPrintMultiSz (NotifyPnpElement->ListofBindingsToIgnore);
|
|
}
|
|
break;
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("---------------------------> -- TdiHandlePnpOperation!!\n"));
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiExecuteRequest(
|
|
IN CTEEvent *Event,
|
|
IN PVOID pParams
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
Called by TdiHandleSerializedRequest to execute the request.
|
|
It has been made another function, so that a worker thread can
|
|
execute this function.
|
|
|
|
Parameters:
|
|
CTEEvent (Event) : If this is NULL, it means that we have
|
|
been called directly from TdiHandleSerializedRequest.
|
|
Otherwise, it is called from the WorkerThread
|
|
PVOID (pParams) : This can NEVER be NULL. It tells this function
|
|
of the work that needs to be done.
|
|
|
|
Output:
|
|
NT_STATUS.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTDI_PROVIDER_RESOURCE ProviderElement, Context;
|
|
PTDI_NOTIFY_COMMON NotifyElement;
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY List;
|
|
PTDI_EXEC_PARAMS pTdiExecParams, pNextParams = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG ScheduledTest = 0;
|
|
PTDI_NOTIFY_PNP_ELEMENT PnpNotifyElement = NULL;
|
|
|
|
TDI_DEBUG(FUNCTION2, ("++ TdiExecuteRequest\n"));
|
|
|
|
// we are in trouble if pParams is NULL
|
|
ASSERT(NULL != pParams);
|
|
pTdiExecParams = (PTDI_EXEC_PARAMS) pParams;
|
|
|
|
if (NULL == pTdiExecParams) {
|
|
|
|
TDI_DEBUG(PARAMETERS, ("TDIExecRequest: params NULL\n"));
|
|
DbgBreakPoint();
|
|
|
|
}
|
|
|
|
if(0x1234cdef != pTdiExecParams->Signature) {
|
|
TDI_DEBUG(PARAMETERS, ("signature is BAD - %d not 0x1234cdef\r\n", pTdiExecParams->Signature));
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
|
|
ExAcquireSpinLock(
|
|
&TDIListLock,
|
|
&OldIrql
|
|
);
|
|
|
|
if (pTdiExecParams->Request.Event != NULL) {
|
|
*(pTdiExecParams->CurrentThread) = PsGetCurrentThread();
|
|
}
|
|
|
|
// DEBUG TRACKING ++++++++++++++++++
|
|
TrackExecs[NextExec].ExecParm = pTdiExecParams;
|
|
TrackExecs[NextExec].Type = pTdiExecParams->Request.Type;
|
|
TrackExecs[NextExec].Element = pTdiExecParams->Request.Element;
|
|
TrackExecs[NextExec].Thread = pTdiExecParams->CurrentThread;
|
|
if (++NextExec == EXEC_CNT) NextExec = 0;
|
|
// DEBUG TRACKING ++++++++++++++++++
|
|
|
|
PrevRequestType = pTdiExecParams->Request.Type;
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
switch (pTdiExecParams->Request.Type) {
|
|
|
|
case TDI_REGISTER_HANDLERS_PNP:
|
|
|
|
// This is a client register bind or address handler request.
|
|
|
|
// Insert this one into the registered client list.
|
|
NotifyElement = (PTDI_NOTIFY_COMMON)pTdiExecParams->Request.Element;
|
|
|
|
|
|
InsertTailList(
|
|
pTdiExecParams->ClientList,
|
|
&NotifyElement->Linkage
|
|
);
|
|
|
|
//
|
|
// Generate the list of new TDI_OPEN_BLOCKS caused by the new
|
|
// Client. If the provider isnt here, we set it to NULL for now.
|
|
//
|
|
TdipBuildProviderList(
|
|
(PTDI_NOTIFY_PNP_ELEMENT) NotifyElement
|
|
);
|
|
|
|
// Call TdiNotifyNewClient to notify this new client of all
|
|
// all existing providers.
|
|
|
|
TdiNotifyNewPnpClient(
|
|
pTdiExecParams->ProviderList,
|
|
pTdiExecParams->Request.Element
|
|
);
|
|
|
|
break;
|
|
|
|
case TDI_DEREGISTER_HANDLERS_PNP:
|
|
|
|
// This is a client deregister request. Pull him from the
|
|
// client list, free it, and we're done.
|
|
|
|
NotifyElement = (PTDI_NOTIFY_COMMON)pTdiExecParams->Request.Element;
|
|
|
|
CTEAssert(NotifyElement->Linkage.Flink != (PLIST_ENTRY)UlongToPtr(0xabababab));
|
|
CTEAssert(NotifyElement->Linkage.Blink != (PLIST_ENTRY)UlongToPtr(0xefefefef));
|
|
|
|
|
|
RemoveEntryList(&NotifyElement->Linkage);
|
|
|
|
NotifyElement->Linkage.Flink = (PLIST_ENTRY)UlongToPtr(0xabababab);
|
|
NotifyElement->Linkage.Blink = (PLIST_ENTRY)UlongToPtr(0xefefefef);
|
|
|
|
// for the new handlers, we also have the name there.
|
|
|
|
PnpNotifyElement = (PTDI_NOTIFY_PNP_ELEMENT)pTdiExecParams->Request.Element;
|
|
|
|
// the name can be NULL, as in the case of TCP/IP.
|
|
if (NULL != PnpNotifyElement->ElementName.Buffer) {
|
|
ExFreePool(PnpNotifyElement->ElementName.Buffer);
|
|
}
|
|
|
|
if (NULL != PnpNotifyElement->ListofProviders) {
|
|
ExFreePool(PnpNotifyElement->ListofProviders);
|
|
}
|
|
|
|
ExFreePool(NotifyElement);
|
|
|
|
break;
|
|
|
|
case TDI_REGISTER_PROVIDER_PNP:
|
|
InterlockedIncrement(&ProvidersRegistered);
|
|
|
|
case TDI_REGISTER_DEVICE_PNP:
|
|
|
|
case TDI_REGISTER_ADDRESS_PNP:
|
|
|
|
// A provider is registering a device or address. Add him to
|
|
// the appropriate provider list, and then notify all
|
|
// existing clients of the new device.
|
|
|
|
ProviderElement = (PTDI_PROVIDER_RESOURCE) pTdiExecParams->Request.Element;
|
|
|
|
InsertTailList(
|
|
pTdiExecParams->ProviderList,
|
|
&ProviderElement->Common.Linkage
|
|
);
|
|
|
|
|
|
// Call TdiNotifyClientList to do the hard work.
|
|
|
|
TdiNotifyPnpClientList(
|
|
pTdiExecParams->ClientList,
|
|
pTdiExecParams->Request.Element,
|
|
TRUE
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TDI_DEREGISTER_PROVIDER_PNP:
|
|
InterlockedDecrement(&ProvidersRegistered);
|
|
case TDI_DEREGISTER_DEVICE_PNP:
|
|
case TDI_DEREGISTER_ADDRESS_PNP:
|
|
|
|
// A provider device or address is deregistering. Pull the
|
|
// resource from the provider list, and notify clients that
|
|
// he's gone.
|
|
|
|
ProviderElement = (PTDI_PROVIDER_RESOURCE)pTdiExecParams->Request.Element;
|
|
|
|
CTEAssert(ProviderElement->Common.Linkage.Flink != (PLIST_ENTRY)UlongToPtr(0xabababab));
|
|
CTEAssert(ProviderElement->Common.Linkage.Blink != (PLIST_ENTRY)UlongToPtr(0xefefefef));
|
|
|
|
|
|
RemoveEntryList(&ProviderElement->Common.Linkage);
|
|
|
|
ProviderElement->Common.Linkage.Flink = (PLIST_ENTRY) UlongToPtr(0xabababab);
|
|
ProviderElement->Common.Linkage.Blink = (PLIST_ENTRY) UlongToPtr(0xefefefef);
|
|
|
|
//
|
|
// Dont have to tell the clients if this is a ProviderDeregister.
|
|
//
|
|
if (pTdiExecParams->Request.Type == TDI_DEREGISTER_PROVIDER_PNP) {
|
|
|
|
if (ProviderElement->ProviderReady) {
|
|
InterlockedDecrement(&ProvidersReady);
|
|
}
|
|
|
|
} else {
|
|
|
|
TdiNotifyPnpClientList(
|
|
pTdiExecParams->ClientList,
|
|
pTdiExecParams->Request.Element,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
// Free the tracking structure we had.
|
|
|
|
if (pTdiExecParams->Request.Type == TDI_DEREGISTER_DEVICE_PNP) {
|
|
ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer);
|
|
}
|
|
|
|
if (ProviderElement->DeviceName.Buffer) {
|
|
ExFreePool(ProviderElement->DeviceName.Buffer);
|
|
ProviderElement->DeviceName.Buffer = NULL;
|
|
ProviderElement->DeviceName.Length = 0;
|
|
ProviderElement->DeviceName.MaximumLength = 0;
|
|
}
|
|
|
|
if (ProviderElement->Context2) {
|
|
ExFreePool(ProviderElement->Context2);
|
|
ProviderElement->Context2 = NULL;
|
|
}
|
|
|
|
ExFreePool(ProviderElement);
|
|
|
|
break;
|
|
|
|
|
|
case TDI_REGISTER_PNP_POWER_EVENT:
|
|
|
|
// Inform all the Clients of the Power Event, which has come from
|
|
// a transport...
|
|
|
|
ProviderElement = (PTDI_PROVIDER_RESOURCE)pTdiExecParams->Request.Element;
|
|
|
|
|
|
/*
|
|
KeInitializeEvent(
|
|
&ProviderElement->PowerSyncEvent,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
*/
|
|
//
|
|
// Figure out how many clients we are going to inform.
|
|
//
|
|
{
|
|
|
|
PLIST_ENTRY Current;
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyPnpElement;
|
|
|
|
ProviderElement->PowerHandlers = 1;
|
|
|
|
Current = pTdiExecParams->ClientList->Flink;
|
|
|
|
while (Current != pTdiExecParams->ClientList) {
|
|
|
|
NotifyPnpElement = CONTAINING_RECORD(
|
|
Current,
|
|
TDI_NOTIFY_PNP_ELEMENT,
|
|
Common.Linkage
|
|
);
|
|
|
|
// RESOURCE_POWER
|
|
if (NotifyPnpElement->PnpPowerHandler) {
|
|
|
|
ProviderElement->PowerHandlers++;
|
|
}
|
|
// Get the next one.
|
|
|
|
TDI_DEBUG(POWER, ("%d PowerCallBacks expected\n", ProviderElement->PowerHandlers));
|
|
|
|
Current = Current->Flink;
|
|
}
|
|
}
|
|
|
|
TDI_LOG(LOG_POWER, ("%X, %d resources to notify\n",
|
|
ProviderElement, ProviderElement->PowerHandlers));
|
|
|
|
Status = TdiNotifyPnpClientList(
|
|
pTdiExecParams->ClientList,
|
|
pTdiExecParams->Request.Element,
|
|
FALSE // NOP: this param is ignored
|
|
);
|
|
|
|
TDI_DEBUG(POWER, ("The client list returned %lx\n", Status));
|
|
|
|
TDI_LOG(LOG_POWER, ("%X, NotityClients returned %X\n",
|
|
ProviderElement, Status));
|
|
|
|
if (!InterlockedDecrement(&ProviderElement->PowerHandlers)) {
|
|
|
|
PTDI_PROVIDER_RESOURCE Temp;
|
|
|
|
TDI_DEBUG(POWER, ("Power Handlers All done...\n", ProviderElement->PowerHandlers));
|
|
|
|
Temp =
|
|
Context = *((PTDI_PROVIDER_RESOURCE *) ProviderElement->PnpPowerEvent->TdiReserved);
|
|
|
|
//
|
|
// Loop thru and see if there are any previous contexts associated
|
|
// with this netpnp event, in which case, pop it.
|
|
//
|
|
|
|
Status = ProviderElement->Status;
|
|
|
|
if (Temp->PreviousContext) {
|
|
|
|
while (Temp->PreviousContext) {
|
|
|
|
Context = Temp;
|
|
Temp = Temp->PreviousContext;
|
|
|
|
}
|
|
|
|
Context->PreviousContext = NULL; //pop the last guy
|
|
|
|
} else {
|
|
//
|
|
// This was the only pointer in the TdiReserved and we dont need it anymore
|
|
//
|
|
RtlZeroMemory(ProviderElement->PnpPowerEvent->TdiReserved,
|
|
sizeof(ProviderElement->PnpPowerEvent->TdiReserved));
|
|
}
|
|
|
|
TDI_LOG(LOG_POWER, ("%X, pnp power complete, Call completion at %X\n",
|
|
ProviderElement, ProviderElement->PnPCompleteHandler));
|
|
|
|
if (pTdiExecParams->Request.Pending && (*(ProviderElement->PnPCompleteHandler))) {
|
|
(*(ProviderElement->PnPCompleteHandler))(
|
|
ProviderElement->PnpPowerEvent,
|
|
ProviderElement->Status
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(POWER, ("At least one of them is pending \n STATUS from ExecuteHAndler:%x\n", Status));
|
|
|
|
TDI_LOG(LOG_POWER, ("%X, a client didn't complete pnp power sync\n",
|
|
ProviderElement));
|
|
|
|
}
|
|
|
|
TDI_DEBUG(POWER, ("<<<<NET NET NET>>>>> : Returning %lx\n", Status));
|
|
|
|
break;
|
|
|
|
case TDI_NDIS_IOCTL_HANDLER_PNP:
|
|
|
|
TdiHandlePnpOperation(
|
|
pTdiExecParams->ClientList,
|
|
pTdiExecParams->Request.Element
|
|
);
|
|
|
|
break;
|
|
|
|
case TDI_ENUMERATE_ADDRESSES:
|
|
|
|
// Insert this one into the registered client list.
|
|
NotifyElement = (PTDI_NOTIFY_COMMON)pTdiExecParams->Request.Element;
|
|
|
|
// Call TdiNotifyNewClient to notify this new client of all
|
|
// all existing providers.
|
|
|
|
TdiNotifyAddresses(
|
|
pTdiExecParams->ProviderList,
|
|
pTdiExecParams->Request.Element
|
|
);
|
|
|
|
break;
|
|
|
|
case TDI_PROVIDER_READY_PNP:
|
|
//
|
|
// Loop through and tell each client about it.
|
|
//
|
|
InterlockedIncrement(&ProvidersReady);
|
|
ProviderElement = (PTDI_PROVIDER_RESOURCE)pTdiExecParams->Request.Element;
|
|
ProviderElement->ProviderReady = TRUE;
|
|
TdiNotifyPnpClientList(
|
|
pTdiExecParams->ClientList,
|
|
pTdiExecParams->Request.Element,
|
|
TRUE
|
|
);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TDI_DEBUG(ERROR, ("unknown switch statement\n"));
|
|
CTEAssert(FALSE);
|
|
|
|
break;
|
|
}
|
|
|
|
// If there was an event specified with this request, signal
|
|
// it now. This should only be a client deregister request, which
|
|
// needs to block until it's completed.
|
|
|
|
if (pTdiExecParams->Request.Event != NULL) {
|
|
|
|
//
|
|
// If we had this thread marked to prevent re-entrant requests, then
|
|
// clear that. Note that we do this BEFORE we set the event below to
|
|
// let the thread go, since it may immediately resubmit another request.
|
|
//
|
|
|
|
*(pTdiExecParams->CurrentThread) = NULL;
|
|
|
|
KeSetEvent(pTdiExecParams->Request.Event, 0, FALSE);
|
|
}
|
|
|
|
ExAcquireSpinLock(
|
|
&TDIListLock,
|
|
&OldIrql
|
|
);
|
|
|
|
// DEBUG TRACKING ++++++++++++++++++
|
|
TrackExecCompletes[NextExecComplete].ExecParm = pTdiExecParams;
|
|
TrackExecCompletes[NextExecComplete].Type = pTdiExecParams->Request.Type;
|
|
TrackExecCompletes[NextExecComplete].Element = pTdiExecParams->Request.Element;
|
|
TrackExecCompletes[NextExecComplete].Thread = pTdiExecParams->CurrentThread;
|
|
if (++NextExecComplete == EXEC_CNT) NextExecComplete = 0;
|
|
// DEBUG TRACKING ++++++++++++++++++
|
|
|
|
|
|
//
|
|
// If this request occured on a worker thread
|
|
// reset the EventScheduled to FALSE
|
|
//
|
|
|
|
if (Event != NULL) {
|
|
|
|
EventScheduled = FALSE;
|
|
}
|
|
|
|
if (!IsListEmpty(pTdiExecParams->RequestList)) {
|
|
|
|
if (EventScheduled == FALSE) {
|
|
|
|
//
|
|
// The following should indicate that no new events should be created.
|
|
//
|
|
|
|
EventScheduled = TRUE;
|
|
|
|
// The request list isn't empty. Pull the next one from
|
|
// the list and process it.
|
|
|
|
List = RemoveHeadList(pTdiExecParams->RequestList);
|
|
pNextParams = CONTAINING_RECORD(List, TDI_EXEC_PARAMS, Linkage);
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
// Schedule a thread to deal with this work
|
|
// To fix bug# 33975
|
|
if(0x1234cdef != pNextParams->Signature) {
|
|
TDI_DEBUG(PARAMETERS, ("2 Signature is BAD - %d not 0x1234cdef\r\n", pTdiExecParams->Signature));
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
ASSERT(pNextParams != NULL);
|
|
ASSERT(0x1234cdef == pNextParams->Signature);
|
|
|
|
PrevRequestType = pNextParams->Request.Type;
|
|
|
|
CTEInitEvent(pNextParams->RequestCTEEvent, TdiExecuteRequest);
|
|
CTEScheduleEvent(pNextParams->RequestCTEEvent, pNextParams);
|
|
|
|
} else {
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
}
|
|
|
|
ExFreePool(pTdiExecParams);
|
|
|
|
} else {
|
|
|
|
// The request list is empty. Clear the flag and we're done.
|
|
// IMP: Since Serializataion can be bypassed
|
|
// (the TdiSerializeRequest allows one type of request to bypass
|
|
// serialization),
|
|
// we need to make sure there are no other worker threads
|
|
// currently processing TdiRequests
|
|
|
|
if (pTdiExecParams->ResetSerializeFlag && EventScheduled == FALSE) {
|
|
|
|
*(pTdiExecParams->SerializeFlag) = FALSE;
|
|
} else {
|
|
TDI_LOG(LOG_POWER, ("Not resetting serialized flag\n"));
|
|
}
|
|
|
|
PrevRequestType = 0;
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
ExFreePool(pTdiExecParams);
|
|
}
|
|
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdiExecuteRequest\n"));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TdiHandleSerializedRequest (
|
|
PVOID RequestInfo,
|
|
UINT RequestType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when we want to process a request relating to one of the
|
|
lists we manage. We look to see if we are currently processing such
|
|
a request - if we are, we queue this for later. Otherwise we'll
|
|
remember that we are doing this, and we'll process this request.
|
|
When we're done we'll look to see if any more came in while we were
|
|
busy.
|
|
|
|
Arguments:
|
|
|
|
RequestInfo - Reqeust specific information.
|
|
RequestType - The type of the request.
|
|
|
|
Return Value:
|
|
|
|
Request completion status.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY List;
|
|
PLIST_ENTRY ClientList;
|
|
PLIST_ENTRY ProviderList;
|
|
PLIST_ENTRY PnpHandlerList;
|
|
PLIST_ENTRY RequestList;
|
|
PBOOLEAN SerializeFlag;
|
|
PETHREAD *RequestThread;
|
|
PTDI_SERIALIZED_REQUEST Request;
|
|
CTEEvent *pEvent;
|
|
PTDI_EXEC_PARAMS pTdiExecParams;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PVOID pCallersAddress;
|
|
PVOID pCallersCallers;
|
|
PETHREAD pCallerThread;
|
|
|
|
TDI_DEBUG(FUNCTION2, ("++ TdiHandleSerializedRequest\n"));
|
|
|
|
// Initialize tracking information
|
|
RtlGetCallersAddress(&pCallersAddress, &pCallersCallers);
|
|
pCallerThread = PsGetCurrentThread ();
|
|
|
|
ExAcquireSpinLock(
|
|
&TDIListLock,
|
|
&OldIrql
|
|
);
|
|
|
|
// means PnP handlers
|
|
if (RequestType > TDI_MAX_ADDRESS_REQUEST) {
|
|
|
|
ClientList = &PnpHandlerClientList;
|
|
ProviderList = &PnpHandlerProviderList;
|
|
RequestList = &PnpHandlerRequestList;
|
|
SerializeFlag = &PnpHandlerRequestInProgress;
|
|
RequestThread = &PnpHandlerRequestThread;
|
|
pEvent = &PnpHandlerEvent;
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest\n"));
|
|
TDI_DEBUG(PARAMETERS, ("TDIHANDLESERIALIZEDREQUEST: BAD Request!!\r\n"));
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
// We only need to allocate memory if this isn't a deregister call.
|
|
if (RequestType != TDI_DEREGISTER_HANDLERS_PNP) {
|
|
pTdiExecParams = (PTDI_EXEC_PARAMS)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_EXEC_PARAMS),
|
|
'aIDT'
|
|
);
|
|
|
|
if (NULL == pTdiExecParams) {
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest : INSUFFICIENT RESOURCES\n"));
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
} else {
|
|
// We preallocated memory during register for this deregister call
|
|
// so that it won't fail sue to low memory conditions.
|
|
pTdiExecParams = ((PTDI_NOTIFY_PNP_ELEMENT)RequestInfo)->pTdiDeregisterExecParams;
|
|
}
|
|
|
|
RtlZeroMemory(&pTdiExecParams->Request, sizeof(TDI_SERIALIZED_REQUEST));
|
|
|
|
// Got the request.
|
|
pTdiExecParams->Request.Element = RequestInfo;
|
|
pTdiExecParams->Request.Type = RequestType;
|
|
pTdiExecParams->Request.Event = NULL;
|
|
|
|
// marshal params into a structure
|
|
// Set the Request Structure, so that we can process it in the TdiExecute function.
|
|
pTdiExecParams->ClientList = ClientList;
|
|
pTdiExecParams->ProviderList = ProviderList;
|
|
pTdiExecParams->RequestList = RequestList;
|
|
pTdiExecParams->SerializeFlag = SerializeFlag;
|
|
pTdiExecParams->RequestCTEEvent = pEvent;
|
|
pTdiExecParams->CurrentThread = RequestThread;
|
|
pTdiExecParams->Signature = 0x1234cdef;
|
|
pTdiExecParams->ResetSerializeFlag = TRUE;
|
|
pTdiExecParams->pCallersAddress = pCallersAddress;
|
|
pTdiExecParams->pCallersCaller = pCallersCallers;
|
|
pTdiExecParams->pCallerThread = pCallerThread;
|
|
|
|
|
|
// If we're not already here, handle it right away.
|
|
|
|
if ((!(*SerializeFlag)) ||
|
|
(((PrevRequestType == TDI_REGISTER_PNP_POWER_EVENT) ||
|
|
(PrevRequestType == TDI_NDIS_IOCTL_HANDLER_PNP)) &&
|
|
(RequestType == TDI_REGISTER_PNP_POWER_EVENT)) ) {
|
|
|
|
if (*SerializeFlag == TRUE) {
|
|
|
|
// A request is currently executing so don't
|
|
// reset the serialize flag when this one
|
|
// completes!!
|
|
pTdiExecParams->ResetSerializeFlag = FALSE;
|
|
}
|
|
|
|
*SerializeFlag = TRUE;
|
|
PrevRequestType = RequestType;
|
|
|
|
// We're done with the lock for now, so free it.
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
// Figure out and execute the type of request we have here.
|
|
|
|
Status = TdiExecuteRequest(NULL, pTdiExecParams);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-TdiSerialized sync\n"));
|
|
|
|
return Status;
|
|
|
|
} else {
|
|
|
|
// We're already running, so we'll have to queue. If this is a
|
|
// deregister bind or address notify call, we'll see if the issueing
|
|
// thread is the same one that is currently busy. If so, we'll fail
|
|
// to avoid deadlock. Otherwise for deregister calls we'll block until
|
|
// it's done.
|
|
|
|
//
|
|
// For Nt5, we have devicename and a context coming in along with net addresses/device objects.
|
|
// It is the transport's responsibility to ensure that these are correct.
|
|
// The Register_PNP_Handlers on the other hand need not be made synch.
|
|
//
|
|
|
|
if (
|
|
pTdiExecParams->Request.Type == TDI_DEREGISTER_HANDLERS_PNP ||
|
|
pTdiExecParams->Request.Type == TDI_NDIS_IOCTL_HANDLER_PNP
|
|
) {
|
|
|
|
// This is a deregister request. See if it's the same thread
|
|
// that's busy. If not, block for it to complete.
|
|
|
|
if (*RequestThread == PsGetCurrentThread()) {
|
|
|
|
// It's the same one, so give up now.
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
ExFreePool(pTdiExecParams);
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest: Network Busy\n"));
|
|
|
|
TDI_LOG(LOG_ERROR, ("-TdiSerializedRequest rc=busy\n"));
|
|
|
|
return STATUS_NETWORK_BUSY;
|
|
|
|
} else {
|
|
// He's not currently busy, go ahead and block.
|
|
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
|
|
KeInitializeEvent(
|
|
&Event,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
pTdiExecParams->Request.Event = &Event;
|
|
|
|
// Put this guy on the end of the request list.
|
|
|
|
InsertTailList(pTdiExecParams->RequestList, &pTdiExecParams->Linkage);
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("TdiSerializedRequest blocked\n"));
|
|
|
|
Status = KeWaitForSingleObject(
|
|
&Event,
|
|
UserRequest,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
// I don't know what we'd do is the wait failed....
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest\n"));
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-TdiSerializeRequest rc=0\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
|
|
// This isn't a deregister request, so there's no special handling
|
|
// necessary. Just put the request on the end of the list.
|
|
|
|
InsertTailList(pTdiExecParams->RequestList, &pTdiExecParams->Linkage);
|
|
|
|
|
|
|
|
if (TDI_REGISTER_PNP_POWER_EVENT == pTdiExecParams->Request.Type) {
|
|
|
|
//
|
|
// For the PnP/PM event, there is now a completion handler, so
|
|
// we can return pending here only for this case.
|
|
// The other cases, we assume success.
|
|
//
|
|
|
|
pTdiExecParams->Request.Pending = TRUE;
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdiHandleSerializedRequest\n"));
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-TdiSerialzied Pending\n"));
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-TdiSerialized sync~sync\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiRegisterNotificationHandler(
|
|
IN TDI_BIND_HANDLER BindHandler,
|
|
IN TDI_UNBIND_HANDLER UnbindHandler,
|
|
OUT HANDLE *BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI client wants to register for
|
|
notification of the arrival of TDI providers. We allocate a
|
|
TDI_NOTIFY_ELEMENT for the provider and then call the serialized
|
|
worker routine to do the real work.
|
|
|
|
Arguments:
|
|
|
|
BindHandler - A pointer to the routine to be called when
|
|
a new provider arrives.
|
|
UnbindHandler - A pointer to the routine to be called when a
|
|
provider leaves.
|
|
BindingHandle - A handle we pass back that identifies this
|
|
client to us.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to register the client.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
TDI_CLIENT_INTERFACE_INFO tdiInterface;
|
|
|
|
//
|
|
// Make sure Tdi is intialized. If there are no pnp transports, then this is
|
|
// called by the tdi client and if tdi is not initialized, it is toast
|
|
// Multiple calls to TdiIntialize are safe since only the first one does
|
|
// the real work
|
|
//
|
|
TdiInitialize();
|
|
|
|
RtlZeroMemory(&tdiInterface, sizeof(tdiInterface));
|
|
|
|
tdiInterface.MajorTdiVersion = 1;
|
|
tdiInterface.MinorTdiVersion = 0;
|
|
tdiInterface.BindHandler = BindHandler;
|
|
tdiInterface.UnBindHandler = UnbindHandler;
|
|
|
|
return (TdiRegisterPnPHandlers(
|
|
&tdiInterface,
|
|
sizeof(tdiInterface),
|
|
BindingHandle
|
|
));
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiDeregisterNotificationHandler(
|
|
IN HANDLE BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI client wants to deregister a
|
|
previously registered bind notification handler. All we really
|
|
do is call TdiHandleSerializedRequest, which does the hard work.
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - A handle we passed back to the client
|
|
on the register call. This is really
|
|
a pointer to the notify element.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to deregister the client.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (TdiDeregisterPnPHandlers(
|
|
BindingHandle));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TdiRegisterDeviceObject(
|
|
IN PUNICODE_STRING DeviceName,
|
|
OUT HANDLE *RegistrationHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a TDI provider wants to register a device object.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - Name of the device to be registered.
|
|
|
|
RegistrationHandle - A handle we pass back to the provider,
|
|
identifying this registration.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to register the provider.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PTDI_PROVIDER_RESOURCE NewResource;
|
|
NTSTATUS Status;
|
|
PWCHAR Buffer;
|
|
int i;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiRegisterDeviceObject\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TdiInitialize();
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_PROVIDER_RESOURCE),
|
|
'cIDT'
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewResource == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(NewResource, sizeof(TDI_PROVIDER_RESOURCE));
|
|
|
|
// Try and get a buffer to hold the name.
|
|
|
|
Buffer = (PWCHAR)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
DeviceName->MaximumLength,
|
|
'dIDT'
|
|
);
|
|
|
|
if (Buffer == NULL) {
|
|
ExFreePool(NewResource);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
// Fill in the basic stuff.
|
|
NewResource->Common.Type = TDI_RESOURCE_DEVICE;
|
|
NewResource->Specific.Device.DeviceName.MaximumLength =
|
|
DeviceName->MaximumLength;
|
|
|
|
NewResource->Specific.Device.DeviceName.Buffer = Buffer;
|
|
|
|
RtlCopyUnicodeString(
|
|
&NewResource->Specific.Device.DeviceName,
|
|
DeviceName
|
|
);
|
|
|
|
*RegistrationHandle = (HANDLE)NewResource;
|
|
|
|
TDI_DEBUG(PROVIDERS, ("Registering Device Object\n"));
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewResource,
|
|
TDI_REGISTER_DEVICE_PNP
|
|
);
|
|
|
|
CTEAssert(STATUS_SUCCESS == Status);
|
|
|
|
if (STATUS_SUCCESS != Status) {
|
|
ExFreePool(Buffer);
|
|
ExFreePool(NewResource);
|
|
*RegistrationHandle = NULL;
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiRegisterDeviceObject\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-RegisterDeviceObject rc=%X h=%X %wZ\n",
|
|
Status, NewResource, DeviceName));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiDeregisterDeviceObject(
|
|
IN HANDLE RegistrationHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI provider want's to deregister
|
|
a device object.
|
|
|
|
Arguments:
|
|
|
|
RegistrationHandle - A handle we passed back to the provider
|
|
on the register call. This is really
|
|
a pointer to the resource element.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to deregister the provider.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiDERegisterDeviceObject\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
CTEAssert(RegistrationHandle);
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
RegistrationHandle,
|
|
TDI_DEREGISTER_DEVICE_PNP
|
|
);
|
|
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiDERegisterDeviceObject\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("TdiDeregisterDeviceObject rc=%d\n", Status));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TdiRegisterAddressChangeHandler(
|
|
IN TDI_ADD_ADDRESS_HANDLER AddHandler,
|
|
IN TDI_DEL_ADDRESS_HANDLER DeleteHandler,
|
|
OUT HANDLE *BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI client wants to register for
|
|
notification of the arrival of network addresses. We allocate a
|
|
TDI_NOTIFY_ELEMENT for the provider and then call the serialized
|
|
worker routine to do the real work.
|
|
|
|
Arguments:
|
|
|
|
AddHandler - A pointer to the routine to be called when
|
|
a new address arrives.
|
|
DeleteHandler - A pointer to the routine to be called when an
|
|
address leaves.
|
|
BindingHandle - A handle we pass back that identifies this
|
|
client to us.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to register the client.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
TDI_CLIENT_INTERFACE_INFO tdiInterface;
|
|
|
|
//
|
|
// Make sure Tdi is intialized. If there are no pnp transports, then this is
|
|
// called by the tdi client and if tdi is not initialized, it is toast
|
|
// Multiple calls to TdiIntialize are safe since only the first one does
|
|
// the real work
|
|
//
|
|
TdiInitialize();
|
|
|
|
RtlZeroMemory(&tdiInterface, sizeof(tdiInterface));
|
|
|
|
tdiInterface.MajorTdiVersion = 1;
|
|
tdiInterface.MinorTdiVersion = 0;
|
|
tdiInterface.AddAddressHandler = AddHandler;
|
|
tdiInterface.DelAddressHandler = DeleteHandler;
|
|
|
|
return (TdiRegisterPnPHandlers(
|
|
&tdiInterface,
|
|
sizeof(tdiInterface),
|
|
BindingHandle
|
|
));
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiDeregisterAddressChangeHandler(
|
|
IN HANDLE BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI client wants to deregister a
|
|
previously registered address change notification handler. All we
|
|
really do is call TdiHandleSerializedRequest, which does the hard work.
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - A handle we passed back to the client
|
|
on the register call. This is really
|
|
a pointer to the notify element.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to deregister the client.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (TdiDeregisterPnPHandlers(
|
|
BindingHandle));
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiRegisterNetAddress(
|
|
IN PTA_ADDRESS Address,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PTDI_PNP_CONTEXT Context2,
|
|
OUT HANDLE *RegistrationHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a TDI provider wants to register a new net address.
|
|
|
|
Arguments:
|
|
|
|
Address - New net address to be registered.
|
|
Context1 - Protocol defined context1. For example,
|
|
TCPIP will pass the list of IP addresses associated
|
|
with this device.
|
|
Context2 - Protocol defined context2. For example, TCPIP may pass
|
|
the PDO of the device on which this PnP event is being notified.
|
|
|
|
RegistrationHandle - A handle we pass back to the provider,
|
|
identifying this registration.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to register the provider.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PTDI_PROVIDER_RESOURCE NewResource;
|
|
NTSTATUS Status;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiRegisterNetAddress\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
FIELD_OFFSET(
|
|
TDI_PROVIDER_RESOURCE,
|
|
Specific.NetAddress
|
|
) +
|
|
FIELD_OFFSET(TA_ADDRESS, Address) +
|
|
Address->AddressLength,
|
|
'eIDT'
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewResource == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
NewResource,
|
|
FIELD_OFFSET(
|
|
TDI_PROVIDER_RESOURCE,
|
|
Specific.NetAddress
|
|
) +
|
|
FIELD_OFFSET(
|
|
TA_ADDRESS,
|
|
Address
|
|
) +
|
|
Address->AddressLength
|
|
);
|
|
|
|
// Fill in the basic stuff.
|
|
NewResource->Common.Type = TDI_RESOURCE_NET_ADDRESS;
|
|
NewResource->Specific.NetAddress.Address.AddressLength =
|
|
Address->AddressLength;
|
|
|
|
NewResource->Specific.NetAddress.Address.AddressType =
|
|
Address->AddressType;
|
|
|
|
RtlCopyMemory(
|
|
NewResource->Specific.NetAddress.Address.Address,
|
|
Address->Address,
|
|
Address->AddressLength
|
|
);
|
|
|
|
*RegistrationHandle = (HANDLE)NewResource;
|
|
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
// we have to fill in the contexts here
|
|
|
|
if (DeviceName) {
|
|
|
|
NewResource->DeviceName.Buffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
DeviceName->MaximumLength,
|
|
'uIDT'
|
|
);
|
|
|
|
if (NULL == NewResource->DeviceName.Buffer) {
|
|
|
|
ExFreePool(NewResource);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
NewResource->DeviceName.Buffer,
|
|
DeviceName->Buffer,
|
|
DeviceName->MaximumLength
|
|
);
|
|
|
|
NewResource->DeviceName.Length = DeviceName->Length;
|
|
NewResource->DeviceName.MaximumLength = DeviceName->MaximumLength;
|
|
|
|
} else {
|
|
NewResource->DeviceName.Buffer = NULL;
|
|
}
|
|
|
|
if (Context2) {
|
|
|
|
NewResource->Context2 = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
FIELD_OFFSET(TDI_PNP_CONTEXT, ContextData)
|
|
+ Context2->ContextSize,
|
|
'vIDT'
|
|
);
|
|
if (NULL == NewResource->Context2) {
|
|
|
|
if (NewResource->DeviceName.Buffer) {
|
|
ExFreePool(NewResource->DeviceName.Buffer);
|
|
}
|
|
ExFreePool(NewResource);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
NewResource->Context2->ContextType = Context2->ContextType;
|
|
NewResource->Context2->ContextSize = Context2->ContextSize;
|
|
RtlCopyMemory(
|
|
NewResource->Context2->ContextData,
|
|
Context2->ContextData,
|
|
Context2->ContextSize
|
|
);
|
|
} else {
|
|
NewResource->Context2 = NULL;
|
|
}
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewResource,
|
|
TDI_REGISTER_ADDRESS_PNP
|
|
);
|
|
|
|
|
|
CTEAssert(STATUS_SUCCESS == Status);
|
|
|
|
if (STATUS_SUCCESS != Status) {
|
|
|
|
*RegistrationHandle = NULL;
|
|
|
|
TDI_DEBUG(ERROR, ("Freeing Contexts due to failure!!\n"));
|
|
|
|
if (NewResource->DeviceName.Buffer) {
|
|
TDI_DEBUG(ERROR, ("Freeing context1: %x", NewResource->DeviceName));
|
|
|
|
ExFreePool(NewResource->DeviceName.Buffer);
|
|
NewResource->DeviceName.Buffer = NULL;
|
|
}
|
|
|
|
if (NewResource->Context2) {
|
|
TDI_DEBUG(ERROR, ("Freeing context2: %x", NewResource->Context2));
|
|
|
|
ExFreePool(NewResource->Context2);
|
|
NewResource->Context2 = NULL;
|
|
}
|
|
|
|
TDI_DEBUG(ERROR, ("Freeing Provider: %x", NewResource));
|
|
|
|
ExFreePool(NewResource);
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiRegisterNetAddress\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-RegisterNetAddress rc=%d h=%X %wZ\n",
|
|
Status, *RegistrationHandle, DeviceName));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiDeregisterNetAddress(
|
|
IN HANDLE RegistrationHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI provider wants to deregister
|
|
a net addres.
|
|
|
|
Arguments:
|
|
|
|
RegistrationHandle - A handle we passed back to the provider
|
|
on the register call. This is really
|
|
a pointer to the resource element.
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to deregister the provider.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiDERegisterNetAddress\n"));
|
|
|
|
CTEAssert(RegistrationHandle);
|
|
|
|
if (NULL == RegistrationHandle) {
|
|
TDI_DEBUG(ERROR, ("NULL Address Deregistration\n"));
|
|
}
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
CTEAssert(((PTDI_PROVIDER_RESOURCE)RegistrationHandle)->Common.Linkage.Flink != (PLIST_ENTRY)UlongToPtr(0xabababab));
|
|
CTEAssert(((PTDI_PROVIDER_RESOURCE)RegistrationHandle)->Common.Linkage.Blink != (PLIST_ENTRY)UlongToPtr(0xefefefef));
|
|
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
RegistrationHandle,
|
|
TDI_DEREGISTER_ADDRESS_PNP
|
|
);
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiDERegisterNetAddress\n"));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
// The PnP/PM extension code
|
|
|
|
NTSTATUS
|
|
TdiRegisterPnPHandlers(
|
|
IN PTDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo,
|
|
IN ULONG InterfaceInfoSize,
|
|
OUT HANDLE *BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a TDI client wants to register
|
|
its set of PnP/PM handlers
|
|
|
|
Arguments:
|
|
|
|
ClientName
|
|
BindingHandler
|
|
AddAddressHandler
|
|
DelAddressHandler
|
|
PowerHandler
|
|
BindingHandle
|
|
|
|
Return Value:
|
|
|
|
The status of the client's attempt to register the handlers.
|
|
|
|
--*/
|
|
{
|
|
PTDI_NOTIFY_PNP_ELEMENT NewElement;
|
|
NTSTATUS Status;
|
|
PWCHAR Buffer = NULL;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiRegisterPnPHandlers\n"));
|
|
|
|
//
|
|
// Check that this is a TDI 2.0 Client
|
|
//
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
if (ClientInterfaceInfo->MajorTdiVersion > 2)
|
|
{
|
|
|
|
TDI_DEBUG(PROVIDERS, ("TDI Client: Bad Version!\n"));
|
|
return TDI_STATUS_BAD_VERSION;
|
|
|
|
}
|
|
|
|
//
|
|
// Check that ClientInfoLength is enough.
|
|
//
|
|
|
|
if (InterfaceInfoSize < sizeof(TDI_CLIENT_INTERFACE_INFO))
|
|
{
|
|
TDI_DEBUG(PROVIDERS, ("TDI Client Info length was incorrect\n"));
|
|
return TDI_STATUS_BAD_CHARACTERISTICS;
|
|
|
|
}
|
|
|
|
// This could be the first provider/client to call into TDI.
|
|
TdiInitialize();
|
|
|
|
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewElement = (PTDI_NOTIFY_PNP_ELEMENT)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_NOTIFY_PNP_ELEMENT),
|
|
'fIDT'
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewElement == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Allocate space for the deregister exec request.
|
|
NewElement->pTdiDeregisterExecParams = (PTDI_EXEC_PARAMS)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_EXEC_PARAMS),
|
|
'aIDT'
|
|
);
|
|
|
|
if (NULL == NewElement->pTdiDeregisterExecParams) {
|
|
|
|
ExFreePool(NewElement);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(NewElement->pTdiDeregisterExecParams, sizeof (TDI_EXEC_PARAMS));
|
|
|
|
// Try and get a buffer to hold the name, if required.
|
|
|
|
if (NULL != ClientInterfaceInfo->ClientName) {
|
|
|
|
Buffer = (PWCHAR)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
ClientInterfaceInfo->ClientName->MaximumLength,
|
|
'gIDT'
|
|
);
|
|
|
|
|
|
if (Buffer == NULL) {
|
|
ExFreePool(NewElement->pTdiDeregisterExecParams);
|
|
ExFreePool(NewElement);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
NewElement->ElementName.Length = ClientInterfaceInfo->ClientName->Length;
|
|
NewElement->ElementName.MaximumLength = ClientInterfaceInfo->ClientName->MaximumLength;
|
|
NewElement->ElementName.Buffer = Buffer;
|
|
|
|
RtlCopyUnicodeString(
|
|
&NewElement->ElementName,
|
|
ClientInterfaceInfo->ClientName
|
|
);
|
|
} else {
|
|
|
|
NewElement->ElementName.Length = 0;
|
|
NewElement->ElementName.MaximumLength = 0;
|
|
NewElement->ElementName.Buffer = NULL;
|
|
|
|
}
|
|
|
|
// Fill in the basic stuff.
|
|
|
|
NewElement->TdiVersion = ClientInterfaceInfo->TdiVersion;
|
|
|
|
NewElement->Common.Type = TDI_NOTIFY_PNP_HANDLERS;
|
|
|
|
if (TDI_VERSION_ONE == ClientInterfaceInfo->TdiVersion) {
|
|
|
|
NewElement->Bind.BindHandler = ClientInterfaceInfo->BindHandler;
|
|
NewElement->Bind.UnbindHandler = ClientInterfaceInfo->UnBindHandler;
|
|
NewElement->AddressElement.AddHandler = ClientInterfaceInfo->AddAddressHandler;
|
|
NewElement->AddressElement.DeleteHandler = ClientInterfaceInfo->DelAddressHandler;
|
|
NewElement->PnpPowerHandler = NULL;
|
|
|
|
} else {
|
|
|
|
NewElement->BindingHandler = ClientInterfaceInfo->BindingHandler;
|
|
NewElement->AddressElement.AddHandlerV2 = ClientInterfaceInfo->AddAddressHandlerV2;
|
|
NewElement->AddressElement.DeleteHandlerV2 = ClientInterfaceInfo->DelAddressHandlerV2;
|
|
NewElement->PnpPowerHandler = ClientInterfaceInfo->PnPPowerHandler;
|
|
|
|
}
|
|
|
|
NewElement->ListofBindingsToIgnore = NULL;
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
*BindingHandle = (HANDLE)NewElement;
|
|
|
|
TDI_DEBUG(PROVIDERS, ("TDI.SYS: Registering PnPHandlers ..."));
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewElement,
|
|
TDI_REGISTER_HANDLERS_PNP
|
|
);
|
|
|
|
CTEAssert(STATUS_SUCCESS == Status);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
if (Buffer) {
|
|
ExFreePool(Buffer);
|
|
}
|
|
|
|
ExFreePool(NewElement->pTdiDeregisterExecParams);
|
|
ExFreePool(NewElement);
|
|
|
|
*BindingHandle = NULL;
|
|
|
|
TDI_DEBUG(PROVIDERS, ("... NOT SUCCESS (%x)!\n", Status));
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(PROVIDERS, ("... SUCCESS!\n"));
|
|
|
|
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiRegisterPnPHandlers\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-RegisterPnpHandlers rc=%d h=%X %wZ\n",
|
|
Status, *BindingHandle, ClientInterfaceInfo->ClientName));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
VOID
|
|
TdiPnPPowerComplete(
|
|
IN HANDLE BindingHandle,
|
|
//IN PUNICODE_STRING DeviceName,
|
|
IN PNET_PNP_EVENT PnpPowerEvent,
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PTDI_PROVIDER_RESOURCE Provider, Context, Temp;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiPnPPowerComplete\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
ASSERT (NULL != PnpPowerEvent);
|
|
|
|
Context = *((PTDI_PROVIDER_RESOURCE *) PnpPowerEvent->TdiReserved);
|
|
|
|
TDI_LOG(LOG_POWER, ("TdiPnpPowerComplete for %X\n", Context));
|
|
|
|
if (NULL != Context) {
|
|
|
|
|
|
while(Context->PreviousContext) {
|
|
Context = Context->PreviousContext;
|
|
}
|
|
|
|
Provider = Context;
|
|
|
|
ASSERT(Provider->PowerHandlers != 0);
|
|
|
|
//
|
|
// Return Status only if Status was not SUCCESS.
|
|
//
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
Provider->Status = Status;
|
|
}
|
|
|
|
if (!InterlockedDecrement(&Provider->PowerHandlers)) {
|
|
|
|
TDI_DEBUG(POWER, ("Calling ProtocolPnPCompletion handler\n"));
|
|
|
|
|
|
if (Provider->PreviousContext) {
|
|
|
|
while (Provider->PreviousContext) {
|
|
|
|
Context = Provider;
|
|
Provider = Provider->PreviousContext;
|
|
|
|
}
|
|
|
|
Context->PreviousContext = NULL; //pop the last guy
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
//
|
|
// This was the only pointer in the TdiReserved and we dont need it anymore
|
|
//
|
|
RtlZeroMemory(PnpPowerEvent->TdiReserved,
|
|
sizeof(PnpPowerEvent->TdiReserved));
|
|
}
|
|
|
|
|
|
if (Provider->PnPCompleteHandler != NULL) {
|
|
|
|
TDI_LOG(LOG_POWER, ("%X, pnp power complete, Call completion at %X\n",
|
|
Provider, Provider->PnPCompleteHandler));
|
|
|
|
|
|
(*(Provider->PnPCompleteHandler))(
|
|
PnpPowerEvent,
|
|
Status
|
|
);
|
|
|
|
TDI_DEBUG(POWER, ("Done calling %wZ's ProtocolPnPCompletion handler\n", &Provider->Specific.Device.DeviceName));
|
|
|
|
TDI_DEBUG(POWER, ("The Previous Context at this point is %lx\n", Provider->PreviousContext));
|
|
//DbgBreakPoint();
|
|
|
|
}
|
|
|
|
|
|
ExFreePool(Provider->Specific.Device.DeviceName.Buffer);
|
|
|
|
if (Provider->Context1) {
|
|
ExFreePool(Provider->Context1);
|
|
Provider->Context1 = NULL;
|
|
}
|
|
|
|
if (Provider->Context2) {
|
|
ExFreePool(Provider->Context2);
|
|
Provider->Context2 = NULL;
|
|
}
|
|
|
|
ExFreePool(Provider); // free resources anyways
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(POWER, ("There are %d callbacks remaining for %wZ\n", Provider->PowerHandlers, &Provider->Specific.Device.DeviceName));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TDI_DEBUG(POWER, ("This was called separately, so we just return\n"));
|
|
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiPnPPowerComplete\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiDeregisterPnPHandlers(
|
|
IN HANDLE BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to deregister the provider.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiDERegisterPnPHandlers\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
BindingHandle,
|
|
TDI_DEREGISTER_HANDLERS_PNP
|
|
);
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiDERegisterPnPHandlers\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TdiPnPPowerRequest(
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PNET_PNP_EVENT PnpPowerEvent,
|
|
IN PTDI_PNP_CONTEXT Context1,
|
|
IN PTDI_PNP_CONTEXT Context2,
|
|
IN ProviderPnPPowerComplete ProtocolCompletionHandler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
DeviceName
|
|
PowerEvent: Choice of QUERYPOWER/SETPOWER
|
|
|
|
Return Value:
|
|
|
|
The status of the attempt to deregister the provider.
|
|
|
|
--*/
|
|
{
|
|
PTDI_PROVIDER_RESOURCE NewResource, Context;
|
|
NTSTATUS Status;
|
|
PWCHAR Buffer;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiPnPPowerRequest\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
CTEAssert(ProtocolCompletionHandler);
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_PROVIDER_RESOURCE),
|
|
'hIDT'
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewResource == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Try and get a buffer to hold the name.
|
|
|
|
Buffer = (PWCHAR)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
DeviceName->MaximumLength,
|
|
'iIDT'
|
|
);
|
|
|
|
if (Buffer == NULL) {
|
|
ExFreePool(NewResource);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Fill in the basic stuff.
|
|
NewResource->Common.Type = TDI_RESOURCE_POWER;
|
|
NewResource->Specific.Device.DeviceName.MaximumLength =
|
|
DeviceName->MaximumLength;
|
|
|
|
NewResource->Specific.Device.DeviceName.Buffer = Buffer;
|
|
|
|
NewResource->PnPCompleteHandler = ProtocolCompletionHandler;
|
|
|
|
Context = *((PTDI_PROVIDER_RESOURCE *) PnpPowerEvent->TdiReserved);
|
|
|
|
if (NULL == Context) {
|
|
|
|
TDI_DEBUG(POWER, ("New NetPnP Event\n"));
|
|
|
|
TDI_LOG(LOG_POWER, ("New pnp event %X, %wZ\n", NewResource, DeviceName));
|
|
|
|
*((PVOID *) PnpPowerEvent->TdiReserved) = (PVOID) NewResource;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This NetPnp structure has looped thru before
|
|
// Loop thru and find out the last one.
|
|
//
|
|
while (Context->PreviousContext) {
|
|
Context = Context->PreviousContext;
|
|
}
|
|
|
|
Context->PreviousContext = NewResource;
|
|
|
|
TDI_LOG(LOG_POWER, ("pnp event linking %X to %X, %wZ\n",
|
|
Context, NewResource, DeviceName));
|
|
}
|
|
|
|
NewResource->PreviousContext = NULL;
|
|
|
|
NewResource->PnpPowerEvent = PnpPowerEvent;
|
|
NewResource->Status = STATUS_SUCCESS;
|
|
|
|
// Note: These pointers must be good for the duration of this call.
|
|
if (Context1) {
|
|
|
|
NewResource->Context1 = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
FIELD_OFFSET(TDI_PNP_CONTEXT, ContextData)
|
|
+ Context1->ContextSize,
|
|
'xIDT'
|
|
);
|
|
|
|
if (NULL == NewResource->Context1) {
|
|
|
|
if (Context) {
|
|
Context->PreviousContext = NULL;
|
|
}
|
|
|
|
ExFreePool(NewResource);
|
|
ExFreePool(Buffer);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
NewResource->Context1->ContextSize = Context1->ContextSize;
|
|
NewResource->Context1->ContextType = Context1->ContextType;
|
|
|
|
RtlCopyMemory(
|
|
NewResource->Context1->ContextData,
|
|
Context1->ContextData,
|
|
Context1->ContextSize
|
|
);
|
|
|
|
} else {
|
|
NewResource->Context1 = NULL;
|
|
}
|
|
|
|
if (Context2) {
|
|
|
|
NewResource->Context2 = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
FIELD_OFFSET(TDI_PNP_CONTEXT, ContextData)
|
|
+ Context2->ContextSize,
|
|
'yIDT'
|
|
);
|
|
if (NULL == NewResource->Context2) {
|
|
|
|
ExFreePool(Buffer);
|
|
|
|
if (NewResource->Context1) {
|
|
ExFreePool(NewResource->Context1);
|
|
}
|
|
|
|
if (Context) {
|
|
|
|
Context->PreviousContext = NULL;
|
|
}
|
|
|
|
ExFreePool(NewResource);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
NewResource->Context2->ContextSize = Context2->ContextSize;
|
|
NewResource->Context2->ContextType = Context2->ContextType;
|
|
RtlCopyMemory(
|
|
NewResource->Context2->ContextData,
|
|
Context2->ContextData,
|
|
Context2->ContextSize
|
|
);
|
|
|
|
} else {
|
|
NewResource->Context2 = NULL;
|
|
}
|
|
|
|
|
|
RtlCopyUnicodeString(
|
|
&NewResource->Specific.Device.DeviceName,
|
|
DeviceName
|
|
);
|
|
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewResource,
|
|
TDI_REGISTER_PNP_POWER_EVENT
|
|
);
|
|
|
|
//
|
|
// If TdiHandleSerialized returns PENDING, then the contexts and Resource
|
|
// structures are freed up in the TdiPnPComplete call.
|
|
//
|
|
if (STATUS_PENDING != Status) {
|
|
|
|
Status = NewResource->Status; // The status is stored in the newresource.
|
|
|
|
ExFreePool(Buffer);
|
|
|
|
if (NewResource->Context1) {
|
|
ExFreePool(NewResource->Context1);
|
|
NewResource->Context1 = NULL;
|
|
}
|
|
|
|
if (NewResource->Context2) {
|
|
ExFreePool(NewResource->Context2);
|
|
NewResource->Context2 = NULL;
|
|
}
|
|
|
|
if (Context) {
|
|
Context->PreviousContext = NULL;
|
|
}
|
|
|
|
TDI_LOG(LOG_POWER, ("%X completed sync, Status %X\n",
|
|
NewResource, Status));
|
|
|
|
ExFreePool(NewResource); // free resources anyways
|
|
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiPnPPowerRequest : %lx\n", Status));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
// This function is private between NDIS and TDI
|
|
// In TdiInitialize we need to pass a pointer to this function.
|
|
NTSTATUS
|
|
TdiMakeNCPAChanges(
|
|
IN TDI_NCPA_BINDING_INFO NcpaBindingInfo
|
|
)
|
|
|
|
{
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Purpose: Count the number of bytes of a double NULL terminated
|
|
// multi-sz, including all NULLs except for the final terminating
|
|
// NULL.
|
|
//
|
|
// Arguments:
|
|
// pmsz [in] The multi-sz to count bytes for.
|
|
//
|
|
// Returns: The count of bytes.
|
|
//
|
|
ULONG
|
|
TdipCbOfMultiSzSafe (
|
|
IN PCWSTR pmsz)
|
|
{
|
|
ULONG cchTotal = 0;
|
|
ULONG cch;
|
|
|
|
// NULL strings have zero length by definition.
|
|
if (!pmsz)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
while (*pmsz)
|
|
{
|
|
cch = wcslen (pmsz) + 1;
|
|
cchTotal += cch;
|
|
pmsz += cch;
|
|
}
|
|
|
|
// Return the count of bytes.
|
|
return cchTotal * sizeof (WCHAR);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Purpose: Search for a string in a multi-sz.
|
|
//
|
|
// Arguments:
|
|
// psz [in] The string to search for.
|
|
// pmsz [in] The multi-sz search in.
|
|
//
|
|
// Returns: TRUE if string was found in the multi-sz.
|
|
//
|
|
BOOLEAN
|
|
TdipIsSzInMultiSzSafe (
|
|
IN PCWSTR pszSearchString,
|
|
IN PCWSTR pmsz)
|
|
{
|
|
if (!pmsz || !pszSearchString)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
while (*pmsz)
|
|
{
|
|
if (0 == _wcsicmp (pmsz, pszSearchString))
|
|
{
|
|
return TRUE;
|
|
}
|
|
pmsz += wcslen (pmsz) + 1;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Purpose: Remove strings in a multi-sz list from an array of strings.
|
|
//
|
|
// Arguments:
|
|
// pmszToRemove [in] The strings we need to remove.
|
|
// pszArray [inout] The array of strings to modify.
|
|
// ItemsInArray [in] The number of items in the array.
|
|
// pRemainingItems [out] The number of items remaining in the array
|
|
// after we have removed all items that
|
|
// match pmszToRemove.
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
VOID
|
|
TdipRemoveMultiSzFromSzArray (
|
|
IN PWSTR pmszToRemove,
|
|
IN OUT PWSTR* pszArray,
|
|
IN ULONG ItemsInArray,
|
|
OUT ULONG* pRemainingItems)
|
|
{
|
|
PWSTR pszScan;
|
|
ULONG i, j;
|
|
ULONG ItemsRemoved;
|
|
|
|
ASSERT(pRemainingItems);
|
|
|
|
*pRemainingItems = ItemsInArray;
|
|
|
|
if (!pszArray || !pszArray[0] ||
|
|
!pmszToRemove || !*pmszToRemove)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Go through the string array.
|
|
//
|
|
ItemsRemoved = 0;
|
|
for (i = 0; pszArray[i]; i++)
|
|
{
|
|
// Check each string in the remove multi-sz against
|
|
// the current array string.
|
|
//
|
|
pszScan = pmszToRemove;
|
|
while (*pszScan)
|
|
{
|
|
if (0 == _wcsicmp (pszScan, pszArray[i]))
|
|
{
|
|
ItemsRemoved++;
|
|
|
|
// The string needs to be removed.
|
|
// Just move the indexes down one slot.
|
|
//
|
|
for (j = i; pszArray[j]; j++)
|
|
{
|
|
pszArray[j] = pszArray[j + 1];
|
|
}
|
|
|
|
// If we removed the last item in the list, get out of the
|
|
// loop. Note that the next entry is also NULL which
|
|
// will cause us to get out of our paraent for loop as
|
|
// well.
|
|
//
|
|
if (!pszArray[i])
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Reset the scan string since the current indexed
|
|
// entry is now the next entry. This means we run the
|
|
// scan again.
|
|
pszScan = pmszToRemove;
|
|
}
|
|
else
|
|
{
|
|
pszScan += wcslen (pszScan) + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the count of items in the array.
|
|
*pRemainingItems = ItemsInArray - ItemsRemoved;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Purpose: Remove a multi-sz of strings from another multi-sz of strings.
|
|
//
|
|
// Arguments:
|
|
// pmszToRemove [in] The strings to remove.
|
|
// pmszToModify [in] The list to modify.
|
|
//
|
|
// Returns: nothing.
|
|
//
|
|
VOID
|
|
TdipRemoveMultiSzFromMultiSz (
|
|
IN PCWSTR pmszToRemove,
|
|
IN OUT PWSTR pmszToModify)
|
|
{
|
|
BOOLEAN fRemoved;
|
|
PCWSTR pszScan;
|
|
if (!pmszToModify || !pmszToRemove || !*pmszToRemove)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Look for each pmszToRemove string in pmsz. When it is found, move
|
|
// the remaining part of the pmsz over it.
|
|
//
|
|
while (*pmszToModify)
|
|
{
|
|
fRemoved = FALSE;
|
|
|
|
pszScan = pmszToRemove;
|
|
while (*pszScan)
|
|
{
|
|
ULONG cchScan = wcslen (pszScan);
|
|
if (0 == _wcsicmp (pmszToModify, pszScan))
|
|
{
|
|
PWSTR pmszRemain = pmszToModify + cchScan + 1;
|
|
|
|
// Count the remaining bytes including the final terminator;
|
|
INT cbRemain = TdipCbOfMultiSzSafe (pmszRemain) + sizeof (WCHAR);
|
|
|
|
RtlMoveMemory (pmszToModify, pmszRemain, cbRemain);
|
|
|
|
fRemoved = TRUE;
|
|
|
|
break;
|
|
}
|
|
pszScan += cchScan + 1;
|
|
}
|
|
|
|
// If we didn't remove the current modify string, advance our
|
|
// pointer.
|
|
//
|
|
if (!fRemoved)
|
|
{
|
|
pmszToModify += wcslen (pmszToModify) + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Purpose: Adds a multi-sz of strings to another multi-sz.
|
|
//
|
|
// Arguments:
|
|
// pUniStringToAdd - [in] The Unicode string that contains the multisz.
|
|
// pmszModify [in] The multi-sz to add to.
|
|
//
|
|
// Returns: NT status code. Either STATUS_SUCCESS or
|
|
// STATUS_INSUFFICIENT_RESOURCES
|
|
//
|
|
NTSTATUS
|
|
TdipAddMultiSzToMultiSz (
|
|
IN PUNICODE_STRING pUniStringToAdd,
|
|
IN PCWSTR pmszModify,
|
|
OUT PWSTR* ppmszOut)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PCWSTR pszScan;
|
|
ULONG cbNeeded;
|
|
PCWSTR pmszAdd = NULL;
|
|
|
|
ASSERT(ppmszOut);
|
|
|
|
// Initialize the output parameters.
|
|
//
|
|
*ppmszOut = NULL;
|
|
|
|
pmszAdd = pUniStringToAdd->Buffer;
|
|
ASSERT(pmszAdd);
|
|
|
|
// Validate the input - all multisz have 2 End -Of -String
|
|
// characters at the end of the unicode string
|
|
//
|
|
{
|
|
ULONG LenWchar = pUniStringToAdd->Length/2; // Length is in bytes
|
|
if(LenWchar <= 2) // is Multisz long enough for our checks
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
if (pmszAdd[LenWchar -1] != 0) // is Multisz null terminated
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (pmszAdd[LenWchar-2] != 0) // is the last string in multisz null terminated
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
}
|
|
// Go through the multi-sz to add and compute how much space we need.
|
|
//
|
|
|
|
for (pszScan = pmszAdd, cbNeeded = 0; *pszScan; pszScan += wcslen (pszScan) + 1)
|
|
{
|
|
// Check if the string is already present in the pmszModify.
|
|
// If it is not, add its size to our total.
|
|
if (!TdipIsSzInMultiSzSafe (pszScan, pmszModify))
|
|
{
|
|
cbNeeded += (wcslen (pszScan) + 1) * sizeof (WCHAR);
|
|
}
|
|
}
|
|
|
|
// If we have something to add...
|
|
//
|
|
if (cbNeeded)
|
|
{
|
|
ULONG cbDataSize;
|
|
ULONG cbAllocSize;
|
|
PWSTR pmszNew;
|
|
|
|
// Get size of current multi-sz.
|
|
cbDataSize = TdipCbOfMultiSzSafe (pmszModify);
|
|
|
|
// Enough space for the old data plus the new string and NULL, and for the
|
|
// second trailing NULL (multi-szs are double-terminated)
|
|
cbAllocSize = cbDataSize + cbNeeded + sizeof (WCHAR);
|
|
|
|
pmszNew = (PWSTR)ExAllocatePoolWithTag (
|
|
NonPagedPool, cbAllocSize, 'jIDT');
|
|
|
|
if (pmszNew)
|
|
{
|
|
ULONG cchOffset;
|
|
|
|
cchOffset = cbDataSize / sizeof (WCHAR);
|
|
RtlZeroMemory (pmszNew, cbAllocSize);
|
|
|
|
// Copy the current buffer into the new buffer.
|
|
RtlCopyMemory (pmszNew, pmszModify, cbDataSize);
|
|
|
|
pszScan = pmszAdd;
|
|
while (*pszScan)
|
|
{
|
|
// Check if the string is already present in the new buffer.
|
|
if (!TdipIsSzInMultiSzSafe (pszScan, pmszNew))
|
|
{
|
|
wcscpy (pmszNew + cchOffset, pszScan);
|
|
cchOffset += wcslen (pmszNew + cchOffset) + 1;
|
|
}
|
|
|
|
pszScan += wcslen (pszScan) + 1;
|
|
}
|
|
|
|
*ppmszOut = pmszNew;
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
TDI_DEBUG(ERROR, ("TdipAddMultiSzToMultiSz: Insufficient resources\n"));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// Purpose: Prints the contents of a multi-sz list.
|
|
//
|
|
// Arguments:
|
|
// pmsz [in] The multi-sz to print.
|
|
//
|
|
// Returns: nothing.
|
|
//
|
|
#if DBG
|
|
VOID
|
|
TdipPrintMultiSz (
|
|
IN PCWSTR pmsz)
|
|
{
|
|
if (pmsz && *pmsz)
|
|
{
|
|
while (*pmsz)
|
|
{
|
|
TDI_DEBUG(BIND, ("%S\n", pmsz));
|
|
pmsz += wcslen (pmsz) + 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN
|
|
TdipMultiSzStrStr(
|
|
PWSTR *TdiClientBindingList,
|
|
PUNICODE_STRING DeviceName
|
|
)
|
|
{
|
|
int i;
|
|
|
|
TDI_DEBUG(FUNCTION2, ("++ TdipMultiSzStrStr\n"));
|
|
|
|
// look for the string in the multiszstring
|
|
if( TdiClientBindingList == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check to see if this device is one of the devices
|
|
// we're interested in.
|
|
//
|
|
for( i=0; TdiClientBindingList[i]; i++ ) {
|
|
if( DeviceName->Length / sizeof( WCHAR ) != wcslen( TdiClientBindingList[i] ) ) {
|
|
continue;
|
|
}
|
|
if( _wcsnicmp( DeviceName->Buffer,
|
|
TdiClientBindingList[i],
|
|
DeviceName->Length / sizeof( WCHAR ) ) == 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we hit the end of the list, then DeviceName is not a device we're
|
|
// interested in.
|
|
//
|
|
if( TdiClientBindingList[i] == NULL ) {
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdipMultiSzStrStr: NULL\n"));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdipMultiSzStrStr\n"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
TdipGetMultiSZList(
|
|
OUT PWSTR **ListPointer,
|
|
IN PWSTR BaseKeyName,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PWSTR Linkage,
|
|
IN PWSTR ParameterKeyName,
|
|
OUT PUINT NumEntries
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queries a registry value key for its MULTI_SZ values.
|
|
|
|
Arguments:
|
|
|
|
ListPointer - Pointer to receive the pointer.
|
|
ParameterKeyValue - Name of the value parameter to query.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeKeyName;
|
|
UNICODE_STRING unicodeParamPath;
|
|
OBJECT_ATTRIBUTES objAttributes;
|
|
HANDLE keyHandle;
|
|
WCHAR ParamBuffer[MAX_UNICODE_BUFLEN];
|
|
|
|
ULONG lengthNeeded;
|
|
ULONG i;
|
|
ULONG numberOfEntries;
|
|
ULONG numberOfDefaultEntries = 0;
|
|
NTSTATUS status;
|
|
|
|
INT copyflag = 0;
|
|
PWCHAR regEntry;
|
|
PWCHAR dataEntry;
|
|
PWSTR *ptrEntry;
|
|
PCHAR newBuffer;
|
|
PKEY_VALUE_FULL_INFORMATION infoBuffer = NULL;
|
|
|
|
TDI_DEBUG(FUNCTION2, ("++ TdipGetMultiSzList\n"));
|
|
|
|
unicodeParamPath.Length = 0;
|
|
unicodeParamPath.MaximumLength = MAX_UNICODE_BUFLEN;
|
|
unicodeParamPath.Buffer = ParamBuffer;
|
|
|
|
// BaseKeyName :\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
|
|
RtlAppendUnicodeToString(&unicodeParamPath, BaseKeyName);
|
|
|
|
// Add DeviceName to it.
|
|
RtlAppendUnicodeStringToString(&unicodeParamPath, DeviceName);
|
|
|
|
// Add Linkage to it.
|
|
RtlAppendUnicodeToString(&unicodeParamPath, Linkage);
|
|
|
|
RtlInitUnicodeString( &unicodeKeyName, ParameterKeyName );
|
|
|
|
InitializeObjectAttributes(
|
|
&objAttributes,
|
|
&unicodeParamPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = ZwOpenKey(
|
|
&keyHandle,
|
|
KEY_QUERY_VALUE,
|
|
&objAttributes
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
TDI_DEBUG(REGISTRY, ("tdi.sys Cannot open key: %x!!\n", status));
|
|
goto use_default;
|
|
}
|
|
|
|
status = ZwQueryValueKey(
|
|
keyHandle,
|
|
&unicodeKeyName,
|
|
KeyValueFullInformation,
|
|
NULL,
|
|
0,
|
|
&lengthNeeded
|
|
);
|
|
|
|
if ( status != STATUS_BUFFER_TOO_SMALL ) {
|
|
NtClose( keyHandle );
|
|
TDI_DEBUG(REGISTRY, ("tdi.sys Cannot query buffer!!\n"));
|
|
goto use_default;
|
|
}
|
|
|
|
infoBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
lengthNeeded,
|
|
'jIDT'
|
|
);
|
|
|
|
if ( infoBuffer == NULL ) {
|
|
NtClose( keyHandle );
|
|
TDI_DEBUG(REGISTRY, ("tdi.sys Cannot alloc buffer!!\n"));
|
|
|
|
goto use_default;
|
|
}
|
|
|
|
status = ZwQueryValueKey(
|
|
keyHandle,
|
|
&unicodeKeyName,
|
|
KeyValueFullInformation,
|
|
infoBuffer,
|
|
lengthNeeded,
|
|
&lengthNeeded
|
|
);
|
|
|
|
NtClose( keyHandle );
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
TDI_DEBUG(REGISTRY, ("tdi.sys Cannot query buffer (2) !!\n"));
|
|
|
|
goto freepool_and_use_default;
|
|
}
|
|
|
|
//
|
|
// Figure out how many entries there are.
|
|
//
|
|
// numberOfEntries should be total number of entries + 1. The extra
|
|
// one is for the NULL sentinel entry.
|
|
//
|
|
|
|
lengthNeeded = infoBuffer->DataLength;
|
|
if ( lengthNeeded <= sizeof(WCHAR) ) {
|
|
|
|
//
|
|
// No entries on the list. Use default.
|
|
//
|
|
|
|
goto freepool_and_use_default;
|
|
}
|
|
|
|
dataEntry = (PWCHAR)((PCHAR)infoBuffer + infoBuffer->DataOffset);
|
|
for ( i = 0, regEntry = dataEntry, numberOfEntries = 0;
|
|
i < lengthNeeded;
|
|
i += sizeof(WCHAR) ) {
|
|
|
|
if ( *regEntry++ == L'\0' ) {
|
|
numberOfEntries++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate space needed for the array of pointers. This is in addition
|
|
// to the ones in the default list.
|
|
//
|
|
|
|
newBuffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
lengthNeeded +
|
|
(numberOfEntries) *
|
|
sizeof( PWSTR ),
|
|
'kIDT'
|
|
);
|
|
|
|
if ( newBuffer == NULL ) {
|
|
goto freepool_and_use_default;
|
|
}
|
|
|
|
//
|
|
// Copy the names
|
|
//
|
|
|
|
regEntry = (PWCHAR)(newBuffer + (numberOfEntries) * sizeof(PWSTR));
|
|
|
|
RtlCopyMemory(
|
|
regEntry,
|
|
dataEntry,
|
|
lengthNeeded
|
|
);
|
|
|
|
//
|
|
// Free the info buffer
|
|
//
|
|
|
|
ExFreePool(infoBuffer);
|
|
|
|
ptrEntry = (PWSTR *) newBuffer;
|
|
|
|
//
|
|
// Build the array of pointers. If numberOfEntries is 1, then
|
|
// it means that the list is empty.
|
|
//
|
|
|
|
if ( numberOfEntries > 1 ) {
|
|
|
|
*ptrEntry++ = regEntry++;
|
|
|
|
//
|
|
// Skip the first WCHAR and the last 2 NULL terminators.
|
|
//
|
|
|
|
for ( i = 3*sizeof(WCHAR) ; i < lengthNeeded ; i += sizeof(WCHAR) ) {
|
|
if ( *regEntry++ == L'\0' ) {
|
|
*ptrEntry++ = regEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
*ptrEntry = NULL;
|
|
*ListPointer = (PWSTR *)newBuffer;
|
|
TDI_DEBUG(FUNCTION2, ("-- TdipGetMultiSzList\n"));
|
|
*NumEntries = numberOfEntries;
|
|
return;
|
|
|
|
freepool_and_use_default:
|
|
|
|
ExFreePool(infoBuffer); // doesnt get freed otherwise
|
|
|
|
use_default:
|
|
|
|
*ListPointer = NULL;
|
|
*NumEntries = 0;
|
|
TDI_DEBUG(REGISTRY, ("GetRegStrings: There was an error : returning NULL\r\n"));
|
|
TDI_DEBUG(FUNCTION2, ("-- TdipGetMultiSzList: error\n"));
|
|
|
|
return;
|
|
|
|
} // TdipGetMultiSZList
|
|
|
|
|
|
NTSTATUS
|
|
TdiPnPHandler(
|
|
IN PUNICODE_STRING UpperComponent,
|
|
IN PUNICODE_STRING LowerComponent,
|
|
IN PUNICODE_STRING BindList,
|
|
IN PVOID ReconfigBuffer,
|
|
IN UINT ReconfigBufferSize,
|
|
IN UINT Operation
|
|
)
|
|
{
|
|
PTDI_NCPA_BINDING_INFO NdisElement;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiPnPHandler\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
NdisElement = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_NCPA_BINDING_INFO),
|
|
'kIDT'
|
|
);
|
|
|
|
if (NdisElement == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
NdisElement->TdiClientName = UpperComponent;
|
|
NdisElement->TdiProviderName = LowerComponent;
|
|
NdisElement->BindList = BindList;
|
|
NdisElement->ReconfigBuffer = ReconfigBuffer;
|
|
NdisElement->ReconfigBufferSize = ReconfigBufferSize;
|
|
NdisElement->PnpOpcode = Operation;
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NdisElement,
|
|
TDI_NDIS_IOCTL_HANDLER_PNP
|
|
);
|
|
|
|
ExFreePool(NdisElement);
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiPnPHandler\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Call the AddAddress handler of the client along with all the
|
|
registered TDI addresses.
|
|
|
|
Arguments:
|
|
|
|
Input: Handle to the client context
|
|
Output: NTSTATUS = Success/Failure
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
TdiEnumerateAddresses(
|
|
IN HANDLE BindingHandle
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiEnumerateAddresses\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
BindingHandle,
|
|
TDI_ENUMERATE_ADDRESSES
|
|
);
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiEnumerateAddresses\n"));
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-TdiEnumerateAddresses %d\n", Status));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Register a generic provider with TDI.
|
|
Each transport is a provider and teh devices that it registers are
|
|
what constitute a transport. When a transport thinks it has all the
|
|
devices ready, it calls TdiNetReady API.
|
|
|
|
Arguments:
|
|
|
|
Input: Device Name
|
|
Output: Handle to be used in future references.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
*/
|
|
NTSTATUS
|
|
TdiRegisterProvider(
|
|
PUNICODE_STRING ProviderName,
|
|
HANDLE *ProviderHandle
|
|
)
|
|
{
|
|
|
|
PTDI_PROVIDER_RESOURCE NewResource;
|
|
NTSTATUS Status;
|
|
PWCHAR Buffer;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiRegisterProvider\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TdiInitialize();
|
|
|
|
// make sure that the transports arent screwing us.
|
|
CTEAssert(ProviderName);
|
|
CTEAssert(ProviderName->Buffer);
|
|
CTEAssert(ProviderHandle);
|
|
|
|
TDI_DEBUG(PROVIDERS, (" %wZ provider is being Registered\n", ProviderName));
|
|
|
|
// First, try and allocate the needed resource.
|
|
NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(TDI_PROVIDER_RESOURCE),
|
|
'cIDT'
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewResource == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Try and get a buffer to hold the name.
|
|
Buffer = (PWCHAR)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
ProviderName->MaximumLength,
|
|
'dIDT'
|
|
);
|
|
|
|
if (Buffer == NULL) {
|
|
ExFreePool(NewResource);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Fill in the basic stuff.
|
|
RtlZeroMemory(
|
|
NewResource,
|
|
sizeof(TDI_PROVIDER_RESOURCE)
|
|
);
|
|
|
|
NewResource->Common.Type = TDI_RESOURCE_PROVIDER;
|
|
NewResource->Specific.Device.DeviceName.MaximumLength =
|
|
ProviderName->MaximumLength;
|
|
|
|
NewResource->Specific.Device.DeviceName.Buffer = Buffer;
|
|
|
|
RtlCopyUnicodeString(
|
|
&NewResource->Specific.Device.DeviceName,
|
|
ProviderName
|
|
);
|
|
|
|
*ProviderHandle = (HANDLE)NewResource;
|
|
|
|
TDI_DEBUG(PROVIDERS, ("Registering Device Object\n"));
|
|
|
|
|
|
NewResource->Context1 = NULL;
|
|
NewResource->Context2 = NULL;
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewResource,
|
|
TDI_REGISTER_PROVIDER_PNP
|
|
);
|
|
|
|
CTEAssert(STATUS_SUCCESS == Status);
|
|
|
|
if (STATUS_SUCCESS != Status) {
|
|
ExFreePool(Buffer);
|
|
ExFreePool(NewResource);
|
|
*ProviderHandle = NULL;
|
|
}
|
|
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiRegisterProvider\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-RegisterProvider rc=%d h=%X %wZ\n",
|
|
Status, *ProviderHandle, ProviderName));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Indicate that a registered provider is ready.
|
|
This means that it thinks that all its devices are
|
|
ready to be used.
|
|
|
|
Arguments:
|
|
|
|
Input: Handle to the client context
|
|
Output: NTSTATUS = Success/Failure
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
|
|
*/
|
|
NTSTATUS
|
|
TdiProviderReady(
|
|
HANDLE ProviderHandle
|
|
)
|
|
{
|
|
|
|
PTDI_PROVIDER_RESOURCE ProvResource = ProviderHandle;
|
|
NTSTATUS Status;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiProviderReady\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
CTEAssert(ProviderHandle);
|
|
|
|
TDI_DEBUG(PROVIDERS, (" %wZ provider is READY\n", &ProvResource->Specific.Device.DeviceName));
|
|
|
|
CTEAssert(!ProvResource->ProviderReady); // doing it twice?
|
|
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
ProvResource,
|
|
TDI_PROVIDER_READY_PNP
|
|
);
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiProviderReady\n"));
|
|
|
|
CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
TDI_LOG(LOG_REGISTER, ("-TdiProviderReady rc=%d %wZ\n",
|
|
Status, &ProvResource->Specific.Device.DeviceName));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Deregister a generic provider with TDI.
|
|
|
|
Arguments:
|
|
|
|
Inpute: Handle to the provider structure.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
|
|
*/
|
|
NTSTATUS
|
|
TdiDeregisterProvider(
|
|
HANDLE ProviderHandle
|
|
)
|
|
{
|
|
|
|
PTDI_PROVIDER_RESOURCE ProvResource = ProviderHandle;
|
|
NTSTATUS Status;
|
|
|
|
TDI_DEBUG(FUNCTION, ("++ TdiDeregisterProvider\n"));
|
|
|
|
CTEAssert(ProviderHandle);
|
|
|
|
TDI_DEBUG(PROVIDERS, (" %wZ provider is being Deregistered\n", &ProvResource->Specific.Device.DeviceName));
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
ProvResource,
|
|
TDI_DEREGISTER_PROVIDER_PNP
|
|
);
|
|
|
|
TDI_DEBUG(FUNCTION, ("-- TdiDeregisterProvider\n"));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Input: New Client
|
|
// Pointer to the OpenList
|
|
// Output: success/failure (boolean)
|
|
//
|
|
// This function takes in the new client and builds all the OPEN structures that
|
|
// need to be built (all the providers that this client is bound to). If the
|
|
// provider doesnt exist at this time, we just point it to NULL and change it
|
|
// when the provider (deviceobject) registers itself.
|
|
//
|
|
//
|
|
|
|
BOOLEAN
|
|
TdipBuildProviderList(
|
|
PTDI_NOTIFY_PNP_ELEMENT NotifyElement
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
TDI_DEBUG(FUNCTION2, ("++ TdipBuildOpenList\n"));
|
|
|
|
TdipGetMultiSZList(
|
|
&NotifyElement->ListofProviders,
|
|
StrRegTdiBindingsBasicPath,
|
|
&NotifyElement->ElementName,
|
|
StrRegTdiLinkage,
|
|
StrRegTdiBindList,
|
|
&NotifyElement->NumberofEntries
|
|
);
|
|
|
|
// look for the string in the multiszstring
|
|
if (NotifyElement->ListofProviders == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
TDI_DEBUG(BIND, ("Added %d Entries\n", NotifyElement->NumberofEntries));
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- TdipBuildOpenList\n"));
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Takes provider (devicename) and returns a pointer to the
|
|
// internal provider structure if it exists.
|
|
//
|
|
PTDI_PROVIDER_RESOURCE
|
|
LocateProviderContext(
|
|
PUNICODE_STRING ProviderName
|
|
)
|
|
{
|
|
|
|
PLIST_ENTRY Current;
|
|
PTDI_PROVIDER_RESOURCE ProviderElement = NULL;
|
|
|
|
TDI_DEBUG(FUNCTION2, ("++ LocateProviderContext\n"));
|
|
|
|
Current = PnpHandlerProviderList.Flink;
|
|
|
|
while (Current != &PnpHandlerProviderList) {
|
|
|
|
ProviderElement = CONTAINING_RECORD(
|
|
Current,
|
|
TDI_PROVIDER_RESOURCE,
|
|
Common.Linkage
|
|
);
|
|
|
|
if (ProviderElement->Common.Type != TDI_RESOURCE_DEVICE) {
|
|
Current = Current->Flink;
|
|
continue;
|
|
}
|
|
|
|
if (!RtlCompareUnicodeString(
|
|
ProviderName,
|
|
&ProviderElement->Specific.Device.DeviceName,
|
|
TRUE)) {
|
|
TDI_DEBUG(BIND, ("Provider is registered with TDI\n"));
|
|
break;
|
|
|
|
}
|
|
|
|
Current = Current->Flink;
|
|
|
|
}
|
|
|
|
TDI_DEBUG(FUNCTION2, ("-- LocateProviderContext\n"));
|
|
|
|
return ProviderElement;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// Cool new memory logging functions added to keep track of the store
|
|
// and forward functionality in TDI (while debugging).
|
|
//
|
|
|
|
VOID
|
|
DbgMsgInit()
|
|
{
|
|
|
|
First = 0;
|
|
Last = 0;
|
|
|
|
CTEInitLock(&DbgLock);
|
|
|
|
}
|
|
|
|
VOID
|
|
DbgMsg(CHAR *Format, ...)
|
|
{
|
|
va_list Args;
|
|
CTELockHandle LockHandle;
|
|
CHAR Temp[MAX_MSG_LEN];
|
|
LONG numCharWritten;
|
|
|
|
va_start(Args, Format);
|
|
|
|
numCharWritten = _vsnprintf(Temp, MAX_MSG_LEN, Format, Args);
|
|
|
|
if (numCharWritten < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Zero Terminate the string
|
|
//
|
|
Temp[numCharWritten] = '\0';
|
|
|
|
if (TdiLogOutput & LOG_OUTPUT_DEBUGGER)
|
|
{
|
|
DbgPrint(Temp);
|
|
}
|
|
|
|
if (TdiLogOutput & LOG_OUTPUT_BUFFER)
|
|
{
|
|
CTEGetLock(&DbgLock, &LockHandle);
|
|
|
|
RtlZeroMemory(DbgMsgs[Last], MAX_MSG_LEN);
|
|
strcpy(DbgMsgs[Last], Temp);
|
|
|
|
Last++;
|
|
|
|
if (Last == LOG_MSG_CNT)
|
|
Last = 0;
|
|
|
|
if (First == Last) {
|
|
First++;
|
|
if (First == LOG_MSG_CNT)
|
|
First = 0;
|
|
}
|
|
|
|
CTEFreeLock(&DbgLock, LockHandle);
|
|
}
|
|
|
|
va_end(Args);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|