mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1029 lines
21 KiB
1029 lines
21 KiB
/*++
|
|
|
|
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
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include <ntddk.h>
|
|
#include <ndis.h>
|
|
#include <tdi.h>
|
|
#include <tdikrnl.h>
|
|
#include "tdipnp.h"
|
|
|
|
KSPIN_LOCK TDIListLock;
|
|
|
|
LIST_ENTRY BindClientList;
|
|
|
|
LIST_ENTRY NetAddressClientList;
|
|
|
|
LIST_ENTRY BindProviderList;
|
|
|
|
LIST_ENTRY NetAddressProviderList;
|
|
|
|
LIST_ENTRY BindRequestList;
|
|
|
|
LIST_ENTRY NetAddressRequestList;
|
|
|
|
BOOLEAN BindRequestInProgress;
|
|
|
|
PETHREAD BindRequestThread;
|
|
|
|
BOOLEAN AddressRequestInProgress;
|
|
|
|
PETHREAD AddressRequestThread;
|
|
|
|
VOID
|
|
TdiNotifyClientList (
|
|
PLIST_ENTRY ListHead,
|
|
PVOID Info,
|
|
BOOLEAN Added
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a new provider is added or deleted. We walk the specified
|
|
client list and notify all of the clients of what just occured.
|
|
|
|
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_ELEMENT NotifyElement;
|
|
PTDI_PROVIDER_RESOURCE Provider;
|
|
|
|
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
|
|
);
|
|
|
|
// Walk the input client list, and for every element in it
|
|
// notifhy the client.
|
|
|
|
while (Current != ListHead) {
|
|
|
|
NotifyElement = CONTAINING_RECORD(
|
|
Current,
|
|
TDI_NOTIFY_ELEMENT,
|
|
Common.Linkage
|
|
);
|
|
|
|
if (Provider->Common.Type == TDI_RESOURCE_DEVICE) {
|
|
// This is a device object provider.
|
|
|
|
// This must be a notify bind element.
|
|
|
|
|
|
// If this is a device coming in, call the bind handler,
|
|
// else call the unbind handler.
|
|
|
|
if (Added) {
|
|
(*(NotifyElement->Specific.BindElement.BindHandler))(
|
|
&Provider->Specific.Device.DeviceName
|
|
);
|
|
} else {
|
|
(*(NotifyElement->Specific.BindElement.UnbindHandler))(
|
|
&Provider->Specific.Device.DeviceName
|
|
);
|
|
}
|
|
} else {
|
|
|
|
// 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 (Added) {
|
|
(*(NotifyElement->Specific.AddressElement.AddHandler))(
|
|
&Provider->Specific.NetAddress.Address
|
|
);
|
|
} else {
|
|
(*(NotifyElement->Specific.AddressElement.DeleteHandler))(
|
|
&Provider->Specific.NetAddress.Address
|
|
);
|
|
}
|
|
}
|
|
|
|
// Get the next one.
|
|
|
|
Current = Current->Flink;
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
TdiNotifyNewClient (
|
|
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_ELEMENT NotifyElement;
|
|
|
|
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;
|
|
|
|
// 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
|
|
);
|
|
|
|
NotifyElement = CONTAINING_RECORD(
|
|
NotifyCommon,
|
|
TDI_NOTIFY_ELEMENT,
|
|
Common
|
|
);
|
|
|
|
if (NotifyCommon->Type == TDI_NOTIFY_DEVICE) {
|
|
|
|
// This is a bind notify client.
|
|
|
|
|
|
|
|
(*(NotifyElement->Specific.BindElement.BindHandler))(
|
|
&Provider->Specific.Device.DeviceName
|
|
);
|
|
|
|
} else {
|
|
// This is an address notify client.
|
|
|
|
(*(NotifyElement->Specific.AddressElement.AddHandler))(
|
|
&Provider->Specific.NetAddress.Address
|
|
);
|
|
}
|
|
|
|
// And do the next one.
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
|
|
}
|
|
}
|
|
|
|
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 RequestList;
|
|
PBOOLEAN SerializeFlag;
|
|
PETHREAD *RequestThread;
|
|
PTDI_SERIALIZED_REQUEST Request;
|
|
PKEVENT BlockedEvent = NULL;
|
|
PTDI_NOTIFY_COMMON NotifyElement;
|
|
PTDI_PROVIDER_RESOURCE ProviderElement;
|
|
|
|
ExAcquireSpinLock(
|
|
&TDIListLock,
|
|
&OldIrql
|
|
);
|
|
|
|
if (RequestType <= TDI_MAX_BIND_REQUEST) {
|
|
ClientList = &BindClientList;
|
|
ProviderList = &BindProviderList;
|
|
RequestList = &BindRequestList;
|
|
SerializeFlag = &BindRequestInProgress;
|
|
RequestThread = &BindRequestThread;
|
|
} else {
|
|
ClientList = &NetAddressClientList;
|
|
ProviderList = &NetAddressProviderList;
|
|
RequestList = &NetAddressRequestList;
|
|
SerializeFlag = &AddressRequestInProgress;
|
|
RequestThread = &AddressRequestThread;
|
|
}
|
|
|
|
// If we're not already here, handle it right away.
|
|
|
|
if (!(*SerializeFlag)) {
|
|
|
|
*SerializeFlag = TRUE;
|
|
|
|
// Save the identity of the thread we're doing this in in case someone
|
|
// tries to delete a client, which needs to block. In that case we'll
|
|
// check to make sure it's not being done in the same thread we're using
|
|
// to prevent deadlock.
|
|
|
|
*RequestThread = PsGetCurrentThread();
|
|
|
|
for (;;) {
|
|
|
|
// We're done with the lock for now, so free it.
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
// Figure out the type of request we have here.
|
|
|
|
switch (RequestType) {
|
|
case TDI_REGISTER_BIND_NOTIFY:
|
|
case TDI_REGISTER_ADDRESS_NOTIFY:
|
|
// This is a client register bind or address handler request.
|
|
|
|
// Insert this one into the registered client list.
|
|
NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
|
|
InsertTailList(
|
|
ClientList,
|
|
&NotifyElement->Linkage,
|
|
);
|
|
|
|
// Call TdiNotifyNewClient to notify this new client of all
|
|
// all existing providers.
|
|
|
|
TdiNotifyNewClient(
|
|
ProviderList,
|
|
RequestInfo
|
|
);
|
|
|
|
break;
|
|
|
|
case TDI_DEREGISTER_BIND_NOTIFY:
|
|
case TDI_DEREGISTER_ADDRESS_NOTIFY:
|
|
|
|
// This is a client deregister request. Pull him from the
|
|
// client list, free it, and we're done.
|
|
|
|
NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
|
|
RemoveEntryList(&NotifyElement->Linkage);
|
|
|
|
ExFreePool(NotifyElement);
|
|
|
|
break;
|
|
|
|
case TDI_REGISTER_DEVICE:
|
|
case TDI_REGISTER_ADDRESS:
|
|
|
|
// 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)RequestInfo;
|
|
|
|
InsertTailList(
|
|
ProviderList,
|
|
&ProviderElement->Common.Linkage
|
|
);
|
|
|
|
// Call TdiNotifyClientList to do the hard work.
|
|
|
|
TdiNotifyClientList(
|
|
ClientList,
|
|
RequestInfo,
|
|
TRUE
|
|
);
|
|
break;
|
|
|
|
case TDI_DEREGISTER_DEVICE:
|
|
case TDI_DEREGISTER_ADDRESS:
|
|
|
|
// 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)RequestInfo;
|
|
RemoveEntryList(&ProviderElement->Common.Linkage);
|
|
|
|
TdiNotifyClientList(
|
|
ClientList,
|
|
RequestInfo,
|
|
FALSE
|
|
);
|
|
|
|
// Free the tracking structure we had.
|
|
|
|
if (RequestType == TDI_DEREGISTER_DEVICE) {
|
|
ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer);
|
|
}
|
|
ExFreePool(ProviderElement);
|
|
|
|
break;
|
|
default:
|
|
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 (BlockedEvent != NULL) {
|
|
KeSetEvent(BlockedEvent, 0, FALSE);
|
|
}
|
|
|
|
// Get the lock, and see if more requests have come in while
|
|
// we've been busy. If they have, we'll service them now, otherwise
|
|
// we'll clear the in progress flag and exit.
|
|
|
|
ExAcquireSpinLock(
|
|
&TDIListLock,
|
|
&OldIrql
|
|
);
|
|
|
|
if (!IsListEmpty(RequestList)) {
|
|
|
|
// The request list isn't empty. Pull the next one from
|
|
// the list and process it.
|
|
|
|
List = RemoveHeadList(RequestList);
|
|
|
|
Request = CONTAINING_RECORD(List, TDI_SERIALIZED_REQUEST, Linkage);
|
|
|
|
RequestInfo = Request->Element;
|
|
RequestType = Request->Type;
|
|
BlockedEvent = Request->Event;
|
|
|
|
ExFreePool(Request);
|
|
|
|
} else {
|
|
|
|
// The request list is empty. Clear the flag and we're done.
|
|
|
|
*SerializeFlag = FALSE;
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
} 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.
|
|
|
|
Request = (PTDI_SERIALIZED_REQUEST)ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(TDI_SERIALIZED_REQUEST)
|
|
);
|
|
|
|
if (Request == NULL) {
|
|
|
|
// Couldn't get a request.
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Got the request.
|
|
Request->Element = RequestInfo;
|
|
Request->Type = RequestType;
|
|
Request->Event = NULL;
|
|
|
|
if (
|
|
RequestType == TDI_DEREGISTER_BIND_NOTIFY ||
|
|
RequestType == TDI_REGISTER_BIND_NOTIFY ||
|
|
RequestType == TDI_DEREGISTER_ADDRESS_NOTIFY
|
|
) {
|
|
|
|
// 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(Request);
|
|
|
|
return STATUS_NETWORK_BUSY;
|
|
} else {
|
|
// He's not currently busy, go ahead and block.
|
|
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
|
|
KeInitializeEvent(
|
|
&Event,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
Request->Event = &Event;
|
|
|
|
// Put this guy on the end of the request list.
|
|
|
|
InsertTailList(RequestList, &Request->Linkage);
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
Status = KeWaitForSingleObject(
|
|
&Event,
|
|
UserRequest,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
// I don't know what we'd do is the wait failed....
|
|
|
|
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(RequestList, &Request->Linkage);
|
|
|
|
ExReleaseSpinLock(
|
|
&TDIListLock,
|
|
OldIrql
|
|
);
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PTDI_NOTIFY_ELEMENT NewElement;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// 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();
|
|
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewElement = (PTDI_NOTIFY_ELEMENT)ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(TDI_NOTIFY_ELEMENT)
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewElement == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Fill in the basic stuff.
|
|
NewElement->Common.Type = TDI_NOTIFY_DEVICE;
|
|
NewElement->Specific.BindElement.BindHandler = BindHandler;
|
|
NewElement->Specific.BindElement.UnbindHandler = UnbindHandler;
|
|
|
|
*BindingHandle = (HANDLE)NewElement;
|
|
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewElement,
|
|
TDI_REGISTER_BIND_NOTIFY
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
ExFreePool(NewElement);
|
|
}
|
|
|
|
return Status;
|
|
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
BindingHandle,
|
|
TDI_DEREGISTER_BIND_NOTIFY
|
|
);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
TdiInitialize();
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(TDI_PROVIDER_RESOURCE)
|
|
);
|
|
|
|
// 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)ExAllocatePool(
|
|
NonPagedPool,
|
|
DeviceName->MaximumLength
|
|
);
|
|
|
|
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;
|
|
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewResource,
|
|
TDI_REGISTER_DEVICE
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
ExFreePool(Buffer);
|
|
ExFreePool(NewResource);
|
|
}
|
|
|
|
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;
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
RegistrationHandle,
|
|
TDI_DEREGISTER_DEVICE
|
|
);
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PTDI_NOTIFY_ELEMENT NewElement;
|
|
NTSTATUS Status;
|
|
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewElement = (PTDI_NOTIFY_ELEMENT)ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof(TDI_NOTIFY_ELEMENT)
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewElement == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Fill in the basic stuff.
|
|
NewElement->Common.Type = TDI_NOTIFY_NET_ADDRESS;
|
|
NewElement->Specific.AddressElement.AddHandler = AddHandler;
|
|
NewElement->Specific.AddressElement.DeleteHandler = DeleteHandler;
|
|
|
|
*BindingHandle = (HANDLE)NewElement;
|
|
|
|
|
|
// Now call HandleBindRequest to handle this one.
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewElement,
|
|
TDI_REGISTER_ADDRESS_NOTIFY
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
ExFreePool(NewElement);
|
|
}
|
|
|
|
return Status;
|
|
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
BindingHandle,
|
|
TDI_DEREGISTER_ADDRESS_NOTIFY
|
|
);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
TdiRegisterNetAddress(
|
|
IN PTA_ADDRESS Address,
|
|
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.
|
|
|
|
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;
|
|
|
|
// First, try and allocate the needed resource.
|
|
|
|
NewResource = (PTDI_PROVIDER_RESOURCE)ExAllocatePool(
|
|
NonPagedPool,
|
|
FIELD_OFFSET(
|
|
TDI_PROVIDER_RESOURCE,
|
|
Specific.NetAddress
|
|
) +
|
|
FIELD_OFFSET(TA_ADDRESS, Address) +
|
|
Address->AddressLength
|
|
);
|
|
|
|
// If we couldn't get it, fail the request.
|
|
if (NewResource == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Fill in the basic stuff.
|
|
NewResource->Common.Type = TDI_RESOURCE_DEVICE;
|
|
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.
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
NewResource,
|
|
TDI_REGISTER_ADDRESS
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
ExFreePool(NewResource);
|
|
}
|
|
|
|
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;
|
|
|
|
Status = TdiHandleSerializedRequest(
|
|
RegistrationHandle,
|
|
TDI_DEREGISTER_ADDRESS
|
|
);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|