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.
484 lines
13 KiB
484 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntos\tdi\isn\fwd\ipxbind.c
|
|
|
|
Abstract:
|
|
IPX Forwarder Driver interface with IPX stack driver
|
|
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
// global handle of the IPX driver
|
|
HANDLE HdlIpxFile;
|
|
|
|
|
|
// Buffer for IPX binding output structure
|
|
PIPX_INTERNAL_BIND_RIP_OUTPUT IPXBindOutput=NULL;
|
|
|
|
NTSTATUS
|
|
IpxFwdFindRoute (
|
|
IN PUCHAR Network,
|
|
IN PUCHAR Node,
|
|
OUT PIPX_FIND_ROUTE_REQUEST RouteEntry
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
B i n d T o I p x D r i v e r
|
|
|
|
Routine Description:
|
|
Exchanges binding information with IPX stack driver
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
STATUS_SUCCESS - exchange was done OK
|
|
STATUS_INSUFFICIENT_RESOURCES - could not allocate buffers for
|
|
info exchange
|
|
error status returned by IPX stack driver
|
|
|
|
*******************************************************************
|
|
--*/
|
|
NTSTATUS
|
|
BindToIpxDriver (
|
|
KPROCESSOR_MODE requestorMode
|
|
) {
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PIPX_INTERNAL_BIND_INPUT bip;
|
|
UNICODE_STRING UstrIpxFileName;
|
|
PWSTR WstrIpxFileName;
|
|
|
|
ASSERT (IPXBindOutput==NULL);
|
|
|
|
// Read Ipx exported device name from the registry
|
|
status = ReadIpxDeviceName (&WstrIpxFileName);
|
|
if (!NT_SUCCESS (status))
|
|
return status;
|
|
|
|
RtlInitUnicodeString (&UstrIpxFileName, WstrIpxFileName);
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UstrIpxFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (requestorMode==UserMode)
|
|
status = ZwCreateFile(&HdlIpxFile,
|
|
SYNCHRONIZE | GENERIC_READ,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0L);
|
|
else
|
|
status = NtCreateFile(&HdlIpxFile,
|
|
SYNCHRONIZE | GENERIC_READ,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0L);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
|
|
("IpxFwd: Open of the IPX driver failed with %lx\n", status));
|
|
return status;
|
|
}
|
|
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
|
|
("IpxFwd: Open of the IPX driver was successful.\n"));
|
|
|
|
// First, send a IOCTL to find out how much data we need to allocate
|
|
if ((bip = ExAllocatePoolWithTag (
|
|
PagedPool,
|
|
sizeof(IPX_INTERNAL_BIND_INPUT),
|
|
FWD_POOL_TAG)) == NULL) {
|
|
|
|
if (ExGetPreviousMode()!=KernelMode)
|
|
ZwClose (HdlIpxFile);
|
|
else
|
|
NtClose (HdlIpxFile);
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
|
|
("IpxFwd: Could not allocate input binding buffer!\n"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Zero out the memory so that there are no garbage pointers.
|
|
// - ShreeM
|
|
//
|
|
RtlZeroMemory(bip, sizeof(IPX_INTERNAL_BIND_INPUT));
|
|
|
|
// fill in our bind data
|
|
// bip->Version = 1;
|
|
bip->Version = ISN_VERSION;
|
|
bip->Identifier = IDENTIFIER_RIP;
|
|
bip->BroadcastEnable = TRUE;
|
|
bip->LookaheadRequired = IPXH_HDRSIZE;
|
|
bip->ProtocolOptions = 0;
|
|
bip->ReceiveHandler = IpxFwdReceive;
|
|
bip->ReceiveCompleteHandler = IpxFwdReceiveComplete;
|
|
bip->SendCompleteHandler = IpxFwdSendComplete;
|
|
bip->TransferDataCompleteHandler = IpxFwdTransferDataComplete;
|
|
bip->FindRouteCompleteHandler = NULL;
|
|
bip->LineUpHandler = IpxFwdLineUp;
|
|
bip->LineDownHandler = IpxFwdLineDown;
|
|
bip->InternalSendHandler = IpxFwdInternalSend;
|
|
bip->FindRouteHandler = IpxFwdFindRoute;
|
|
bip->InternalReceiveHandler = IpxFwdInternalReceive;
|
|
// bip->RipParameters = GlobalWanNetwork ? IPX_RIP_PARAM_GLOBAL_NETWORK : 0;
|
|
|
|
|
|
if (requestorMode==UserMode)
|
|
status = ZwDeviceIoControlFile(
|
|
HdlIpxFile, // HANDLE to File
|
|
NULL, // HANDLE to Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&IoStatusBlock, // IO_STATUS_BLOCK
|
|
IOCTL_IPX_INTERNAL_BIND, // IoControlCode
|
|
bip, // Input Buffer
|
|
sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
|
|
NULL, // Output Buffer
|
|
0); // Output Buffer Length
|
|
else
|
|
status = NtDeviceIoControlFile(
|
|
HdlIpxFile, // HANDLE to File
|
|
NULL, // HANDLE to Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&IoStatusBlock, // IO_STATUS_BLOCK
|
|
IOCTL_IPX_INTERNAL_BIND, // IoControlCode
|
|
bip, // Input Buffer
|
|
sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
|
|
NULL, // Output Buffer
|
|
0); // Output Buffer Length
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
if (requestorMode==UserMode)
|
|
status = ZwWaitForSingleObject(
|
|
HdlIpxFile,
|
|
FALSE,
|
|
NULL);
|
|
else
|
|
status = NtWaitForSingleObject(
|
|
HdlIpxFile,
|
|
FALSE,
|
|
NULL);
|
|
if (NT_SUCCESS(status))
|
|
status = IoStatusBlock.Status;
|
|
}
|
|
|
|
if (status != STATUS_BUFFER_TOO_SMALL) {
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
|
|
("IpxFwd: Ioctl to the IPX driver failed with %lx\n", status));
|
|
|
|
ExFreePool(bip);
|
|
if (requestorMode==UserMode)
|
|
ZwClose (HdlIpxFile);
|
|
else
|
|
NtClose (HdlIpxFile);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((IPXBindOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)
|
|
ExAllocatePoolWithTag(NonPagedPool,
|
|
(ULONG)IoStatusBlock.Information,
|
|
FWD_POOL_TAG)) == NULL) {
|
|
|
|
ExFreePool(bip);
|
|
if (requestorMode==UserMode)
|
|
ZwClose (HdlIpxFile);
|
|
else
|
|
NtClose (HdlIpxFile);
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
|
|
("IpxFwd: Could not allocate output binding buffer!\n"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
if (requestorMode==UserMode)
|
|
status = ZwDeviceIoControlFile(
|
|
HdlIpxFile, // HANDLE to File
|
|
NULL, // HANDLE to Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&IoStatusBlock, // IO_STATUS_BLOCK
|
|
IOCTL_IPX_INTERNAL_BIND, // IoControlCode
|
|
bip, // Input Buffer
|
|
sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
|
|
IPXBindOutput, // Output Buffer
|
|
(ULONG)IoStatusBlock.Information); // Output Buffer Length
|
|
else
|
|
status = NtDeviceIoControlFile(
|
|
HdlIpxFile, // HANDLE to File
|
|
NULL, // HANDLE to Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&IoStatusBlock, // IO_STATUS_BLOCK
|
|
IOCTL_IPX_INTERNAL_BIND, // IoControlCode
|
|
bip, // Input Buffer
|
|
sizeof(IPX_INTERNAL_BIND_INPUT),// Input Buffer Length
|
|
IPXBindOutput, // Output Buffer
|
|
(ULONG)IoStatusBlock.Information); // Output Buffer Length
|
|
|
|
|
|
if (status == STATUS_PENDING) {
|
|
if (requestorMode==UserMode)
|
|
status = ZwWaitForSingleObject(
|
|
HdlIpxFile,
|
|
(BOOLEAN)FALSE,
|
|
NULL);
|
|
else
|
|
status = NtWaitForSingleObject(
|
|
HdlIpxFile,
|
|
(BOOLEAN)FALSE,
|
|
NULL);
|
|
if (NT_SUCCESS(status))
|
|
status = IoStatusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_ERROR,
|
|
("IpxFwd: Ioctl to the IPX driver failed with %lx\n", IoStatusBlock.Status));
|
|
|
|
ExFreePool(bip);
|
|
ExFreePool(IPXBindOutput);
|
|
IPXBindOutput = NULL;
|
|
if (requestorMode==UserMode)
|
|
ZwClose (HdlIpxFile);
|
|
else
|
|
NtClose (HdlIpxFile);
|
|
return status;
|
|
}
|
|
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
|
|
("IpxFwd: Succesfuly bound to the IPX driver\n"));
|
|
|
|
ExFreePool (bip);
|
|
ExFreePool (WstrIpxFileName);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
U n b i n d F r o m I p x D r i v e r
|
|
|
|
Routine Description:
|
|
Closes connection to IPX stack driver
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
UnbindFromIpxDriver (
|
|
KPROCESSOR_MODE requestorMode
|
|
) {
|
|
// Free binding output buffer and close driver handle
|
|
ASSERT (IPXBindOutput!=NULL);
|
|
ExFreePool (IPXBindOutput);
|
|
IPXBindOutput = NULL;
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_WARNING,
|
|
("IpxFwd: Closing IPX driver handle\n"));
|
|
if (requestorMode==UserMode)
|
|
ZwClose (HdlIpxFile);
|
|
else
|
|
NtClose (HdlIpxFile);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
F w F i n d R o u t e
|
|
|
|
Routine Description:
|
|
This routine is provided by the Kernel Forwarder to find the route
|
|
to a given node and network
|
|
Arguments:
|
|
Network - the destination network
|
|
Node - destination node
|
|
RouteEntry - filled in by the Forwarder if a route exists
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
STATUS_NETWORK_UNREACHABLE - if the findroute failed
|
|
*******************************************************************
|
|
--*/
|
|
NTSTATUS
|
|
IpxFwdFindRoute (
|
|
IN PUCHAR Network,
|
|
IN PUCHAR Node,
|
|
OUT PIPX_FIND_ROUTE_REQUEST RouteEntry
|
|
) {
|
|
PINTERFACE_CB ifCB;
|
|
ULONG net;
|
|
KIRQL oldIRQL;
|
|
NTSTATUS status = STATUS_NETWORK_UNREACHABLE;
|
|
PFWD_ROUTE fwRoute;
|
|
|
|
if (!EnterForwarder ())
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
net = GETULONG (Network);
|
|
|
|
ifCB = FindDestination (net, Node, &fwRoute);
|
|
if (ifCB!=NULL) {
|
|
if (IS_IF_ENABLED(ifCB)) {
|
|
KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
|
|
switch (ifCB->ICB_Stats.OperationalState) {
|
|
case FWD_OPER_STATE_UP:
|
|
IPX_NET_CPY (&RouteEntry->Network, Network);
|
|
if (fwRoute->FR_Network==ifCB->ICB_Network) {
|
|
if (Node!=NULL) {
|
|
IPX_NODE_CPY (RouteEntry->LocalTarget.MacAddress, Node);
|
|
}
|
|
else {
|
|
IPX_NODE_CPY (RouteEntry->LocalTarget.MacAddress,
|
|
BROADCAST_NODE);
|
|
}
|
|
}
|
|
else {
|
|
IPX_NODE_CPY (RouteEntry->LocalTarget.MacAddress,
|
|
fwRoute->FR_NextHopAddress);
|
|
}
|
|
if (ifCB!=InternalInterface) {
|
|
ADAPTER_CONTEXT_TO_LOCAL_TARGET (
|
|
ifCB->ICB_AdapterContext,
|
|
&RouteEntry->LocalTarget);
|
|
}
|
|
else {
|
|
CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (
|
|
VIRTUAL_NET_ADAPTER_CONTEXT,
|
|
&RouteEntry->LocalTarget);
|
|
}
|
|
|
|
//
|
|
// Fill in the hop count and tick count
|
|
//
|
|
RouteEntry->TickCount = fwRoute->FR_TickCount;
|
|
RouteEntry->HopCount = fwRoute->FR_HopCount;
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
case FWD_OPER_STATE_SLEEPING:
|
|
IPX_NODE_CPY (&RouteEntry->LocalTarget.MacAddress,
|
|
fwRoute->FR_NextHopAddress);
|
|
CONSTANT_ADAPTER_CONTEXT_TO_LOCAL_TARGET (DEMAND_DIAL_ADAPTER_CONTEXT,
|
|
&RouteEntry->LocalTarget);
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Fill in the hop count and tick count
|
|
//
|
|
RouteEntry->TickCount = fwRoute->FR_TickCount;
|
|
RouteEntry->HopCount = fwRoute->FR_HopCount;
|
|
|
|
|
|
break;
|
|
case FWD_OPER_STATE_DOWN:
|
|
status = STATUS_NETWORK_UNREACHABLE;
|
|
break;
|
|
default:
|
|
ASSERTMSG ("Inavalid operational state", FALSE);
|
|
}
|
|
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
|
|
#if DBG
|
|
if (Node!=NULL) {
|
|
if (NT_SUCCESS (status)) {
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
|
|
("IpxFwd: Found route for IPX driver:"
|
|
" %08lX:%02X%02X%02X%02X%02X%02X"
|
|
" -> %ld(%ld):%02X%02X%02X%02X%02X%02X\n",
|
|
net, Node[0],Node[1],Node[2],Node[3],Node[4],Node[5],
|
|
ifCB->ICB_Index, RouteEntry->LocalTarget.NicId,
|
|
RouteEntry->LocalTarget.MacAddress[0],
|
|
RouteEntry->LocalTarget.MacAddress[1],
|
|
RouteEntry->LocalTarget.MacAddress[2],
|
|
RouteEntry->LocalTarget.MacAddress[3],
|
|
RouteEntry->LocalTarget.MacAddress[4],
|
|
RouteEntry->LocalTarget.MacAddress[5]));
|
|
}
|
|
else {
|
|
IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
|
|
("IpxFwd: Network unreachable for:"
|
|
" %08lX:%02X%02X%02X%02X%02X%02X -> %ld.\n",
|
|
net, Node[0],Node[1],Node[2],Node[3],Node[4],Node[5],
|
|
ifCB->ICB_Index));
|
|
}
|
|
}
|
|
else {
|
|
if (NT_SUCCESS (status)) {
|
|
IpxFwdDbgPrint (DBG_IPXBIND, DBG_INFORMATION,
|
|
("IpxFwd: Found route for IPX driver:"
|
|
" %08lX"
|
|
" -> %ld(%ld):%02X%02X%02X%02X%02X%02X\n",
|
|
net, ifCB->ICB_Index, RouteEntry->LocalTarget.NicId,
|
|
RouteEntry->LocalTarget.MacAddress[0],
|
|
RouteEntry->LocalTarget.MacAddress[1],
|
|
RouteEntry->LocalTarget.MacAddress[2],
|
|
RouteEntry->LocalTarget.MacAddress[3],
|
|
RouteEntry->LocalTarget.MacAddress[4],
|
|
RouteEntry->LocalTarget.MacAddress[5]));
|
|
}
|
|
else {
|
|
IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
|
|
("IpxFwd: Network unreachable for:"
|
|
" %08lX -> %ld.\n", net));
|
|
}
|
|
}
|
|
#endif
|
|
ReleaseInterfaceReference (ifCB);
|
|
ReleaseRouteReference (fwRoute);
|
|
|
|
}
|
|
}
|
|
else {
|
|
#if DBG
|
|
if (Node!=NULL) {
|
|
IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
|
|
("IpxFwd: No route for:"
|
|
" %08lX:%02X%02X%02X%02X%02X%02X.\n",
|
|
net, Node[0],Node[1],Node[2],Node[3],Node[4],Node[5]));
|
|
}
|
|
else {
|
|
IpxFwdDbgPrint (DBG_IPXROUTE, DBG_WARNING,
|
|
("IpxFwd: No route for: %08lX.\n", net));
|
|
}
|
|
#endif
|
|
status = STATUS_NETWORK_UNREACHABLE;
|
|
}
|
|
LeaveForwarder ();
|
|
return status;
|
|
}
|
|
|
|
|
|
|