windows-nt/Source/XPSP1/NT/net/nwlink/fwd/ipxbind.c

485 lines
13 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}