mirror of https://github.com/tongzx/nt5src
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.
2268 lines
52 KiB
2268 lines
52 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
routing\ip\wanarp\ioctl.c
|
|
|
|
Abstract:
|
|
|
|
IOCTL handlers for wanarp
|
|
|
|
Revision History:
|
|
|
|
AmritanR
|
|
|
|
--*/
|
|
|
|
#define __FILE_SIG__ IOCTL_SIG
|
|
|
|
#include "inc.h"
|
|
|
|
|
|
NTSTATUS
|
|
WanProcessNotification(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The handler for IOCTL_WANARP_NOTIFICATION. We see if we have some info
|
|
we wish to return to the caller and if we do, we return it. Otherwise,
|
|
we pend the IRP and use it later when we need to report an event to
|
|
the user mode
|
|
|
|
Locks:
|
|
|
|
Acquires the IoCancelSpinLock
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
PLIST_ENTRY pleNode;
|
|
PVOID pvIoBuffer;
|
|
|
|
PPENDING_NOTIFICATION pNotification;
|
|
|
|
TraceEnter(CONN, "ProcessNotification");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if((ulInLength < sizeof(WANARP_NOTIFICATION)) or
|
|
(ulOutLength < sizeof(WANARP_NOTIFICATION)))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
|
|
//
|
|
// use cancel spin lock to prevent irp being cancelled during this call.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&kiIrql);
|
|
|
|
//
|
|
// If we have a pending notification then complete it - else
|
|
// queue the notification IRP
|
|
//
|
|
|
|
if(!IsListEmpty(&g_lePendingNotificationList))
|
|
{
|
|
//
|
|
// We have some old info
|
|
//
|
|
|
|
Trace(GLOBAL, TRACE,
|
|
("ProcNotification: Pending notification being completed\n"));
|
|
|
|
//
|
|
// Remove it off the pending list
|
|
//
|
|
|
|
pleNode = RemoveHeadList(&g_lePendingNotificationList);
|
|
|
|
//
|
|
// Get a pointer to the structure
|
|
//
|
|
|
|
pNotification = CONTAINING_RECORD(pleNode,
|
|
PENDING_NOTIFICATION,
|
|
leNotificationLink);
|
|
|
|
//
|
|
// Copy out the event to the user mode buffer
|
|
//
|
|
|
|
RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer,
|
|
&pNotification->wnMsg,
|
|
sizeof(WANARP_NOTIFICATION));
|
|
|
|
//
|
|
// Mark the IRP as non pending (and hence non cancelable)
|
|
//
|
|
|
|
IoSetCancelRoutine(pIrp,
|
|
NULL);
|
|
|
|
//
|
|
// Fill the irp info
|
|
//
|
|
|
|
pIrp->IoStatus.Information = sizeof(WANARP_NOTIFICATION);
|
|
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
//
|
|
// Free the allocated notification
|
|
//
|
|
|
|
FreeNotification(pNotification);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
Trace(GLOBAL, TRACE,
|
|
("ProcNotification: Notification being queued\n"));
|
|
|
|
|
|
//
|
|
// Queue this IRP to use for later
|
|
//
|
|
|
|
//
|
|
// Mark the irp as pending
|
|
//
|
|
|
|
IoMarkIrpPending(pIrp);
|
|
|
|
//
|
|
// Queue up the irp at the end
|
|
//
|
|
|
|
InsertTailList(&g_lePendingIrpList,
|
|
&(pIrp->Tail.Overlay.ListEntry));
|
|
|
|
//
|
|
// Set the cancel routine
|
|
//
|
|
|
|
IoSetCancelRoutine(pIrp,
|
|
WanCancelNotificationIrp);
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
WanAddUserModeInterface(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The handler for IOCTL_WANARP_ADD_INTERFACE.
|
|
We walk our list of interface and make sure we dont have an interface
|
|
with the same user mode index as the one we are being asked to create.
|
|
If this is a new interface, we create a UMODE_INTERFACE structure
|
|
and string it to the list. If it is the server interface then we also
|
|
keep a special pointer to it
|
|
|
|
Locks:
|
|
|
|
Acquires the g_rwlIfLock as WRITER
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL
|
|
STATUS_OBJECT_NAME_EXISTS
|
|
STATUS_OBJECT_NAME_NOT_FOUND
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID pvIoBuffer;
|
|
PUMODE_INTERFACE pInterface;
|
|
KIRQL kiIrql;
|
|
NTSTATUS nStatus;
|
|
|
|
PWANARP_ADD_INTERFACE_INFO pAddIfInfo;
|
|
|
|
TraceEnter(ADPT, "AddUserModeInterface");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if(ulInLength < sizeof(WANARP_ADD_INTERFACE_INFO))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
pAddIfInfo = (PWANARP_ADD_INTERFACE_INFO)pvIoBuffer;
|
|
|
|
if(pAddIfInfo->bCallinInterface)
|
|
{
|
|
if(ulOutLength < sizeof(WANARP_ADD_INTERFACE_INFO))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
RtlZeroMemory(pAddIfInfo->rgwcDeviceName,
|
|
(WANARP_MAX_DEVICE_NAME_LEN + 2) * sizeof(WCHAR));
|
|
|
|
EnterReader(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
if(g_pServerAdapter is NULL)
|
|
{
|
|
ExitReader(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
Trace(ADPT, ERROR,
|
|
("AddUserModeInterface: No Server adapter\n"));
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Lock out the server adapter
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
RtAssert(g_pServerInterface);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(g_pServerInterface->rlLock));
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlAdapterLock);
|
|
|
|
if(pAddIfInfo->dwUserIfIndex isnot WANARP_INVALID_IFINDEX)
|
|
{
|
|
//
|
|
// In this case all we need to do is set the interface index
|
|
// for the server adapter. It is OK for this index to be INVALID
|
|
// in that case, the user is merely asking for the server
|
|
// adapter name
|
|
//
|
|
|
|
g_pServerInterface->dwIfIndex = pAddIfInfo->dwUserIfIndex;
|
|
}
|
|
|
|
//
|
|
// We also need to return the name to the user
|
|
//
|
|
|
|
RtAssert(g_pServerAdapter->usDeviceNameW.Length <= WANARP_MAX_DEVICE_NAME_LEN * sizeof(WCHAR));
|
|
|
|
RtlCopyMemory(pAddIfInfo->rgwcDeviceName,
|
|
&(g_pServerAdapter->usDeviceNameW.Buffer[wcslen(TCPIP_IF_PREFIX) + 1]),
|
|
g_pServerAdapter->usDeviceNameW.Length - ((wcslen(TCPIP_IF_PREFIX) + 1) * sizeof(WCHAR)));
|
|
|
|
//
|
|
// Also copy out the index
|
|
//
|
|
|
|
pAddIfInfo->dwAdapterIndex = g_pServerInterface->dwRsvdAdapterIndex;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerInterface->rlLock));
|
|
|
|
RtReleaseSpinLock(&(g_pServerAdapter->rlLock),
|
|
kiIrql);
|
|
|
|
//
|
|
// We need to copy out info in this case
|
|
//
|
|
|
|
pIrp->IoStatus.Information = sizeof(WANARP_ADD_INTERFACE_INFO);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
EnterWriter(&g_rwlIfLock,
|
|
&kiIrql);
|
|
|
|
pInterface = WanpFindInterfaceGivenIndex(pAddIfInfo->dwUserIfIndex);
|
|
|
|
if(pInterface isnot NULL)
|
|
{
|
|
//
|
|
// Found an interface with the matching index. Not good
|
|
//
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
ExitWriter(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
Trace(ADPT, ERROR,
|
|
("AddUserModeInterface: %d already exists\n",
|
|
pAddIfInfo->dwUserIfIndex));
|
|
|
|
return STATUS_OBJECT_NAME_EXISTS;
|
|
}
|
|
|
|
ExitWriter(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
pInterface = RtAllocate(NonPagedPool,
|
|
sizeof(UMODE_INTERFACE),
|
|
WAN_INTERFACE_TAG);
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pInterface,
|
|
sizeof(UMODE_INTERFACE));
|
|
|
|
//
|
|
// Reserve an Index with IP
|
|
// This sets the value to invalid if it cant find an index
|
|
//
|
|
|
|
nStatus = WanpGetNewIndex(&(pInterface->dwRsvdAdapterIndex));
|
|
|
|
if(nStatus isnot STATUS_SUCCESS)
|
|
{
|
|
RtFree(pInterface);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Trace(ADPT, TRACE,
|
|
("AddUserModeInterface: for 0x%x - will use 0x%x\n",
|
|
pAddIfInfo->dwUserIfIndex,
|
|
pInterface->dwRsvdAdapterIndex));
|
|
|
|
RtInitializeSpinLock(&(pInterface->rlLock));
|
|
|
|
//
|
|
// Initialize the interface
|
|
//
|
|
|
|
pInterface->dwIfIndex = pAddIfInfo->dwUserIfIndex;
|
|
pInterface->dwAdminState = IF_ADMIN_STATUS_UP;
|
|
pInterface->dwOperState = IF_OPER_STATUS_DISCONNECTED;
|
|
pInterface->dwLastChange = GetTimeTicks();
|
|
|
|
pAddIfInfo->dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
|
|
|
|
//
|
|
// Now set the refcount to 1 to account for the fact that the interface
|
|
// will be put on the g_leIfList.
|
|
//
|
|
|
|
InitInterfaceRefCount(pInterface);
|
|
|
|
pInterface->duUsage = DU_ROUTER;
|
|
|
|
EnterWriter(&g_rwlIfLock,
|
|
&kiIrql);
|
|
|
|
InsertHeadList(&g_leIfList,
|
|
&(pInterface->leIfLink));
|
|
|
|
ExitWriter(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
pIrp->IoStatus.Information = sizeof(WANARP_ADD_INTERFACE_INFO);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
WanDeleteUserModeInterface(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for IOCTL_WANARP_DELETE_INTERFACE.
|
|
We lookup our list to see if we have the interface. If we do, then
|
|
we remove the interface from the g_leIfList and dereference it.
|
|
If the interface was not mapped, then this should be the last
|
|
reference on the interface, otherwise when the refcount goes to 0, it
|
|
will get deleted.
|
|
|
|
Locks:
|
|
|
|
Acquires the g_rwlIfLock as WRITER and then calls FindInterface
|
|
which locks the interface in question
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_BUFFER_TOO_SMALL
|
|
STATUS_OBJECT_NAME_NOT_FOUND
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
PUMODE_INTERFACE pInterface;
|
|
PVOID pvIoBuffer;
|
|
|
|
PWANARP_DELETE_INTERFACE_INFO pDeleteInfo;
|
|
|
|
TraceEnter(ADPT, "DeleteUserModeInterface");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if(ulInLength < sizeof(WANARP_DELETE_INTERFACE_INFO))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
|
|
pDeleteInfo = (PWANARP_DELETE_INTERFACE_INFO)pvIoBuffer;
|
|
|
|
//
|
|
// Cant service binds or unbinds here
|
|
//
|
|
|
|
WanpAcquireResource(&g_wrBindMutex);
|
|
|
|
EnterWriter(&g_rwlIfLock,
|
|
&kiIrql);
|
|
|
|
//
|
|
// Find the interface for the index
|
|
//
|
|
|
|
pInterface = WanpFindInterfaceGivenIndex(pDeleteInfo->dwUserIfIndex);
|
|
|
|
//
|
|
// If the interface is not found, bug out
|
|
//
|
|
|
|
Trace(ADPT, TRACE,
|
|
("DeleteUserModeInterface: Deleting i/f 0x%x\n",
|
|
pDeleteInfo->dwUserIfIndex));
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
ExitWriter(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
Trace(ADPT, ERROR,
|
|
("DeleteUserModeInterface: Couldnt find i/f 0x%x\n",
|
|
pDeleteInfo->dwUserIfIndex));
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
RemoveEntryList(&(pInterface->leIfLink));
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlIfLock);
|
|
|
|
//
|
|
// If found, the interface is locked
|
|
// So dereference it and remove it from the list. The interface may
|
|
// not get deleted here because it is already mapped and has a connection
|
|
// active on it.
|
|
//
|
|
|
|
if(pInterface->dwOperState >= IF_OPER_STATUS_CONNECTING)
|
|
{
|
|
Trace(ADPT, ERROR,
|
|
("DeleteUserModeInterface: I/f %d is in state %d\n",
|
|
pInterface->dwIfIndex,
|
|
pInterface->dwOperState));
|
|
}
|
|
|
|
RtReleaseSpinLock(&(pInterface->rlLock),
|
|
kiIrql);
|
|
|
|
//
|
|
// Dereference the interface twice. Once because we put a ref on it
|
|
// when we called FindInterface... and once because we removed it
|
|
// from the if list
|
|
//
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
WanpCleanOutInterfaces(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to delete all the interface from the system.
|
|
We remove the interface from the g_leIfList and dereference it.
|
|
For the server interface we simply mark it as disconnected
|
|
|
|
Locks:
|
|
|
|
Acquires the g_rwlIfLock as WRITER
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
PUMODE_INTERFACE pInterface;
|
|
|
|
|
|
TraceEnter(ADPT, "CleanOutInterfaces");
|
|
|
|
//
|
|
// Cant service binds or unbinds here
|
|
//
|
|
|
|
WanpAcquireResource(&g_wrBindMutex);
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
EnterWriterAtDpcLevel(&g_rwlIfLock);
|
|
|
|
while(!IsListEmpty(&g_leIfList))
|
|
{
|
|
PLIST_ENTRY pleNode;
|
|
|
|
pleNode = RemoveHeadList(&g_leIfList);
|
|
|
|
pInterface = CONTAINING_RECORD(pleNode,
|
|
UMODE_INTERFACE,
|
|
leIfLink);
|
|
|
|
if(pInterface->dwOperState >= IF_OPER_STATUS_CONNECTING)
|
|
{
|
|
Trace(ADPT, ERROR,
|
|
("CleanOutInterfaces: I/f %d is in state %d\n",
|
|
pInterface->dwIfIndex,
|
|
pInterface->dwOperState));
|
|
}
|
|
|
|
DereferenceInterface(pInterface);
|
|
}
|
|
|
|
//
|
|
// What should we do with the server interface?
|
|
//
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlIfLock);
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WanpDeleteInterface(
|
|
PUMODE_INTERFACE pInterface
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Called by DereferenceInterface() when the refcount on an interface
|
|
falls to 0
|
|
|
|
Locks
|
|
|
|
The interface is neither locked nor refcounted. Since there are no
|
|
stored pointers to the interface, this structure can not be accessed
|
|
by anyone but this function
|
|
|
|
Arguments
|
|
|
|
pInterface The interface to delete
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER pAdapter;
|
|
|
|
if(pInterface is g_pServerInterface)
|
|
{
|
|
//
|
|
// If this is the server interface, make sure that all
|
|
// connection entries are gone
|
|
//
|
|
}
|
|
|
|
//
|
|
// There should be no interface mapped to it because otherwise we wouldnt
|
|
// be down to a refcount of 0
|
|
//
|
|
|
|
RtAssert(pInterface->dwRsvdAdapterIndex isnot INVALID_IF_INDEX);
|
|
RtAssert(pInterface->dwRsvdAdapterIndex isnot 0);
|
|
|
|
WanpFreeIndex(pInterface->dwRsvdAdapterIndex);
|
|
|
|
RtAssert(pInterface->pAdapter is NULL);
|
|
|
|
RtFree(pInterface);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
WanProcessConnectionFailure(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for IOCTL_WANARP_CONNECT_FAILED
|
|
We find the interface that failed to connect. If we do find one, we
|
|
mark its state as disconnected and then see if it was mapped to an
|
|
adapter (as it should be). If we find an adapter, we do funky stuff
|
|
with lock orders, clean out the packets queued to the adapter and
|
|
unmap the adapter.
|
|
|
|
Locks:
|
|
|
|
One of the more complex functions.
|
|
We take the g_rwlIfLock to get to the interface and lock it.
|
|
Then we get a pointer to the adapter, and ref it. We release the
|
|
interface lock and lock the adapter.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_BUFFER_TOO_SMALL
|
|
STATUS_OBJECT_NAME_NOT_FOUND
|
|
STATUS_INVALID_PARAMETER
|
|
STATUS_INVALID_DEVICE_STATE
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET packet;
|
|
PADAPTER pAdapter;
|
|
PUMODE_INTERFACE pInterface;
|
|
DWORD dwIfIndex;
|
|
PVOID pvIoBuffer;
|
|
KIRQL kiIrql;
|
|
|
|
TraceEnter(CONN, "ProcessConnectionFailure");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if(ulInLength < sizeof(WANARP_CONNECT_FAILED_INFO))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
dwIfIndex = ((PWANARP_CONNECT_FAILED_INFO)pvIoBuffer)->dwUserIfIndex;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Find the interface
|
|
//
|
|
|
|
EnterReader(&g_rwlIfLock,
|
|
&kiIrql);
|
|
|
|
pInterface = WanpFindInterfaceGivenIndex(dwIfIndex);
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
ExitReader(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
Trace(CONN, ERROR,
|
|
("ProcessConnectionFailure: Couldnt find i/f for index %d\n",
|
|
dwIfIndex));
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
if(pInterface is g_pServerInterface)
|
|
{
|
|
//
|
|
// Cant get a disconnect on this
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
ExitReader(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
Trace(CONN, ERROR,
|
|
("ProcessConnectionFailure: disconnect on server i/f (%d)n",
|
|
dwIfIndex));
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlIfLock);
|
|
|
|
RtAssert(pInterface->dwIfIndex is dwIfIndex);
|
|
|
|
//
|
|
// So now the interface is locked.
|
|
//
|
|
|
|
Trace(CONN, TRACE,
|
|
("ProcessConnectionFailure for %d %p\n", pInterface->dwIfIndex, pInterface));
|
|
|
|
|
|
if(pInterface->dwOperState isnot IF_OPER_STATUS_CONNECTING)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("ProcessConnectionFailure: %p is in state %d\n",
|
|
pInterface,
|
|
pInterface->dwOperState));
|
|
|
|
RtReleaseSpinLock(&(pInterface->rlLock),
|
|
kiIrql);
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
pAdapter = pInterface->pAdapter;
|
|
|
|
if(pAdapter is NULL)
|
|
{
|
|
//
|
|
// This is the case where we couldnt find an adapter added to IP
|
|
// to make a DOD connection
|
|
// We dont need to do too much here, just release the interface
|
|
// lock and remove ref that was put by FindInterface()
|
|
//
|
|
|
|
RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTING);
|
|
|
|
pInterface->dwOperState = IF_OPER_STATUS_DISCONNECTED;
|
|
pInterface->dwLastChange= GetTimeTicks();
|
|
|
|
RtAssert(pInterface->ulPacketsPending is 0);
|
|
|
|
RtReleaseSpinLock(&(pInterface->rlLock),
|
|
kiIrql);
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// We should never get a connection failure if have gotten a LinkUp
|
|
//
|
|
|
|
RtAssert(pAdapter->pConnEntry is NULL);
|
|
|
|
//
|
|
// If we do have an adapter then it can not go away because the
|
|
// interface has a refcount on it (i.e when we set the pAdapter field
|
|
// in the interface, we refcounted the adapter because we had a stored
|
|
// pointer to it)
|
|
//
|
|
|
|
|
|
RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTING);
|
|
|
|
//
|
|
// If the interface is still mapped, unmap it and drain any packets we
|
|
// may have queued
|
|
//
|
|
|
|
pInterface->ulPacketsPending = 0;
|
|
|
|
pInterface->dwOperState = IF_OPER_STATUS_DISCONNECTED;
|
|
pInterface->dwLastChange= GetTimeTicks();
|
|
|
|
//
|
|
// The adapter can not go away because the interface has a refcount on
|
|
// it (i.e when we set the pAdapter field in the interface, we
|
|
// refcounted the adapter because we had a stored pointer to it)
|
|
//
|
|
|
|
pAdapter = pInterface->pAdapter;
|
|
|
|
RtAssert(pAdapter);
|
|
|
|
//
|
|
// Clear out the adapter field, BUT DONT DEREF the adapter
|
|
//
|
|
|
|
pInterface->pAdapter = NULL;
|
|
|
|
//
|
|
// So we are done with the interface. We now go and clean out the
|
|
// adapter. To do that we need to acquire the adapter lock. However we
|
|
// can not do that since we have the interface lock. So we first
|
|
// reference the adapter (so that it will be around). Then we
|
|
// let go of the interface lock. (The interface can not go away since
|
|
// we put a refcount on the it when we called FindInterface). After
|
|
// which we can acquire the adapter lock
|
|
//
|
|
|
|
ReferenceAdapter(pAdapter);
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
//
|
|
// The adapter has to be around, because of the refcount
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
//
|
|
// Make sure that the adapter still thinks that it is mapped to the
|
|
// interface in question
|
|
//
|
|
|
|
if(pAdapter->pInterface is pInterface)
|
|
{
|
|
RtAssert(pAdapter->byState is AS_MAPPED);
|
|
|
|
//
|
|
// Drain all the packets
|
|
//
|
|
|
|
Trace(CONN, TRACE,
|
|
("ProcsConnFailure: Draining and freeing any queued packets\n"));
|
|
|
|
|
|
while(!IsListEmpty(&(pAdapter->lePendingPktList)))
|
|
{
|
|
PLIST_ENTRY pleNode;
|
|
PNDIS_PACKET pnpPacket;
|
|
|
|
pleNode = RemoveHeadList(&(pAdapter->lePendingPktList));
|
|
|
|
//
|
|
// get to the packet structure in which LIST_ENTRY is embedded
|
|
//
|
|
|
|
pnpPacket = CONTAINING_RECORD(pleNode,
|
|
NDIS_PACKET,
|
|
MacReserved);
|
|
|
|
WanpFreePacketAndBuffers(pnpPacket);
|
|
}
|
|
|
|
if(!IsListEmpty(&(pAdapter->lePendingHdrList)))
|
|
{
|
|
LIST_ENTRY leTempList;
|
|
|
|
leTempList = pAdapter->lePendingHdrList;
|
|
|
|
pAdapter->lePendingHdrList.Flink->Blink = &leTempList;
|
|
pAdapter->lePendingHdrList.Blink->Flink = &leTempList;
|
|
|
|
InitializeListHead(&(pAdapter->lePendingHdrList));
|
|
|
|
FreeBufferListToPool(&g_bpHeaderBufferPool,
|
|
&leTempList);
|
|
}
|
|
|
|
pAdapter->pInterface = NULL;
|
|
|
|
//
|
|
// Deref the interface because we are clearing out a stored pointer
|
|
//
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
//
|
|
// Deref the adapter now (due to the fact that we cleared out
|
|
// the pAdapter field in pInterface
|
|
//
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
}
|
|
|
|
//
|
|
// Done with the adapter
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
|
|
|
|
WanpUnmapAdapter(pAdapter);
|
|
|
|
KeLowerIrql(kiIrql);
|
|
|
|
//
|
|
// Remove ref that was put by FindInterface()
|
|
//
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
//
|
|
// Remove the ref that was put when we let go of the interface lock
|
|
//
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
WanGetIfStats(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Locks:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID pvIoBuffer;
|
|
PWANARP_GET_IF_STATS_INFO pInfo;
|
|
KIRQL kiIrql;
|
|
PUMODE_INTERFACE pInterface;
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if((ulOutLength < (FIELD_OFFSET(WANARP_GET_IF_STATS_INFO, ifeInfo)
|
|
+ IFE_FIXED_SIZE))or
|
|
(ulInLength < (FIELD_OFFSET(WANARP_GET_IF_STATS_INFO, ifeInfo)
|
|
+ IFE_FIXED_SIZE)))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
EnterReader(&g_rwlIfLock,
|
|
&kiIrql);
|
|
|
|
pInfo = (PWANARP_GET_IF_STATS_INFO)pvIoBuffer;
|
|
|
|
pInterface = WanpFindInterfaceGivenIndex(pInfo->dwUserIfIndex);
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
ExitReader(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlIfLock);
|
|
|
|
//
|
|
// We dont take the adapter lock, because the adapter can not
|
|
// go away while the interface is mapped to it.
|
|
// Sure the qlen can be inconsistent, but hey
|
|
//
|
|
|
|
if((pInterface->pAdapter) and
|
|
(pInterface->pAdapter->pConnEntry))
|
|
{
|
|
pInfo->ifeInfo.if_index = pInterface->pAdapter->dwAdapterIndex;
|
|
pInfo->ifeInfo.if_outqlen = pInterface->pAdapter->ulQueueLen;
|
|
pInfo->ifeInfo.if_mtu = pInterface->pAdapter->pConnEntry->ulMtu;
|
|
pInfo->ifeInfo.if_speed = pInterface->pAdapter->pConnEntry->ulSpeed;
|
|
}
|
|
else
|
|
{
|
|
pInfo->ifeInfo.if_index = (uint)-1;
|
|
pInfo->ifeInfo.if_outqlen = 0;
|
|
pInfo->ifeInfo.if_mtu = WANARP_DEFAULT_MTU;
|
|
pInfo->ifeInfo.if_speed = WANARP_DEFAULT_SPEED;
|
|
}
|
|
|
|
pInfo->ifeInfo.if_adminstatus = pInterface->dwAdminState;
|
|
pInfo->ifeInfo.if_operstatus = pInterface->dwOperState;
|
|
pInfo->ifeInfo.if_lastchange = pInterface->dwLastChange;
|
|
pInfo->ifeInfo.if_inoctets = pInterface->ulInOctets;
|
|
pInfo->ifeInfo.if_inucastpkts = pInterface->ulInUniPkts;
|
|
pInfo->ifeInfo.if_innucastpkts = pInterface->ulInNonUniPkts;
|
|
pInfo->ifeInfo.if_indiscards = pInterface->ulInDiscards;
|
|
pInfo->ifeInfo.if_inerrors = pInterface->ulInErrors;
|
|
pInfo->ifeInfo.if_inunknownprotos = pInterface->ulInUnknownProto;
|
|
pInfo->ifeInfo.if_outoctets = pInterface->ulOutOctets;
|
|
pInfo->ifeInfo.if_outucastpkts = pInterface->ulOutUniPkts;
|
|
pInfo->ifeInfo.if_outnucastpkts = pInterface->ulOutNonUniPkts;
|
|
pInfo->ifeInfo.if_outdiscards = pInterface->ulOutDiscards;
|
|
pInfo->ifeInfo.if_outerrors = pInterface->ulOutErrors;
|
|
|
|
RtReleaseSpinLock(&(pInterface->rlLock),
|
|
kiIrql);
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
pInfo->ifeInfo.if_type = IF_TYPE_PPP;
|
|
pInfo->ifeInfo.if_physaddrlen = ARP_802_ADDR_LENGTH;
|
|
pInfo->ifeInfo.if_descrlen = 0;
|
|
|
|
RtlZeroMemory(pInfo->ifeInfo.if_physaddr,
|
|
MAX_PHYSADDR_SIZE);
|
|
|
|
pIrp->IoStatus.Information =
|
|
FIELD_OFFSET(WANARP_GET_IF_STATS_INFO, ifeInfo) + IFE_FIXED_SIZE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
WanDeleteAdapters(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for IOCTL_WANARP_DELETE_ADAPTERS.
|
|
The caller indicates to us the number of adapters that she wants
|
|
removed. If we have that many free adapters, we remove them and
|
|
return the names of the devices, removed.
|
|
|
|
Locks:
|
|
|
|
Acquires the g_rwlAdaptersLock as WRITER
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_BUFFER_TOO_SMALL
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
PADAPTER pAdapter;
|
|
PVOID pvIoBuffer;
|
|
ULONG i;
|
|
PLIST_ENTRY pleNode;
|
|
LIST_ENTRY leTempHead;
|
|
PVOID pvNameBuffer;
|
|
NTSTATUS nStatus;
|
|
KEVENT keChangeEvent;
|
|
|
|
PWANARP_DELETE_ADAPTERS_INFO pDeleteInfo;
|
|
|
|
TraceEnter(ADPT, "DeleteAdapters");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if(ulInLength < sizeof(WANARP_DELETE_ADAPTERS_INFO))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
pDeleteInfo = (PWANARP_DELETE_ADAPTERS_INFO)pvIoBuffer;
|
|
|
|
//
|
|
// Dont service binds or unbinds here
|
|
//
|
|
|
|
WanpAcquireResource(&g_wrBindMutex);
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
if(pDeleteInfo->ulNumAdapters > g_ulNumFreeAdapters + g_ulNumAddedAdapters)
|
|
{
|
|
//
|
|
// Asking to delete more adapters than are present
|
|
//
|
|
|
|
pIrp->IoStatus.Information = g_ulNumFreeAdapters + g_ulNumAddedAdapters;
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// So there are enough unmapped adapters. See if we have enough space to
|
|
// return the names of the adapters
|
|
//
|
|
|
|
if(ulOutLength <
|
|
FIELD_OFFSET(WANARP_DELETE_ADAPTERS_INFO, rgAdapterGuid[0]) +
|
|
(pDeleteInfo->ulNumAdapters * sizeof(GUID)))
|
|
{
|
|
//
|
|
// Not enough space to hold the names
|
|
//
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
pIrp->IoStatus.Information =
|
|
FIELD_OFFSET(WANARP_DELETE_ADAPTERS_INFO, rgAdapterGuid[0]) +
|
|
(pDeleteInfo->ulNumAdapters * sizeof(GUID));
|
|
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
pIrp->IoStatus.Information =
|
|
FIELD_OFFSET(WANARP_DELETE_ADAPTERS_INFO, rgAdapterGuid[0]) +
|
|
(pDeleteInfo->ulNumAdapters * sizeof(GUID));
|
|
|
|
//
|
|
// Everything's good. First see if we can remove the ones we want
|
|
// removed from the free list
|
|
//
|
|
|
|
i = 0;
|
|
|
|
while((i < pDeleteInfo->ulNumAdapters) and
|
|
(!IsListEmpty(&g_leFreeAdapterList)))
|
|
{
|
|
pleNode = RemoveHeadList(&g_leFreeAdapterList);
|
|
|
|
g_ulNumFreeAdapters--;
|
|
|
|
pAdapter = CONTAINING_RECORD(pleNode,
|
|
ADAPTER,
|
|
leAdapterLink);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
RtAssert(pAdapter->byState is AS_FREE);
|
|
RtAssert(pAdapter->pInterface is NULL);
|
|
|
|
//
|
|
// Copy out the name
|
|
// TCPIP_IF_PREFIX is \Device and we need to remove \Device\
|
|
//
|
|
|
|
ConvertStringToGuid(
|
|
&(pAdapter->usDeviceNameW.Buffer[wcslen(TCPIP_IF_PREFIX) + 1]),
|
|
pAdapter->usDeviceNameW.Length - ((wcslen(TCPIP_IF_PREFIX) + 1) * sizeof(WCHAR)),
|
|
&(pDeleteInfo->rgAdapterGuid[i])
|
|
);
|
|
|
|
i++;
|
|
|
|
//
|
|
// Deref it for removing it from the list. This should delete
|
|
// it
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
}
|
|
|
|
if(i is pDeleteInfo->ulNumAdapters)
|
|
{
|
|
//
|
|
// We are done
|
|
//
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Need to get some added adapters deleted, too
|
|
//
|
|
|
|
InitializeListHead(&leTempHead);
|
|
|
|
while((i < pDeleteInfo->ulNumAdapters) and
|
|
(!IsListEmpty(&g_leAddedAdapterList)))
|
|
{
|
|
pleNode = RemoveHeadList(&g_leAddedAdapterList);
|
|
|
|
g_ulNumAddedAdapters--;
|
|
|
|
pAdapter = CONTAINING_RECORD(pleNode,
|
|
ADAPTER,
|
|
leAdapterLink);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
pAdapter->byState = AS_REMOVING;
|
|
|
|
InsertHeadList(&leTempHead,
|
|
&(pAdapter->leAdapterLink));
|
|
|
|
//
|
|
// Copy out the name
|
|
//
|
|
|
|
ConvertStringToGuid(
|
|
&(pAdapter->usDeviceNameW.Buffer[wcslen(TCPIP_IF_PREFIX) + 1]),
|
|
pAdapter->usDeviceNameW.Length - ((wcslen(TCPIP_IF_PREFIX) + 1) * sizeof(WCHAR)),
|
|
&(pDeleteInfo->rgAdapterGuid[i])
|
|
);
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
|
|
|
|
i++;
|
|
}
|
|
|
|
//
|
|
// We better have enough adapters
|
|
//
|
|
|
|
RtAssert(i is pDeleteInfo->ulNumAdapters);
|
|
|
|
//
|
|
// Now we can let go of the lock
|
|
//
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
KeInitializeEvent(&keChangeEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
//
|
|
// Loop through and delete the adapters
|
|
//
|
|
|
|
while(!IsListEmpty(&leTempHead))
|
|
{
|
|
pleNode = RemoveHeadList(&leTempHead);
|
|
|
|
pAdapter = CONTAINING_RECORD(pleNode,
|
|
ADAPTER,
|
|
leAdapterLink);
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
//
|
|
// Insert it into the change list
|
|
//
|
|
|
|
InsertHeadList(&g_leChangeAdapterList,
|
|
&(pAdapter->leAdapterLink));
|
|
|
|
//
|
|
// Set the event to block on
|
|
//
|
|
|
|
RtAssert(pAdapter->pkeChangeEvent is NULL);
|
|
|
|
pAdapter->pkeChangeEvent = &keChangeEvent;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
g_pfnIpDeleteInterface(pAdapter->pvIpContext,
|
|
FALSE);
|
|
|
|
//
|
|
// Wait till the CloseAdapter completes
|
|
//
|
|
|
|
nStatus = KeWaitForSingleObject(&keChangeEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// Remove from the change list
|
|
//
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
#if DBG
|
|
|
|
RtAssert(IsEntryOnList(&g_leChangeAdapterList,
|
|
&(pAdapter->leAdapterLink)));
|
|
|
|
#endif
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
RemoveEntryList(&(pAdapter->leAdapterLink));
|
|
|
|
pAdapter->byState = 0xFF;
|
|
|
|
pAdapter->pkeChangeEvent = NULL;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
//
|
|
// Dereference the adapter for removing from the list
|
|
// (CloseAdapter will deref it for removing from IP)
|
|
//
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
}
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
WanMapServerAdapter(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by RAS to add the server adapter and map it to an interface.
|
|
It has to be done before the first client dials in.
|
|
|
|
Locks:
|
|
|
|
Acquires the g_wrBindMutex. Also acquires the adapter list lock and the
|
|
adapter lock
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL
|
|
STATUS_NO_SUCH_DEVICE
|
|
STATUS_DIRECTORY_NOT_EMPTY
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS nStatus;
|
|
PVOID pvIoBuffer;
|
|
KIRQL kiIrql;
|
|
WCHAR rgwcGuid[GUID_STR_LEN + 1];
|
|
KEVENT keTempEvent;
|
|
PLIST_ENTRY pleNode;
|
|
PADAPTER pTempAdapter;
|
|
|
|
UNICODE_STRING usTempName;
|
|
PUMODE_INTERFACE pInterface;
|
|
|
|
PWANARP_MAP_SERVER_ADAPTER_INFO pInfo;
|
|
|
|
TraceEnter(ADPT, "MapServerAdapter");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pInfo = (PWANARP_MAP_SERVER_ADAPTER_INFO)pvIoBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if((ulOutLength < sizeof(WANARP_MAP_SERVER_ADAPTER_INFO)) or
|
|
(ulInLength < sizeof(WANARP_MAP_SERVER_ADAPTER_INFO)))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
WanpAcquireResource(&g_wrBindMutex);
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
if(g_pServerAdapter is NULL)
|
|
{
|
|
Trace(ADPT, ERROR,
|
|
("MapServerAdapter: No server adapter\n"));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
RtAssert(g_pServerInterface);
|
|
|
|
//
|
|
// Lock the adapter and change the state to let people know we are
|
|
// trying to add or remove the adapter, hence they should wait on the
|
|
// global event
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
if(pInfo->fMap is 0)
|
|
{
|
|
KEVENT keTempEvent;
|
|
|
|
//
|
|
// Trying to unmap
|
|
//
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if(g_pServerAdapter->byState is AS_FREE)
|
|
{
|
|
//
|
|
// Nothing to do
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Since add is serialized, the only other state is AS_MAPPED
|
|
//
|
|
|
|
RtAssert(g_pServerAdapter->byState is AS_MAPPED);
|
|
|
|
//
|
|
// Make sure there are no new connections
|
|
//
|
|
|
|
if(!WanpIsConnectionTableEmpty())
|
|
{
|
|
Trace(ADPT, ERROR,
|
|
("MapServerAdapter: Connection Table not empty\n"));
|
|
|
|
// RtAssert(FALSE);
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
|
}
|
|
|
|
//
|
|
// Remove the adapter from ip, remove the cross ref
|
|
//
|
|
|
|
//
|
|
// Since we are changing the state, no one else should be also
|
|
// changing the state
|
|
//
|
|
|
|
RtAssert(g_pServerAdapter->pkeChangeEvent is NULL);
|
|
|
|
KeInitializeEvent(&keTempEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
g_pServerAdapter->pkeChangeEvent = &keTempEvent;
|
|
|
|
ReferenceAdapter(g_pServerAdapter);
|
|
|
|
g_pServerAdapter->byState = AS_REMOVING;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
//
|
|
// Delete from IP, but dont clear the index
|
|
//
|
|
|
|
g_pfnIpDeleteInterface(g_pServerAdapter->pvIpContext,
|
|
FALSE);
|
|
|
|
nStatus = KeWaitForSingleObject(&keTempEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
RtAssert(nStatus is STATUS_SUCCESS);
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
#if DBG
|
|
|
|
Trace(ADPT, INFO,
|
|
("MapServerAdapter: Removed %s (server adapter) from Ip\n",
|
|
g_pServerAdapter->asDeviceNameA.Buffer));
|
|
|
|
#endif
|
|
|
|
g_pServerAdapter->pkeChangeEvent = NULL;
|
|
|
|
g_pServerAdapter->byState = AS_FREE;
|
|
g_pServerInterface->pAdapter = NULL;
|
|
g_pServerAdapter->pInterface = NULL;
|
|
|
|
//
|
|
// deref because of the cross ref
|
|
//
|
|
|
|
DereferenceAdapter(g_pServerAdapter);
|
|
DereferenceInterface(g_pServerInterface);
|
|
|
|
g_pServerAdapter->dwAdapterIndex = 0;
|
|
|
|
//
|
|
// If anyone is waiting on a state change, notify them
|
|
//
|
|
|
|
for(pleNode = g_pServerAdapter->leEventList.Flink;
|
|
pleNode isnot &(g_pServerAdapter->leEventList);
|
|
pleNode = pleNode->Flink)
|
|
{
|
|
PWAN_EVENT_NODE pTempEvent;
|
|
|
|
pTempEvent = CONTAINING_RECORD(pleNode,
|
|
WAN_EVENT_NODE,
|
|
leEventLink);
|
|
|
|
KeSetEvent(&(pTempEvent->keEvent),
|
|
0,
|
|
FALSE);
|
|
}
|
|
|
|
pTempAdapter = g_pServerAdapter;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
DereferenceAdapter(pTempAdapter);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
if(g_pServerAdapter->byState isnot AS_FREE)
|
|
{
|
|
//
|
|
// Valid states are AS_FREE, AS_ADDING, AS_MAPPED.
|
|
// It can not be in the process of being added since the resource
|
|
// is acquired
|
|
//
|
|
|
|
RtAssert(g_pServerAdapter->byState is AS_MAPPED);
|
|
|
|
RtAssert(g_pServerAdapter->pInterface is g_pServerInterface);
|
|
RtAssert(g_pServerInterface->pAdapter is g_pServerAdapter);
|
|
|
|
pInfo->dwAdapterIndex = g_pServerAdapter->dwAdapterIndex;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
pIrp->IoStatus.Information = sizeof(WANARP_MAP_SERVER_ADAPTER_INFO);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
RtAssert(g_pServerInterface->pAdapter is NULL);
|
|
RtAssert(g_pServerAdapter->pInterface is NULL);
|
|
|
|
ReferenceAdapter(g_pServerAdapter);
|
|
|
|
g_pServerAdapter->byState = AS_ADDING;
|
|
|
|
//
|
|
// Since we are changing the state, no one else should be also
|
|
// changing the state
|
|
//
|
|
|
|
RtAssert(g_pServerAdapter->pkeChangeEvent is NULL)
|
|
|
|
KeInitializeEvent(&keTempEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
g_pServerAdapter->pkeChangeEvent = &keTempEvent;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
usTempName.MaximumLength = (GUID_STR_LEN + 1) * sizeof(WCHAR);
|
|
usTempName.Length = GUID_STR_LEN * sizeof(WCHAR);
|
|
usTempName.Buffer = rgwcGuid;
|
|
|
|
ConvertGuidToString(&(g_pServerInterface->Guid),
|
|
rgwcGuid);
|
|
|
|
nStatus = WanpAddAdapterToIp(g_pServerAdapter,
|
|
TRUE,
|
|
g_pServerInterface->dwRsvdAdapterIndex,
|
|
&usTempName,
|
|
IF_TYPE_PPP,
|
|
IF_ACCESS_POINTTOMULTIPOINT,
|
|
IF_CONNECTION_PASSIVE);
|
|
|
|
if(nStatus isnot STATUS_SUCCESS)
|
|
{
|
|
Trace(ADPT, ERROR,
|
|
("MapServerAdapter: %x adding %x to IP\n",
|
|
nStatus, g_pServerAdapter));
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
g_pServerAdapter->byState = AS_FREE;
|
|
|
|
g_pServerAdapter->pkeChangeEvent = NULL;
|
|
|
|
//
|
|
// If anyone is waiting on a state change, notify them
|
|
//
|
|
|
|
for(pleNode = g_pServerAdapter->leEventList.Flink;
|
|
pleNode isnot &(g_pServerAdapter->leEventList);
|
|
pleNode = pleNode->Flink)
|
|
{
|
|
PWAN_EVENT_NODE pTempEvent;
|
|
|
|
pTempEvent = CONTAINING_RECORD(pleNode,
|
|
WAN_EVENT_NODE,
|
|
leEventLink);
|
|
|
|
KeSetEvent(&(pTempEvent->keEvent),
|
|
0,
|
|
FALSE);
|
|
}
|
|
|
|
pTempAdapter = g_pServerAdapter;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
#if DBG
|
|
|
|
Trace(ADPT, ERROR,
|
|
("MapServerAdapter: Couldnt add %s to Ip as server adapter\n",
|
|
pTempAdapter->asDeviceNameA.Buffer));
|
|
|
|
#endif
|
|
|
|
DereferenceAdapter(pTempAdapter);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
return nStatus;
|
|
}
|
|
|
|
//
|
|
// Wait till the OpenAdapter is called
|
|
//
|
|
|
|
nStatus = KeWaitForSingleObject(&keTempEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
RtAssert(nStatus is STATUS_SUCCESS);
|
|
|
|
Trace(ADPT, TRACE,
|
|
("MapServerAdapter: IPAddInterface succeeded for adapter %w\n",
|
|
g_pServerAdapter->usDeviceNameW.Buffer));
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
//
|
|
// Cross ref the structures
|
|
//
|
|
|
|
g_pServerAdapter->pInterface = g_pServerInterface;
|
|
g_pServerInterface->pAdapter = g_pServerAdapter;
|
|
|
|
g_pServerAdapter->byState = AS_MAPPED;
|
|
g_pServerInterface->dwOperState = IF_OPER_STATUS_CONNECTED;
|
|
g_pServerInterface->dwLastChange= GetTimeTicks();
|
|
|
|
//
|
|
// bump the refcount because of the cross ref
|
|
//
|
|
|
|
ReferenceAdapter(g_pServerAdapter);
|
|
ReferenceInterface(g_pServerInterface);
|
|
|
|
pInfo->dwAdapterIndex = g_pServerAdapter->dwAdapterIndex;
|
|
|
|
g_pServerAdapter->pkeChangeEvent = NULL;
|
|
|
|
//
|
|
// If anyone is waiting on a state change, notify them
|
|
//
|
|
|
|
for(pleNode = g_pServerAdapter->leEventList.Flink;
|
|
pleNode isnot &(g_pServerAdapter->leEventList);
|
|
pleNode = pleNode->Flink)
|
|
{
|
|
PWAN_EVENT_NODE pTempEvent;
|
|
|
|
pTempEvent = CONTAINING_RECORD(pleNode,
|
|
WAN_EVENT_NODE,
|
|
leEventLink);
|
|
|
|
KeSetEvent(&(pTempEvent->keEvent),
|
|
0,
|
|
FALSE);
|
|
}
|
|
|
|
pTempAdapter = g_pServerAdapter;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
DereferenceAdapter(pTempAdapter);
|
|
|
|
WanpReleaseResource(&g_wrBindMutex);
|
|
|
|
pIrp->IoStatus.Information = sizeof(WANARP_MAP_SERVER_ADAPTER_INFO);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
WanStartStopQueuing(
|
|
PIRP pIrp,
|
|
ULONG ulInLength,
|
|
ULONG ulOutLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The handler for IOCTL_WANARP_QUEUE.
|
|
It is used to start or stop queuing notifications to the router manager.
|
|
On start, we return the dial out interfaces that we currently have.
|
|
|
|
Locks:
|
|
|
|
Acquires the IoCancelSpinLock
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_PENDING
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
PLIST_ENTRY pleNode;
|
|
PVOID pvIoBuffer;
|
|
ULONG i, ulMaxInterfaces, ulSizeReq;
|
|
|
|
PWANARP_QUEUE_INFO pQueueInfo;
|
|
PPENDING_NOTIFICATION pNotification;
|
|
|
|
TraceEnter(GLOBAL, "StartStopQueuing");
|
|
|
|
pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
if(ulInLength < FIELD_OFFSET(WANARP_QUEUE_INFO, rgIfInfo))
|
|
{
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
//
|
|
// use cancel spin lock to prevent irp being cancelled during this call.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&kiIrql);
|
|
|
|
//
|
|
// If the user is stopping queueing, delete all the pending notifications
|
|
//
|
|
|
|
pQueueInfo = (PWANARP_QUEUE_INFO)pvIoBuffer;
|
|
|
|
if(!pQueueInfo->fQueue)
|
|
{
|
|
g_bQueueNotifications = FALSE;
|
|
|
|
while(!IsListEmpty(&g_lePendingNotificationList))
|
|
{
|
|
//
|
|
// We have some old info
|
|
// Remove it off the pending list
|
|
//
|
|
|
|
pleNode = RemoveHeadList(&g_lePendingNotificationList);
|
|
|
|
//
|
|
// Get a pointer to the structure
|
|
//
|
|
|
|
pNotification = CONTAINING_RECORD(pleNode,
|
|
PENDING_NOTIFICATION,
|
|
leNotificationLink);
|
|
|
|
//
|
|
// Free the allocated notification
|
|
//
|
|
|
|
FreeNotification(pNotification);
|
|
}
|
|
|
|
//
|
|
// Done
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
WanpClearPendingIrps();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// The user wants to start queueing
|
|
// See if she has given us enough space to copy out
|
|
// the current dial outs
|
|
//
|
|
|
|
if(ulOutLength < FIELD_OFFSET(WANARP_QUEUE_INFO, rgIfInfo))
|
|
{
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
EnterReaderAtDpcLevel(&g_rwlAdapterLock);
|
|
|
|
ulSizeReq = FIELD_OFFSET(WANARP_QUEUE_INFO, rgIfInfo) +
|
|
(g_ulNumDialOutInterfaces * sizeof(WANARP_IF_INFO));
|
|
|
|
|
|
pQueueInfo->ulNumCallout = g_ulNumDialOutInterfaces;
|
|
|
|
if(ulOutLength < ulSizeReq)
|
|
{
|
|
pIrp->IoStatus.Information = FIELD_OFFSET(WANARP_QUEUE_INFO, rgIfInfo);
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlAdapterLock);
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
return STATUS_MORE_ENTRIES;
|
|
}
|
|
|
|
ulMaxInterfaces =
|
|
(ulOutLength - FIELD_OFFSET(WANARP_QUEUE_INFO, rgIfInfo)) / sizeof(WANARP_IF_INFO);
|
|
|
|
//
|
|
// Have enough space
|
|
// Walk the list of mapped adapters looking for CALLOUTs
|
|
//
|
|
|
|
for(i = 0, pleNode = g_leMappedAdapterList.Flink;
|
|
pleNode isnot &g_leMappedAdapterList;
|
|
pleNode = pleNode->Flink)
|
|
{
|
|
PUMODE_INTERFACE pIf;
|
|
PADAPTER pAdapter;
|
|
PCONN_ENTRY pConnEntry;
|
|
|
|
pAdapter = CONTAINING_RECORD(pleNode,
|
|
ADAPTER,
|
|
leAdapterLink);
|
|
|
|
//
|
|
// Lock the adapter and check its connection entry
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
pConnEntry = pAdapter->pConnEntry;
|
|
|
|
if(pConnEntry and
|
|
(pConnEntry->duUsage is DU_CALLOUT))
|
|
{
|
|
RtAssert(i < ulMaxInterfaces);
|
|
|
|
pIf = pAdapter->pInterface;
|
|
|
|
RtAssert(pIf);
|
|
RtAssert(pIf->dwRsvdAdapterIndex);
|
|
|
|
pQueueInfo->rgIfInfo[i].InterfaceGuid = pIf->Guid;
|
|
pQueueInfo->rgIfInfo[i].dwAdapterIndex = pIf->dwRsvdAdapterIndex;
|
|
pQueueInfo->rgIfInfo[i].dwLocalAddr = pConnEntry->dwLocalAddr;
|
|
pQueueInfo->rgIfInfo[i].dwLocalMask = pConnEntry->dwLocalMask;
|
|
pQueueInfo->rgIfInfo[i].dwRemoteAddr = pConnEntry->dwRemoteAddr;
|
|
|
|
i++;
|
|
}
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
|
|
}
|
|
|
|
g_bQueueNotifications = TRUE;
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlAdapterLock);
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
pIrp->IoStatus.Information = ulSizeReq;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
WanCancelNotificationIrp(
|
|
PDEVICE_OBJECT pDeviceObject,
|
|
PIRP pIrp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to cancel a queued irp
|
|
|
|
Locks:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
Trace(GLOBAL, TRACE,
|
|
("CancelNotificationIrp\n"));
|
|
|
|
|
|
//
|
|
// Mark this Irp as cancelled
|
|
//
|
|
|
|
pIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Take off our own list
|
|
//
|
|
|
|
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
|
|
|
|
//
|
|
// Release cancel spin lock which the IO system acquired
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
|
|
|
IoCompleteRequest(pIrp,
|
|
IO_NETWORK_INCREMENT);
|
|
}
|
|
|
|
|
|
VOID
|
|
WanpCompleteIrp(
|
|
PPENDING_NOTIFICATION pEvent
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes a notification irp.
|
|
|
|
Locks:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
|
|
Trace(GLOBAL, TRACE,
|
|
("Completing Notification Irp\n"));
|
|
|
|
//
|
|
// grab cancel spin lock
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&kiIrql);
|
|
|
|
if(!g_bQueueNotifications)
|
|
{
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
FreeNotification(pEvent);
|
|
|
|
return;
|
|
}
|
|
|
|
if(!IsListEmpty(&g_lePendingIrpList))
|
|
{
|
|
PLIST_ENTRY pleNode;
|
|
PIRP pIrp;
|
|
|
|
//
|
|
// We have a pending IRP. Use it to return info to router manager
|
|
//
|
|
|
|
pleNode = RemoveHeadList(&g_lePendingIrpList) ;
|
|
|
|
pIrp = CONTAINING_RECORD(pleNode,
|
|
IRP,
|
|
Tail.Overlay.ListEntry);
|
|
|
|
RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer,
|
|
&(pEvent->wnMsg),
|
|
sizeof(WANARP_NOTIFICATION));
|
|
|
|
Trace(GLOBAL, TRACE,
|
|
("Returning Irp with event code of %d\n",
|
|
((PWANARP_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer)->ddeEvent));
|
|
|
|
IoSetCancelRoutine(pIrp,
|
|
NULL);
|
|
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
pIrp->IoStatus.Information = sizeof(WANARP_NOTIFICATION);
|
|
|
|
//
|
|
// release lock
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
|
|
IoCompleteRequest(pIrp,
|
|
IO_NETWORK_INCREMENT);
|
|
|
|
//
|
|
// Free the allocated notification
|
|
//
|
|
|
|
FreeNotification(pEvent);
|
|
|
|
}
|
|
else
|
|
{
|
|
Trace(GLOBAL, TRACE,
|
|
("Found no pending Irp so queuing the notification\n"));
|
|
|
|
|
|
InsertTailList(&g_lePendingNotificationList,
|
|
&(pEvent->leNotificationLink));
|
|
|
|
//
|
|
// release lock
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(kiIrql);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
WanpGetNewIndex(
|
|
OUT PULONG pulIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets a new interface index from IP
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
pulIndex OUT interface index
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulMax;
|
|
|
|
*pulIndex = INVALID_IF_INDEX;
|
|
|
|
return g_pfnIpReserveIndex(1, pulIndex, &ulMax);
|
|
}
|
|
|
|
VOID
|
|
WanpFreeIndex(
|
|
IN ULONG ulIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees an index back to IP
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
ulIndex
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulMax;
|
|
|
|
g_pfnIpDereserveIndex(1,
|
|
ulIndex);
|
|
}
|
|
|