windows-nt/Source/XPSP1/NT/net/nwlink/fwd/driver.c
2020-09-26 16:20:57 +08:00

1218 lines
30 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ntos\tdi\isn\fwd\driver.c
Abstract:
IPX Forwarder driver dispatch routines
Author:
Vadim Eydelman
Revision History:
--*/
#include "precomp.h"
const UCHAR BROADCAST_NODE[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const LONGLONG WaitTimeout = -50000000i64;
volatile BOOLEAN IpxFwdInitialized = FALSE;
BOOLEAN MeasuringPerformance = FALSE;
KSPIN_LOCK PerfCounterLock;
FWD_PERFORMANCE PerfBlock;
LONG ClientCount = 0;
KEVENT ClientsGoneEvent;
PFILE_OBJECT RouterFile, FilterFile;
NTSTATUS
IpxFwdDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
IpxFwdUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
DoStart (
IN ULONG RouteHashTableSize,
IN BOOLEAN thisMachineOnly
);
NTSTATUS
DoStop (
void
);
NTSTATUS
DoSetInterface (
IN ULONG InterfaceIndex,
IN BOOLEAN NetbiosAccept,
IN UCHAR NetbiosDeliver
);
NTSTATUS
DoGetInterface (
IN ULONG InterfaceIndex,
OUT PFWD_IF_STATS stats,
OUT BOOLEAN *NetbiosAccept,
OUT UCHAR *NetbiosDeliver
);
NTSTATUS
DoSetNbNames (
IN ULONG InterfaceIndex,
IN ULONG Count,
IN PFWD_NB_NAME Names
);
NTSTATUS
DoGetNbNames (
IN ULONG InterfaceIndex,
IN OUT ULONG *BufferSize,
OUT ULONG *Count,
OUT PFWD_NB_NAME Names
);
NTSTATUS
DoBindInterface (
IN ULONG InterfaceIndex,
IN PFWD_ADAPTER_BINDING_INFO info
);
NTSTATUS
DoUnbindInterface (
IN ULONG InterfaceIndex
);
NTSTATUS
DoDisableInterface (
IN ULONG InterfaceIndex
);
NTSTATUS
DoEnableInterface (
IN ULONG InterfaceIndex
);
NTSTATUS
DoSetRoutes (
IN PFWD_ROUTE_SET_PARAMS routeArray,
IN ULONG nRoutes,
OUT PULONG nProcessed
);
VOID
IpxFwdCancel (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP irp
);
NTSTATUS
DoGetPerfCounters (
OUT PFWD_PERFORMANCE_PARAMS perfParams,
OUT ULONG* plSize
);
// [pmay] Keep the forwarder sync'd with the stack's nic id
// numbering scheme.
NTSTATUS DecrementNicids (USHORT usThreshold);
NTSTATUS IncrementNicids (USHORT usThreshold);
NTSTATUS DoGetIfTable (FWD_INTERFACE_TABLE_ROW * pRows,
ULONG dwRowBufferSize);
/*++
D r i v e r E n t r y
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
) {
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS status;
WCHAR deviceNameBuffer[] = IPXFWD_NAME;
UNICODE_STRING deviceNameUnicodeString;
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION,
("IpxFwd: Entering DriverEntry\n"));
//
// Create an non-EXCLUSIVE device object
//
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer);
status = IoCreateDevice (DriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_IPXFWD,
0,
FALSE, // Non-Exclusive
&deviceObject
);
if (NT_SUCCESS(status)) {
//
// Create dispatch points for device control, create, close.
//
GetForwarderParameters (RegistryPath);
DriverObject->MajorFunction[IRP_MJ_CREATE]
= DriverObject->MajorFunction[IRP_MJ_CLEANUP]
= DriverObject->MajorFunction[IRP_MJ_CLOSE]
= DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
= IpxFwdDispatch;
DriverObject->DriverUnload = IpxFwdUnload;
status = BindToIpxDriver (KernelMode);
if (NT_SUCCESS (status)) {
#if DBG
KeQueryPerformanceCounter (&CounterFrequency);
#endif
FilterFile = RouterFile = NULL;
ClientCount = 0;
return STATUS_SUCCESS;
}
IoDeleteDevice (DriverObject->DeviceObject);
}
else
IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
("IpxFwd: IoCreateDevice failed\n"));
return status;
}
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
NTSTATUS
IpxFwdDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
) {
PIO_STACK_LOCATION IrpStack;
PVOID inBuffer, outBuffer;
ULONG inpBufLength;
ULONG outBufLength;
NTSTATUS status;
KIRQL cancelIRQL;
LONG lNumProcessed;
ULONG ulBytesCopied;
ulBytesCopied = 0;
lNumProcessed = 0;
Irp->IoStatus.Information = 0;
status = STATUS_SUCCESS;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
IrpStack = IoGetCurrentIrpStackLocation(Irp);
switch (IrpStack->MajorFunction) {
case IRP_MJ_CREATE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CREATE\n"));
break;
case IRP_MJ_CLOSE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CLOSE\n"));
if (EnterForwarder ()) {
if (IrpStack->FileObject==RouterFile) {
LeaveForwarder ();
IpxFwdInitialized = FALSE;
while (InterlockedDecrement (&ClientCount)>=0) {
KeWaitForSingleObject (&ClientsGoneEvent,
Executive,
KernelMode,
FALSE,
(PLARGE_INTEGER)&WaitTimeout);
InterlockedIncrement (&ClientCount);
IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
("IpxFwd: Waiting for all clients (%ld) to exit.\n",
ClientCount));
}
status = DoStop ();
ClientCount = 0;
RouterFile = NULL;
}
else if (IrpStack->FileObject==FilterFile) {
UnbindFilterDriver ();
FilterFile = NULL;
LeaveForwarder ();
}
else
LeaveForwarder ();
}
break;
case IRP_MJ_CLEANUP:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: IRP_MJ_CLEANUP\n"));
if (EnterForwarder ()) {
if (IrpStack->FileObject==RouterFile) {
IoAcquireCancelSpinLock (&cancelIRQL);
while (!IsListEmpty (&ConnectionIrpQueue)) {
PIRP irp = CONTAINING_RECORD (ConnectionIrpQueue.Blink,
IRP, Tail.Overlay.ListEntry);
irp->Cancel = TRUE;
irp->CancelIrql = cancelIRQL;
irp->CancelRoutine = NULL;
IpxFwdCancel(DeviceObject, irp);
IoAcquireCancelSpinLock (&cancelIRQL);
}
IoReleaseCancelSpinLock(cancelIRQL);
}
LeaveForwarder ();
}
break;
case IRP_MJ_DEVICE_CONTROL:
//
// Get the pointer to the input/output buffer and it's length
//
status = STATUS_INVALID_PARAMETER;
inpBufLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode&3) {
case METHOD_BUFFERED:
inBuffer = outBuffer = Irp->AssociatedIrp.SystemBuffer;
break;
case METHOD_IN_DIRECT:
case METHOD_OUT_DIRECT:
inBuffer = Irp->AssociatedIrp.SystemBuffer;
if (outBufLength>0) {
outBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, NormalPagePriority);
if (outBuffer == NULL)
{
IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
("IpxFwd: System too low on memory to allocate mdl buffer.\n"));
goto DispatchExit;
}
}
else {
outBuffer = NULL;
IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
("IpxFwd: IOCTL...METHOD_DIRECT with 0 output buffer ???\n"));
}
break;
default:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
("IpxFwd: IOCTL...METHOD_NEITHER ???\n"));
goto DispatchExit;
}
if (EnterForwarder ()) {
if (IrpStack->FileObject==RouterFile) {
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_FWD_SET_ROUTES:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_ROUTES\n"));
if (inpBufLength>=sizeof (FWD_ROUTE_SET_PARAMS))
status = DoSetRoutes (
(PFWD_ROUTE_SET_PARAMS)inBuffer,
inpBufLength/sizeof(FWD_ROUTE_SET_PARAMS),
&lNumProcessed);
break;
case IOCTL_FWD_SET_NB_NAMES:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_NB_NAMES\n"));
if (inpBufLength==sizeof (ULONG))
status = DoSetNbNames (
*((PULONG)inBuffer),
outBufLength/sizeof (FWD_NB_NAME),
(PFWD_NB_NAME)outBuffer);
break;
case IOCTL_FWD_RESET_NB_NAMES:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_RESET_NB_NAMES\n"));
if (inpBufLength==sizeof (ULONG))
status = DoSetNbNames (*((PULONG)inBuffer), 0, NULL);
break;
case IOCTL_FWD_GET_NB_NAMES:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_NB_NAMES\n"));
if ((inpBufLength==sizeof (ULONG))
&& (outBufLength>=sizeof(ULONG))) {
Irp->IoStatus.Information = outBufLength
-FIELD_OFFSET (FWD_NB_NAMES_PARAMS, Names);
status = DoGetNbNames (
*((PULONG)inBuffer),
&ulBytesCopied,
&((PFWD_NB_NAMES_PARAMS)outBuffer)->TotalCount,
((PFWD_NB_NAMES_PARAMS)outBuffer)->Names);
Irp->IoStatus.Information = ulBytesCopied;
if (NT_SUCCESS (status)) {
Irp->IoStatus.Information += FIELD_OFFSET (
FWD_NB_NAMES_PARAMS, Names);
}
}
break;
case IOCTL_FWD_CREATE_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_CREATE_INTERFACE\n"));
if (inpBufLength==sizeof(FWD_IF_CREATE_PARAMS))
status = AddInterface (
((PFWD_IF_CREATE_PARAMS)inBuffer)->Index,
((PFWD_IF_CREATE_PARAMS)inBuffer)->InterfaceType,
((PFWD_IF_CREATE_PARAMS)inBuffer)->NetbiosAccept,
((PFWD_IF_CREATE_PARAMS)inBuffer)->NetbiosDeliver);
break;
case IOCTL_FWD_DELETE_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DELETE_INTERFACE\n"));
if (inpBufLength==sizeof(ULONG))
status = DeleteInterface (
*((PULONG)inBuffer));
break;
case IOCTL_FWD_SET_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_SET_INTERFACE\n"));
if (inpBufLength==sizeof(FWD_IF_SET_PARAMS))
status = DoSetInterface (
((PFWD_IF_SET_PARAMS)inBuffer)->Index,
((PFWD_IF_SET_PARAMS)inBuffer)->NetbiosAccept,
((PFWD_IF_SET_PARAMS)inBuffer)->NetbiosDeliver);
break;
case IOCTL_FWD_GET_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_INTERFACE\n"));
if ((inpBufLength==sizeof(ULONG))
&& (outBufLength==sizeof(FWD_IF_GET_PARAMS))) {
status = DoGetInterface (
*((PULONG)inBuffer),
&((PFWD_IF_GET_PARAMS)outBuffer)->Stats,
&((PFWD_IF_GET_PARAMS)outBuffer)->NetbiosAccept,
&((PFWD_IF_GET_PARAMS)outBuffer)->NetbiosDeliver);
if (NT_SUCCESS (status))
Irp->IoStatus.Information = sizeof(FWD_IF_GET_PARAMS);
}
break;
case IOCTL_FWD_BIND_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_BIND_INTERFACE\n"));
if (inpBufLength==sizeof(FWD_IF_BIND_PARAMS))
status = DoBindInterface (
((PFWD_IF_BIND_PARAMS)inBuffer)->Index,
&((PFWD_IF_BIND_PARAMS)inBuffer)->Info);
break;
case IOCTL_FWD_UNBIND_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_UNBIND_INTERFACE\n"));
if (inpBufLength==sizeof(ULONG))
status = DoUnbindInterface (*((PULONG)inBuffer));
break;
case IOCTL_FWD_RENUMBER_NICS:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_RENUMBER_NICS\n"));
if (inpBufLength == sizeof(FWD_RENUMBER_NICS_DATA)) {
if (((FWD_RENUMBER_NICS_DATA*)inBuffer)->ulOpCode == FWD_NIC_OPCODE_DECREMENT)
status = DecrementNicids (((FWD_RENUMBER_NICS_DATA*)inBuffer)->usThreshold);
else
status = IncrementNicids (((FWD_RENUMBER_NICS_DATA*)inBuffer)->usThreshold);
}
break;
case IOCTL_FWD_GET_DIAL_REQUEST:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_DIAL_REQUEST\n"));
if (outBufLength>=sizeof (ULONG)) {
IoAcquireCancelSpinLock (&cancelIRQL);
if (!IsListEmpty (&ConnectionRequestQueue)) {
PINTERFACE_CB ifCB = CONTAINING_RECORD (
ConnectionRequestQueue.Flink,
INTERFACE_CB,
ICB_ConnectionLink);
RemoveEntryList (&ifCB->ICB_ConnectionLink);
InitializeListEntry (&ifCB->ICB_ConnectionLink);
IoReleaseCancelSpinLock (cancelIRQL);
KeAcquireSpinLock (&ifCB->ICB_Lock, &cancelIRQL);
FillConnectionRequest (
ifCB->ICB_Index,
ifCB->ICB_ConnectionPacket,
ifCB->ICB_ConnectionData,
(PFWD_DIAL_REQUEST)outBuffer,
outBufLength,
&ulBytesCopied);
Irp->IoStatus.Information = ulBytesCopied;
status = STATUS_SUCCESS;
KeReleaseSpinLock (&ifCB->ICB_Lock, cancelIRQL);
}
else {
InsertTailList (&ConnectionIrpQueue,
&Irp->Tail.Overlay.ListEntry);
IoSetCancelRoutine (Irp, IpxFwdCancel);
IoMarkIrpPending (Irp);
Irp->IoStatus.Status = status = STATUS_PENDING;
IoReleaseCancelSpinLock (cancelIRQL);
}
}
break;
case IOCTL_FWD_DIAL_REQUEST_FAILED:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DIAL_REQUEST_FAILED\n"));
if (inpBufLength==sizeof (ULONG))
status = FailConnectionRequest (
*((PULONG)inBuffer));
break;
case IOCTL_FWD_DISABLE_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_DISABLE_INTERFACE\n"));
if (inpBufLength==sizeof (ULONG))
status = DoDisableInterface (
*((PULONG)inBuffer));
break;
case IOCTL_FWD_ENABLE_INTERFACE:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_ENABLE_INTERFACE\n"));
if (inpBufLength==sizeof (ULONG))
status = DoEnableInterface (
*((PULONG)inBuffer));
break;
case IOCTL_FWD_UPDATE_CONFIG:
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_UPDATE_CONFIG\n"));
if (inpBufLength==sizeof (FWD_UPDATE_CONFIG_PARAMS)) {
ThisMachineOnly = ((FWD_UPDATE_CONFIG_PARAMS*)inBuffer)->bThisMachineOnly;
status = STATUS_SUCCESS;
}
break;
default:
IpxFwdDbgPrint (DBG_IOCTLS, DBG_WARNING, ("IpxFwd: unknown IRP_MJ_DEVICE_CONTROL\n"));
break;
}
}
else if (IrpStack->Parameters.DeviceIoControl.IoControlCode
==IOCTL_FWD_INTERNAL_BIND_FILTER)
{
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_INTERNAL_BIND_FILTER\n"));
//
// pmay: 218246
// We only allow the kernel-mode ipx filter driver
// to bind to us.
//
if (
(ExGetPreviousMode() == KernelMode) &&
(inpBufLength == sizeof(IPX_FLT_BIND_INPUT) ) &&
(outBufLength >= sizeof(ULONG) )
)
{
if (outBufLength >= sizeof (IPX_FLT_BIND_OUTPUT)) {
BindFilterDriver (
(PIPX_FLT_BIND_INPUT)inBuffer,
(PIPX_FLT_BIND_OUTPUT)outBuffer);
Irp->IoStatus.Information = sizeof (IPX_FLT_BIND_OUTPUT);
FilterFile = IrpStack->FileObject;
status = STATUS_SUCCESS;
}
else {
IPX_FLT_BIND_OUTPUT bindOutput;
BindFilterDriver (
(PIPX_FLT_BIND_INPUT)inBuffer,
&bindOutput);
memcpy (outBuffer, &bindOutput, outBufLength);
Irp->IoStatus.Information = outBufLength;
status = STATUS_BUFFER_OVERFLOW;
}
}
}
else if (IrpStack->Parameters.DeviceIoControl.IoControlCode
==IOCTL_FWD_GET_PERF_COUNTERS) {
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_PERF_COUNTERS\n"));
if (outBufLength==sizeof (FWD_PERFORMANCE_PARAMS))
{
status = DoGetPerfCounters (
((PFWD_PERFORMANCE_PARAMS)outBuffer),
&ulBytesCopied);
Irp->IoStatus.Information = ulBytesCopied;
}
}
else if (IrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_FWD_GET_IF_TABLE) {
IpxFwdDbgPrint(DBG_IOCTLS, DBG_INFORMATION, ("IpxFwd: IOCTL_FWD_GET_IF_TABLE\n"));
status = DoGetIfTable (outBuffer, outBufLength);
Irp->IoStatus.Information = outBufLength;
}
else {
status = STATUS_ACCESS_DENIED;
IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING,
("IpxFwd: IOCTL: %08lx on non-router file object!\n",
IrpStack->Parameters.DeviceIoControl.IoControlCode));
}
LeaveForwarder ();
} else {
if (IrpStack->Parameters.DeviceIoControl.IoControlCode==IOCTL_FWD_START) {
IpxFwdDbgPrint (DBG_IOCTLS, DBG_WARNING,
("IpxFwd: IOCTL_FWD_START\n"));
if (inpBufLength==sizeof (FWD_START_PARAMS)) {
KeInitializeEvent (&ClientsGoneEvent,
SynchronizationEvent,
FALSE);
status = DoStart (
((PFWD_START_PARAMS)inBuffer)->RouteHashTableSize,
((PFWD_START_PARAMS)inBuffer)->ThisMachineOnly);
if (NT_SUCCESS (status)) {
RouterFile = IrpStack->FileObject;
IpxFwdInitialized = TRUE;
}
}
}
else {
IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
("IpxFwd: IOCTL: %08lx but fwd not started.\n",
IrpStack->Parameters.DeviceIoControl.IoControlCode));
}
}
break;
default:
IpxFwdDbgPrint (DBG_IOCTLS, DBG_ERROR,
("IpxFwd: unknown MajorFunction.\n"));
break;
}
DispatchExit:
if (status!=STATUS_PENDING) {
IpxFwdDbgPrint(DBG_IOCTLS,
NT_ERROR(status) ? DBG_WARNING : DBG_INFORMATION,
("IpxFwd: completing IOCTL %08lx with status %08lx.\n",
IrpStack->Parameters.DeviceIoControl.IoControlCode,
status));
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
}
/*++
Routine Description:
Cleans up on driver unload
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
VOID
IpxFwdUnload(
IN PDRIVER_OBJECT DriverObject
) {
IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: unloading\n"));
if (EnterForwarder ()) {
LeaveForwarder ();
IpxFwdInitialized = FALSE;
while (InterlockedDecrement (&ClientCount)>=0) {
KeWaitForSingleObject (&ClientsGoneEvent,
Executive,
KernelMode,
FALSE,
(PLARGE_INTEGER)&WaitTimeout);
InterlockedIncrement (&ClientCount);
IpxFwdDbgPrint(DBG_IOCTLS, DBG_ERROR,
("IpxFwd: Waiting for all clients (%ld) to exit.\n",
ClientCount));
}
DoStop ();
}
UnbindFromIpxDriver (KernelMode);
IoDeleteDevice (DriverObject->DeviceObject);
}
/*++
D o S t a r t
Routine Description:
Initializes all driver components and binds to IPX
stack driver at strat up
Arguments:
RouteHashTableSize - size of route hash table
thisMachineOnly - whether to forward dialin client packets
to other dests on the net
Return Value:
STATUS_SUCCESS - initialization succeded
STATUS_UNSUCCESSFULL - failure
--*/
NTSTATUS
DoStart (
IN ULONG RouteHashTableSize,
IN BOOLEAN thisMachineOnly
) {
NTSTATUS status;
InitializeConnectionQueues ();
RouteHashSize = RouteHashTableSize;
status = CreateTables ();
if (NT_SUCCESS (status)) {
InitializePacketAllocator ();
InitializeNetbiosQueue ();
InitializeRecvQueue ();
InitializeSendQueue ();
MeasuringPerformance = FALSE;
KeInitializeSpinLock (&PerfCounterLock);
ThisMachineOnly = thisMachineOnly;
return STATUS_SUCCESS;
}
return status;
}
/*++
D o S t o p
Routine Description:
Cleans up allocated resources and unbinds from IPX stack
driver when forwarder is stopped
Arguments:
None
Return Value:
STATUS_SUCCESS - cleanup succeded
--*/
NTSTATUS
DoStop (
void
) {
if (FilterFile!=NULL) {
UnbindFilterDriver ();
FilterFile = NULL;
}
DeleteSendQueue ();
DeleteRecvQueue ();
DeleteNetbiosQueue ();
DeleteTables (); // Unbinds all bound interfaces
if (WanPacketListId!=-1) {
DeregisterPacketConsumer (WanPacketListId);
WanPacketListId = -1;
}
DeletePacketAllocator ();
return STATUS_SUCCESS;
}
/*++
D o S e t R o u t e s
Routine Description:
Updates route table with supplied routes
Arguments:
routeArray - array of routes to add/de;ete/update
nRoutes - number of routes in the array
nProcessed - number of routes that were processed successfully
Return Value:
STATUS_SUCCESS - all routes were processed ok
error status - reason of failure for the first unprocessed route
--*/
NTSTATUS
DoSetRoutes (
IN PFWD_ROUTE_SET_PARAMS routeArray,
IN ULONG nRoutes,
OUT PULONG nProcessed
) {
NTSTATUS status=STATUS_SUCCESS;
UINT i;
for (i=0; i<nRoutes; i++, routeArray++) {
switch (routeArray->Action) {
case FWD_ADD_ROUTE:
status = AddRoute (routeArray->Network,
routeArray->NextHopAddress,
routeArray->TickCount,
routeArray->HopCount,
routeArray->InterfaceIndex);
break;
case FWD_DELETE_ROUTE:
status = DeleteRoute (routeArray->Network);
break;
case FWD_UPDATE_ROUTE:
status = UpdateRoute (routeArray->Network,
routeArray->NextHopAddress,
routeArray->TickCount,
routeArray->HopCount,
routeArray->InterfaceIndex);
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS (status))
break;
}
*nProcessed = i;
return status;
}
/*++
D o S e t N b N a m e s
Routine Description:
Sets static Netbios Names on the interface
Arguments:
InterfaceIndex - index oc interface on which to set names
Count - number of names to set
Names - array of netbios names
Return Value:
STATUS_SUCCESS - names were set OK
STATUS_UNSUCCESSFULL - interface does not exist
STATUS_INSUFFICIENT_RESOURCES - not enough resources to complete
the operation
--*/
NTSTATUS
DoSetNbNames (
IN ULONG InterfaceIndex,
IN ULONG Count,
IN PFWD_NB_NAME Names
) {
PINTERFACE_CB ifCB;
KIRQL oldIRQL;
PNB_ROUTE nbRoutes;
NTSTATUS status=STATUS_SUCCESS;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
if (ifCB->ICB_NBRoutes!=NULL) {
DeleteNBRoutes (ifCB->ICB_NBRoutes, ifCB->ICB_NBRouteCount);
ifCB->ICB_NBRoutes = NULL;
ifCB->ICB_NBRouteCount = 0;
}
if (Count>0) {
status = AddNBRoutes (ifCB, Names, Count, &nbRoutes);
if (NT_SUCCESS (status)) {
ifCB->ICB_NBRoutes = nbRoutes;
ifCB->ICB_NBRouteCount = Count;
}
}
ReleaseInterfaceReference (ifCB);
}
else
status = STATUS_UNSUCCESSFUL;
return status;
}
/*++
D o G e t N b N a m e s
Routine Description:
Gets all static Netbios Names on the interface
Arguments:
InterfaceIndex - index of interface from which to get names
ArraySize - on input: size of the buffer to put names into
on output: size of data put into the array
Names - buffer to put names into names, if buffer
is to small to hold all names, this orutine stuffs
total number of names into the first ULONG in the
array (this is the only way to return in to the
caller through the IOCTL interface)
Return Value:
STATUS_SUCCESS - names were copied into the array
STATUS_UNSUCCESSFULL - interface does not exist
STATUS_BUFFER_OVERFLOW - buffer is too small to copy all the
names, number of names are in the first ULONG of
the buffer
--*/
NTSTATUS
DoGetNbNames (
IN ULONG InterfaceIndex,
IN OUT ULONG *ArraySize,
OUT ULONG *TotalCount,
OUT PFWD_NB_NAME Names
) {
PINTERFACE_CB ifCB;
KIRQL oldIRQL;
NTSTATUS status=STATUS_SUCCESS;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
if (ifCB->ICB_NBRoutes!=NULL) {
ULONG i;
PFWD_NB_NAME nameLM = Names+(*ArraySize/sizeof(FWD_NB_NAME));
for (i=0; (i<ifCB->ICB_NBRouteCount)&&(Names<nameLM); i++, Names++)
NB_NAME_CPY (Names, &ifCB->ICB_NBRoutes[i].NBR_Name);
*ArraySize = sizeof (FWD_NB_NAME)*i;
*TotalCount = ifCB->ICB_NBRouteCount;
}
else {
*ArraySize = 0;
*TotalCount = 0;
}
ReleaseInterfaceReference (ifCB);
}
else
status = STATUS_UNSUCCESSFUL;
return status;
}
/*++
D o S e t I n t e r f a c e
Routine Description:
Sets interface configurable parameters
Arguments:
InterfaceIndex - index of interface to set
NetbiosAccept - whether to accept nb packets on the interface
NetbiosDeliver - whether to deliver nb packets on the interface
Return Value:
STATUS_SUCCESS - interface was set OK
STATUS_UNSUCCESSFULL - interface does not exist
--*/
NTSTATUS
DoSetInterface (
IN ULONG InterfaceIndex,
IN BOOLEAN NetbiosAccept,
IN UCHAR NetbiosDeliver
) {
PINTERFACE_CB ifCB;
KIRQL oldIRQL;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
ifCB->ICB_NetbiosAccept = NetbiosAccept;
ifCB->ICB_NetbiosDeliver = NetbiosDeliver;
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
ReleaseInterfaceReference (ifCB);
return STATUS_SUCCESS;
}
else
return STATUS_UNSUCCESSFUL;
}
/*++
D o G e t I n t e r f a c e
Routine Description:
Gets interface configurable parameters and statistics
Arguments:
InterfaceIndex - index of interface to query
stats - interface statistics
NetbiosAccept - whether nb packets accepter on the interface
NetbiosDeliver - whether nb packets delivered on the interface
Return Value:
STATUS_SUCCESS - interface data was queried OK
STATUS_UNSUCCESSFULL - interface does not exist
--*/
NTSTATUS
DoGetInterface (
IN ULONG InterfaceIndex,
OUT PFWD_IF_STATS stats,
OUT BOOLEAN *NetbiosAccept,
OUT UCHAR *NetbiosDeliver
) {
PINTERFACE_CB ifCB;
KIRQL oldIRQL;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
*NetbiosAccept = ifCB->ICB_NetbiosAccept;
*NetbiosDeliver = ifCB->ICB_NetbiosDeliver;
IF_STATS_CPY (stats, &ifCB->ICB_Stats);
if (!IS_IF_ENABLED(ifCB))
stats->OperationalState = FWD_OPER_STATE_DOWN;
ReleaseInterfaceReference (ifCB);
return STATUS_SUCCESS;
}
else
return STATUS_UNSUCCESSFUL;
}
/*++
D o B i n d I n t e r f a c e
Routine Description:
Binds interface to the specified adapter and sets binding
parameters
Arguments:
InterfaceIndex - index of interface to bind
info - binding info
Return Value:
STATUS_SUCCESS - interface was bound OK
STATUS_UNSUCCESSFULL - interface does not exist or could not be
bound
--*/
NTSTATUS
DoBindInterface (
IN ULONG InterfaceIndex,
IN PFWD_ADAPTER_BINDING_INFO info
) {
PINTERFACE_CB ifCB;
NTSTATUS status;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
status = BindInterface (ifCB,
(USHORT)info->AdapterIndex,
info->MaxPacketSize,
info->Network,
info->LocalNode,
info->RemoteNode);
else
status = STATUS_SUCCESS;
ReleaseInterfaceReference (ifCB);
return status;
}
else
return STATUS_UNSUCCESSFUL;
}
/*++
D o U n b i n d I n t e r f a c e
Routine Description:
Unbinds interface from the adapter and invalidates binding
parameters
Arguments:
InterfaceIndex - index of interface to unbind
Return Value:
STATUS_SUCCESS - interface was unbound OK
STATUS_UNSUCCESSFULL - interface does not exist
--*/
NTSTATUS
DoUnbindInterface (
IN ULONG InterfaceIndex
) {
PINTERFACE_CB ifCB;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
if (ifCB->ICB_InterfaceType==FWD_IF_PERMANENT)
UnbindInterface (ifCB);
ReleaseInterfaceReference (ifCB);
return STATUS_SUCCESS;
}
else
return STATUS_UNSUCCESSFUL;
}
/*++
D o D i s a b l e I n t e r f a c e
Routine Description:
Disables all packet traffic through the interface
Arguments:
InterfaceIndex - index of interface to disable
Return Value:
STATUS_SUCCESS - interface was disabled OK
STATUS_UNSUCCESSFULL - interface does not exist
--*/
NTSTATUS
DoDisableInterface (
IN ULONG InterfaceIndex
) {
PINTERFACE_CB ifCB;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
KIRQL oldIRQL;
KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
if (IS_IF_ENABLED (ifCB)) {
SET_IF_DISABLED (ifCB);
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
if (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX) {
ProcessInternalQueue (ifCB);
ProcessExternalQueue (ifCB);
}
}
else
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
ReleaseInterfaceReference (ifCB);
return STATUS_SUCCESS;
}
else
return STATUS_UNSUCCESSFUL;
}
/*++
D o E n a b l e I n t e r f a c e
Routine Description:
Enables all packet traffic through the interface
Arguments:
InterfaceIndex - index of interface to enable
Return Value:
STATUS_SUCCESS - interface was disabled OK
STATUS_UNSUCCESSFULL - interface does not exist
--*/
NTSTATUS
DoEnableInterface (
IN ULONG InterfaceIndex
) {
PINTERFACE_CB ifCB;
ifCB = GetInterfaceReference (InterfaceIndex);
if (ifCB!=NULL) {
SET_IF_ENABLED (ifCB);
ReleaseInterfaceReference (ifCB);
return STATUS_SUCCESS;
}
else
return STATUS_UNSUCCESSFUL;
}
/*++
I p x F w d C a n c e l
Routine Description:
Cancels specified IRP
Arguments:
DeviceObject - forwarder device object
irp - irp to cancel
Return Value:
None
--*/
VOID
IpxFwdCancel (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP irp
) {
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
IoReleaseCancelSpinLock (irp->CancelIrql);
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_CANCELLED;
IpxFwdDbgPrint(DBG_IOCTLS, DBG_WARNING, ("IpxFwd: completing cancelled irp.\n"));
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
/*++
D o G e t P e r f C o u n t e r s
Routine Description:
Gets performance counters
Arguments:
perfParams - buffer ot pu counters into
Return Value:
STATUS_SUCCESS - counter were copied ok
STATUS_UNSUCCESSFULL - performance measurement were not enabled
--*/
NTSTATUS
DoGetPerfCounters (
OUT PFWD_PERFORMANCE_PARAMS perfParams,
OUT ULONG* pulSize
) {
LONGLONG lTotalPacketProcessingTime;
LONGLONG lMaxPacketProcessingTime;
LONG lPacketCounter;
LONGLONG lTotalNbPacketProcessingTime;
LONGLONG lMaxNbPacketProcessingTime;
LONG lNbPacketCounter;
KIRQL oldIRQL;
if (!MeasuringPerformance)
return STATUS_UNSUCCESSFUL;
KeAcquireSpinLock (&PerfCounterLock, &oldIRQL);
*perfParams = PerfBlock;
memset (&PerfBlock, 0, sizeof (PerfBlock));
KeReleaseSpinLock (&PerfCounterLock, oldIRQL);
*pulSize = sizeof(PerfBlock);
return STATUS_SUCCESS;
}
BOOLEAN
DoLeaveForwarder (
VOID
) {
return LeaveForwarder () != 0;
}