windows-nt/Source/XPSP1/NT/net/nwlink/ipx/internal.c

1455 lines
40 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
internal.c
Abstract:
This module contains the code to handle the internal
binding of the upper drivers to IPX.
Author:
Adam Barr (adamba) 2-September-1993
Environment:
Kernel mode
Revision History:
Sanjay Anand (SanjayAn) 25-August-1995
Bug Fixes - tagged [SA]
--*/
#include "precomp.h"
#pragma hdrstop
NTSTATUS
IpxInternalBind(
IN PDEVICE Device,
IN PIRP Irp
)
/*++
Routine Description:
This routine is used when one of the upper drivers submits
a request to bind to IPX.
Arguments:
DeviceObject - Pointer to the device object for this driver.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value is the status of the operation.
--*/
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
PIPX_INTERNAL_BIND_INPUT BindInput;
PIPX_INTERNAL_BIND_OUTPUT BindOutput;
PIPX_INTERNAL_BIND_RIP_OUTPUT BindRipOutput;
CTELockHandle LockHandle;
PIPX_NIC_DATA NicData;
PBINDING Binding, LastRealBinding;
PADAPTER Adapter;
ULONG Identifier;
ULONG BindOutputSize;
BOOLEAN BroadcastEnable;
#ifdef SUNDOWN
// To avoid a warning when NicData->NicId = i;
// Assume that USHORT is enough to hold the number of bindings
USHORT i;
#else
UINT i;
#endif
#if DBG
PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
#endif
BOOLEAN fFwdBindAttempt = FALSE;
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
(sizeof(IPX_INTERNAL_BIND_INPUT) - sizeof(ULONG))) {
IPX_DEBUG (BIND, ("Bind received, bad input length %d/%d\n",
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
sizeof (IPX_INTERNAL_BIND_INPUT)));
return STATUS_INVALID_PARAMETER;
}
BindInput = (PIPX_INTERNAL_BIND_INPUT)(Irp->AssociatedIrp.SystemBuffer);
if (BindInput->Identifier >= UPPER_DRIVER_COUNT) {
IPX_DEBUG (BIND, ("Bind received, bad id %d\n", BindInput->Identifier));
return STATUS_INVALID_PARAMETER;
}
IPX_DEBUG (BIND, ("Bind received from id %d (%s)\n",
BindInput->Identifier,
IdStrings[BindInput->Identifier]));
//
// RIP gives us version == 1 whereas Forwarder gives us 2 (ISN_VERSION).
//
if (BindInput->Identifier == IDENTIFIER_RIP) {
if (BindInput->Version == ISN_VERSION) {
fFwdBindAttempt = TRUE;
} else {
CTEAssert(!Device->ForwarderBound);
DbgPrint("IPX:Check out who is requesting bind?.\n");
CTEAssert(FALSE);
if (BindInput->Version != 1) {
IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
BindInput->Version, 1));
return STATUS_INVALID_PARAMETER;
}
}
} else {
if (BindInput->Version != ISN_VERSION) {
IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
BindInput->Version, 1));
return STATUS_INVALID_PARAMETER;
}
}
if (BindInput->Identifier != IDENTIFIER_RIP) {
BindOutputSize = sizeof(IPX_INTERNAL_BIND_OUTPUT);
} else {
BindOutputSize = FIELD_OFFSET (IPX_INTERNAL_BIND_RIP_OUTPUT, NicInfoBuffer.NicData[0]) +
(MIN (Device->MaxBindings, Device->HighestExternalNicId) * sizeof(IPX_NIC_DATA));
}
Irp->IoStatus.Information = BindOutputSize;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
BindOutputSize) {
IPX_DEBUG (BIND, ("Bind: bad output length %d/%d\n",
IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
BindOutputSize));
//
// Fail this request with BUFFER_TOO_SMALL. Since the
// I/O system may not copy the status block back to
// the user's status block, do that here so that
// he gets IoStatus.Information.
//
try {
*Irp->UserIosb = Irp->IoStatus;
} except(EXCEPTION_EXECUTE_HANDLER) {
NOTHING;
}
return STATUS_BUFFER_TOO_SMALL;
}
//
// We have verified the length, make sure we are not
// already bound.
//
Identifier = BindInput->Identifier;
CTEGetLock (&Device->Lock, &LockHandle);
if (Device->UpperDriverBound[Identifier]) {
IPX_DEBUG (BIND, ("Bind: already bound\n"));
CTEFreeLock (&Device->Lock, LockHandle);
return STATUS_REQUEST_NOT_ACCEPTED;
}
{
LARGE_INTEGER ControlChId;
CCID_FROM_REQUEST(ControlChId, Irp);
IPX_DEBUG (BIND, ("Control ChId: (%d, %d) for Id: %d\n", ControlChId.HighPart, ControlChId.LowPart, Identifier));
Device->UpperDriverControlChannel[Identifier].QuadPart = ControlChId.QuadPart;
}
RtlCopyMemory(
&Device->UpperDrivers[Identifier],
BindInput,
sizeof (IPX_INTERNAL_BIND_INPUT)
);
BroadcastEnable = BindInput->BroadcastEnable;
//
// Now construct the output buffer.
//
if (Identifier != IDENTIFIER_RIP) {
BindOutput = (PIPX_INTERNAL_BIND_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory(BindOutput, sizeof(IPX_INTERNAL_BIND_OUTPUT));
BindOutput->Version = 1;
//
// Tell netbios our first binding's net/node instead of the
// virtual one.
//
//
// Fill the fields in only if the adapters have already appeared
// Else, set NodeNumber to 0 so NB/SPX know of it.
//
if ((*(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4) != 0) ||
(*(UNALIGNED ULONG *)Device->SourceAddress.NodeAddress != 0)) {
IPX_DEBUG(BIND, ("Device already opened\n"));
CTEAssert(Device->ValidBindings);
if (Identifier == IDENTIFIER_SPX) {
//
// For SPX, inform directly.
//
IPX_FREE_LOCK(&Device->Lock, LockHandle);
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
ExInitializeWorkItem(
&Device->PnPIndicationsQueueItemSpx,
IpxPnPIsnIndicate,
UlongToPtr(Identifier));
IpxReferenceDevice(Device, DREF_PNP);
ExQueueWorkItem(&Device->PnPIndicationsQueueItemSpx, DelayedWorkQueue);
// DbgPrint("---------- 5. Queued with IpxPnPIsnIndicate ----------\n");
//IpxPnPIsnIndicate((PVOID)Identifier);
} else {
CTEAssert(FALSE);
IPX_FREE_LOCK(&Device->Lock, LockHandle);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
}
IPX_GET_LOCK(&Device->Lock, &LockHandle);
} else {
//
// For NB, queue a work item which will go thru' the adapters list and
// inform the upper drivers about each of them.
//
KeResetEvent(&Device->NbEvent);
ExInitializeWorkItem(
&Device->PnPIndicationsQueueItemNb,
IpxPnPIsnIndicate,
UlongToPtr(Identifier));
IpxReferenceDevice(Device, DREF_PNP);
ExQueueWorkItem(&Device->PnPIndicationsQueueItemNb, DelayedWorkQueue);
// DbgPrint("---------- 5 (2). Queued with IpxPnPIsnIndicate ----------\n");
}
} else {
// This should not happen as SourceAddress should set in DriverEntry
// to initial loopback address or virtual network address.
DbgPrint("IPX:IpxInternalBind:Device not open:IpxPnPIsnIndicate thread did not launch.\n");
*((UNALIGNED ULONG *)BindOutput->Node) = 0;
*((UNALIGNED USHORT *)(BindOutput->Node+4)) = 0;
RtlZeroMemory(&BindOutput->LineInfo, sizeof(BindOutput->LineInfo));
}
BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
BindOutput->IncludedHeaderOffset = MAC_HEADER_SIZE; // (USHORT)Device->IncludedHeaderOffset;
BindOutput->SendHandler = IpxSendFramePreFwd;
BindOutput->FindRouteHandler = IpxInternalFindRoute;
BindOutput->QueryHandler = IpxInternalQuery;
BindOutput->TransferDataHandler = IpxTransferData;
BindOutput->PnPCompleteHandler = IpxPnPCompletionHandler;
} else {
//
// Set this so we stop RIPping for our virtual network (if
// we have one).
//
Device->RipResponder = FALSE;
//
// See if he wants a single wan network number.
//
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(IPX_INTERNAL_BIND_INPUT)) ||
((BindInput->RipParameters & IPX_RIP_PARAM_GLOBAL_NETWORK) == 0)) {
Device->WanGlobalNetworkNumber = FALSE;
Device->SapNicCount = Device->HighestExternalNicId;
} else {
Device->WanGlobalNetworkNumber = TRUE;
}
BindRipOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory(BindRipOutput, sizeof(IPX_INTERNAL_BIND_RIP_OUTPUT));
BindRipOutput->Version = 1;
BindRipOutput->MaximumNicCount = MIN (Device->MaxBindings, Device->HighestExternalNicId) + 1;
BindRipOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
BindRipOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
BindRipOutput->SendHandler = IpxSendFrame;
if (!fFwdBindAttempt) {
BindRipOutput->SegmentCount = Device->SegmentCount;
BindRipOutput->SegmentLocks = Device->SegmentLocks;
BindRipOutput->GetSegmentHandler = RipGetSegment;
BindRipOutput->GetRouteHandler = RipGetRoute;
BindRipOutput->AddRouteHandler = RipAddRoute;
BindRipOutput->DeleteRouteHandler = RipDeleteRoute;
BindRipOutput->GetFirstRouteHandler = RipGetFirstRoute;
BindRipOutput->GetNextRouteHandler = RipGetNextRoute;
//
// remove this...
//
BindRipOutput->IncrementWanInactivityHandler = IpxInternalIncrementWanInactivity;
BindRipOutput->QueryWanInactivityHandler = IpxInternalQueryWanInactivity;
} else {
//
// [FW] New routines provided for the Forwarder
//
BindRipOutput->OpenAdapterHandler = IpxOpenAdapter;
BindRipOutput->CloseAdapterHandler = IpxCloseAdapter;
BindRipOutput->InternalSendCompleteHandler = IpxInternalSendComplete;
}
BindRipOutput->TransferDataHandler = IpxTransferData;
BindRipOutput->NicInfoBuffer.NicCount = (USHORT)MIN (Device->MaxBindings, Device->HighestExternalNicId);
BindRipOutput->NicInfoBuffer.VirtualNicId = 0;
if (Device->VirtualNetwork || Device->MultiCardZeroVirtual) {
*(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = Device->SourceAddress.NetworkAddress;
} else if (Device->DedicatedRouter) {
*(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = 0x0;
}
NicData = &BindRipOutput->NicInfoBuffer.NicData[0];
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
{
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
for (i = FIRST_REAL_BINDING; i <= Index; i++) {
Binding = NIC_ID_TO_BINDING(Device, i);
//
// NULL bindings are WAN bindings, so we return the
// information from the last non-NULL binding found,
// which will be the first one on this adapter.
// Otherwise we save this as the last non-NULL one.
//
if (Binding == NULL) {
Binding = LastRealBinding;
} else {
LastRealBinding = Binding;
}
Adapter = Binding->Adapter;
NicData->NicId = i;
RtlCopyMemory (NicData->Node, Binding->LocalAddress.NodeAddress, 6);
*(UNALIGNED ULONG *)NicData->Network = Binding->LocalAddress.NetworkAddress;
NicData->LineInfo.LinkSpeed = Binding->MediumSpeed;
NicData->LineInfo.MaximumPacketSize =
Binding->MaxLookaheadData + sizeof(IPX_HEADER);
NicData->LineInfo.MaximumSendSize =
Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
NicData->LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
NicData->DeviceType = Adapter->MacInfo.RealMediumType;
NicData->EnableWanRouter = Adapter->EnableWanRouter;
++NicData;
}
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
}
//
// This is enabled by default these days!
//
/*
if (BroadcastEnable) {
IpxAddBroadcast (Device);
}
*/
Device->UpperDriverBound[Identifier] = TRUE;
Device->ForwarderBound = fFwdBindAttempt;
Device->AnyUpperDriverBound = TRUE;
CTEFreeLock (&Device->Lock, LockHandle);
return STATUS_SUCCESS;
} /* IpxInternalBind */
NTSTATUS
IpxInternalUnbind(
IN PDEVICE Device,
IN UINT Identifier
)
/*++
Routine Description:
This routine is used when one of the upper drivers submits
a request to unbind from IPX. It does this by closing the
control channel on which the bind ioctl was submitted.
Arguments:
DeviceObject - Pointer to the device object for this driver.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value is the status of the operation.
--*/
{
CTELockHandle LockHandle;
#if DBG
PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
#endif
IPX_DEBUG (BIND, ("Unbind received from id %d (%s)\n",
Identifier,
IdStrings[Identifier]));
CTEGetLock (&Device->Lock, &LockHandle);
if (!Device->UpperDriverBound[Identifier]) {
CTEFreeLock (&Device->Lock, LockHandle);
IPX_DEBUG (BIND, ("No existing binding\n"));
return STATUS_SUCCESS;
}
//
// [FW] If RIP is unbinding, restart the long timer
// Also, set the RipResponder flag if virutal net configured
//
// Deref all bindings that RIP did not close
//
if (Identifier == IDENTIFIER_RIP &&
Device->ForwarderBound) {
UINT i;
Device->ForwarderBound = FALSE;
//
// [FW] Walk the binding list, to deref all bindings not closed by
// the forwarder before it unbound from us.
//
{
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
for (i = FIRST_REAL_BINDING; i <= Index; i++) {
PBINDING Binding = NIC_ID_TO_BINDING(Device, i);
//
// We need to ensure that they will all be indicated when
// the Router starts up again.
//
if (Binding) {
Binding->fInfoIndicated = FALSE;
}
if (Binding && (Binding->FwdAdapterContext != 0)) {
IpxDereferenceBinding(Binding, BREF_FWDOPEN);
}
}
}
if (Device->VirtualNetwork) {
Device->RipResponder = TRUE;
}
//
// Start the timer which updates the RIP database
// periodically.
//
IpxReferenceDevice (Device, DREF_LONG_TIMER);
CTEStartTimer(
&Device->RipLongTimer,
10000,
RipLongTimeout,
(PVOID)Device);
}
Device->UpperDriverBound[Identifier] = FALSE;
Device->AnyUpperDriverBound = (BOOLEAN)
(Device->UpperDriverBound[IDENTIFIER_RIP] ||
Device->UpperDriverBound[IDENTIFIER_SPX] ||
Device->UpperDriverBound[IDENTIFIER_NB]);
//
// Lets do it in UnBindadapter anyway - later! [ShreeM]
//
/*
if (Device->UpperDrivers[Identifier].BroadcastEnable) {
IpxRemoveBroadcast (Device);
}
*/
if (Device->ValidBindings > 0) {
//
// If SPX went away, reset the IsnIndicate flag in the first binding
//
if (Identifier == IDENTIFIER_SPX) {
CTEAssert(NIC_ID_TO_BINDING(Device, 1));
if (NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = FALSE;
IPX_DEBUG(PNP, ("SPX unbound: IsnInformed turned off\n"));
}
}
//
// If NB went away, reset all the Binding's flags
//
if (Identifier == IDENTIFIER_NB) {
PBINDING Binding;
UINT i;
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
// DbgBreakPoint();
for (i = LOOPBACK_NIC_ID; i < Index; i++) {
Binding = NIC_ID_TO_BINDING(Device, i);
if (Binding && Binding->IsnInformed[Identifier]) {
Binding->IsnInformed[Identifier] = FALSE;
IPX_DEBUG(PNP, ("NB unbound: IsnInformed off for NicId: %lx\n", i));
}
}
}
}
//
// Lets NULL out the drivers
//
RtlZeroMemory(
&Device->UpperDrivers[Identifier],
sizeof (IPX_INTERNAL_BIND_INPUT)
);
CTEFreeLock (&Device->Lock, LockHandle);
return STATUS_SUCCESS;
} /* IpxInternalUnbind */
VOID
IpxInternalFindRoute (
IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
)
/*++
Routine Description:
This routine is the entry point for upper drivers to submit
requests to find a remote network, which is contained in
FindRouteRequest->Network. FindRouteRequest->Identifier must
contain the identifier of the upper driver.
This request is always asynchronous and is completed by
a call to the FindRouteComplete handler of the upper driver.
NOTE: As a currently unspecified extension to this call,
we returns the tick and hop counts as two USHORTs in the
PVOID Reserved2 structure of the request.
Arguments:
FindRouteRequest - Describes the request and contains
storage for IPX to use while processing it.
Return Value:
None.
--*/
{
PDEVICE Device = IpxDevice;
ULONG Segment;
TDI_ADDRESS_IPX TempAddress;
PBINDING Binding, MasterBinding;
NTSTATUS Status;
IPX_DEFINE_SYNC_CONTEXT (SyncContext)
IPX_DEFINE_LOCK_HANDLE (LockHandle)
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
//
// [FW] Call the Forwarder's FindRoute if installed
//
if (Device->ForwarderBound) {
// IPX_ROUTE_ENTRY routeEntry;
Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) (
FindRouteRequest->Network,
FindRouteRequest->Node,
FindRouteRequest);
if (Status != STATUS_SUCCESS) {
IPX_DEBUG (RIP, ("RouteHandler returned: %lx\n", Status));
} else {
#if DBG
//
// If a demand-dial NIC was returned, we should have a WAN adapter. In PnP we can check this
// by making sure that Device->HighestLanNicId < Device->HighestExternalNicId.
//
if (FindRouteRequest->LocalTarget.NicId == DEMAND_DIAL_ADAPTER_CONTEXT) {
CTEAssert(Device->HighestLanNicId < Device->HighestExternalNicId);
}
#endif
IPX_DEBUG(RIP, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx",
FindRouteRequest->LocalTarget.MacAddress[0],
FindRouteRequest->LocalTarget.MacAddress[1],
FindRouteRequest->LocalTarget.MacAddress[2],
FindRouteRequest->LocalTarget.MacAddress[3],
FindRouteRequest->LocalTarget.MacAddress[4],
FindRouteRequest->LocalTarget.MacAddress[5],
Status));
}
} else {
//
// First see if we have a route to this network in our
// table.
//
TempAddress.NetworkAddress = *(UNALIGNED ULONG *)(FindRouteRequest->Network);
//
// [SA] Bug #15094 Copy over the Node address so it can be used in WAN cases
//
// RtlZeroMemory (TempAddress.NodeAddress, 6);
*((UNALIGNED ULONG *)TempAddress.NodeAddress) = *((UNALIGNED ULONG *)FindRouteRequest->Node);
*((UNALIGNED USHORT *)(TempAddress.NodeAddress+4)) = *((UNALIGNED USHORT *)(FindRouteRequest->Node+4));
Segment = RipGetSegment(FindRouteRequest->Network);
//
// Since we maintain the order of locks as Bind > Device > RIP table
// Get the lock up-front.
//
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
IPX_BEGIN_SYNC (&SyncContext);
IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
//
// This call will return STATUS_PENDING if we need to
// RIP for the packet.
//
CTEAssert ((sizeof(USHORT)*2) <= sizeof(PVOID));
Status = RipGetLocalTarget(
Segment,
&TempAddress,
FindRouteRequest->Type,
&FindRouteRequest->LocalTarget,
(PUSHORT)&FindRouteRequest->Reserved2);
if (Status == STATUS_PENDING) {
//
// A RIP request went out on the network; we queue
// this find route request for completion when the
// RIP response arrives.
//
CTEAssert (FindRouteRequest->Type != IPX_FIND_ROUTE_NO_RIP); // should never pend
InsertTailList(
&Device->Segments[Segment].FindWaitingForRoute,
&FindRouteRequest->Linkage);
}
IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
IPX_END_SYNC (&SyncContext);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
}
if (Status != STATUS_PENDING) {
if (Status == STATUS_SUCCESS && FindRouteRequest->LocalTarget.NicId) {
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_HANDLE_TO_BINDING(Device, &FindRouteRequest->LocalTarget.NicHandle);
if (Binding == NULL) {
Status = STATUS_NETWORK_UNREACHABLE;
} else {
if (Binding->BindingSetMember) {
//
// It's a binding set member, we round-robin the
// responses across all the cards to distribute
// the traffic.
//
MasterBinding = Binding->MasterBinding;
Binding = MasterBinding->CurrentSendBinding;
MasterBinding->CurrentSendBinding = Binding->NextBinding;
FILL_LOCAL_TARGET(&FindRouteRequest->LocalTarget, Binding->NicId);
}
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
}
(*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
FindRouteRequest,
(BOOLEAN)((Status == STATUS_SUCCESS) ? TRUE : FALSE));
}
} /* IpxInternalFindRoute */
NTSTATUS
IpxInternalQuery(
IN ULONG InternalQueryType,
IN PNIC_HANDLE NicHandle OPTIONAL,
IN OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG BufferLengthNeeded OPTIONAL
)
/*++
Routine Description:
This routine is the entry point for upper drivers to query
information from us.
Arguments:
InternalQueryType - Identifies the type of the query.
NicId - The ID to query, if needed
Buffer - Input or output buffer for the query.
BufferLength - The length of the buffer.
BufferLengthNeeded - If the buffer is too short, this returns
the length needed.
Return Value:
None.
--*/
{
PBINDING Binding;
BOOLEAN BindingNeeded;
ULONG LengthNeeded;
PIPX_LINE_INFO LineInfo;
PUSHORT MaximumNicId;
PULONG ReceiveBufferSpace;
TDI_ADDRESS_IPX UNALIGNED * IpxAddress;
IPX_SOURCE_ROUTING_INFO UNALIGNED * SourceRoutingInfo;
ULONG SourceRoutingLength;
UINT MaxUserData;
PDEVICE Device = IpxDevice;
USHORT NicId;
PNDIS_MEDIUM Medium;
PVOID *PPDO;
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
//
// First verify the parameters.
//
switch (InternalQueryType) {
case IPX_QUERY_LINE_INFO:
BindingNeeded = TRUE;
LengthNeeded = sizeof(IPX_LINE_INFO);
break;
case IPX_QUERY_MAXIMUM_NIC_ID:
case IPX_QUERY_MAX_TYPE_20_NIC_ID:
BindingNeeded = FALSE;
LengthNeeded = sizeof(USHORT);
break;
case IPX_QUERY_IS_ADDRESS_LOCAL:
BindingNeeded = FALSE; // for now we don't need it
LengthNeeded = sizeof(TDI_ADDRESS_IPX);
break;
case IPX_QUERY_RECEIVE_BUFFER_SPACE:
BindingNeeded = TRUE;
LengthNeeded = sizeof(ULONG);
break;
case IPX_QUERY_IPX_ADDRESS:
if (NicHandle != NULL) {
NicId = NicHandle->NicId;
} else {
return STATUS_INVALID_PARAMETER;
}
if ((NicId == 0) &&
(BufferLength >= sizeof(TDI_ADDRESS_IPX))) {
RtlCopyMemory (Buffer, &Device->SourceAddress, sizeof(TDI_ADDRESS_IPX));
return STATUS_SUCCESS;
}
BindingNeeded = TRUE;
LengthNeeded = sizeof(TDI_ADDRESS_IPX);
break;
case IPX_QUERY_SOURCE_ROUTING:
BindingNeeded = TRUE;
LengthNeeded = sizeof(IPX_SOURCE_ROUTING_INFO);
break;
//
// These are moved down from NB/SPX to IPX. LengthNeeded is set to 0
// so we dont return BUFFER_TOO_SMALL here; we assume here that
// Bufferlength is also 0.
// Buffer is actually the IRP here.
//
case IPX_QUERY_DATA_LINK_ADDRESS:
case IPX_QUERY_NETWORK_ADDRESS:
BindingNeeded = FALSE;
LengthNeeded = 0;
break;
//
// NBIPX wants to know if it is a WAN link
//
case IPX_QUERY_MEDIA_TYPE:
BindingNeeded = TRUE;
LengthNeeded = sizeof(NDIS_MEDIUM);
break;
case IPX_QUERY_DEVICE_RELATION:
BindingNeeded = TRUE;
LengthNeeded = sizeof(void *);
break;
default:
return STATUS_NOT_SUPPORTED;
}
if (LengthNeeded > BufferLength) {
if (BufferLengthNeeded != NULL) {
*BufferLengthNeeded = LengthNeeded;
}
return STATUS_BUFFER_TOO_SMALL;
}
if (BindingNeeded) {
if (NicHandle != NULL) {
NicId = NicHandle->NicId;
} else {
return STATUS_INVALID_PARAMETER;
}
if (NicId == 0) {
NicId = 1;
}
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
if ((Binding == NULL) ||
(!Binding->LineUp)) {
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
return STATUS_INVALID_PARAMETER;
}
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
}
//
// Now return the data.
//
switch (InternalQueryType) {
case IPX_QUERY_LINE_INFO:
LineInfo = (PIPX_LINE_INFO)Buffer;
LineInfo->LinkSpeed = Binding->MediumSpeed;
LineInfo->MaximumPacketSize = Binding->MaxLookaheadData + sizeof(IPX_HEADER);
LineInfo->MaximumSendSize = Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
LineInfo->MacOptions = Binding->Adapter->MacInfo.MacOptions;
break;
case IPX_QUERY_MAXIMUM_NIC_ID:
MaximumNicId = (PUSHORT)Buffer;
*MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestExternalNicId);
break;
case IPX_QUERY_IS_ADDRESS_LOCAL:
IpxAddress = (TDI_ADDRESS_IPX UNALIGNED *)Buffer;
if (!IpxIsAddressLocal(IpxAddress)) {
return STATUS_NO_SUCH_DEVICE;
}
break;
case IPX_QUERY_RECEIVE_BUFFER_SPACE:
ReceiveBufferSpace = (PULONG)Buffer;
*ReceiveBufferSpace = Binding->Adapter->ReceiveBufferSpace;
break;
case IPX_QUERY_IPX_ADDRESS:
RtlCopyMemory (Buffer, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
break;
case IPX_QUERY_SOURCE_ROUTING:
SourceRoutingInfo = (IPX_SOURCE_ROUTING_INFO UNALIGNED *)Buffer;
MacLookupSourceRouting(
SourceRoutingInfo->Identifier,
Binding,
SourceRoutingInfo->RemoteAddress,
SourceRoutingInfo->SourceRouting,
&SourceRoutingLength);
//
// Reverse the direction of the source routing since it
// is returned in the outgoing order.
//
if (SourceRoutingLength > 0) {
SourceRoutingInfo->SourceRouting[0] &= 0x7f;
}
SourceRoutingInfo->SourceRoutingLength = (USHORT)SourceRoutingLength;
MacReturnMaxDataSize(
&Binding->Adapter->MacInfo,
SourceRoutingInfo->SourceRouting,
SourceRoutingLength,
Binding->MaxSendPacketSize,
&MaxUserData);
//
// MaxUserData does not include the MAC header but does include
// any extra 802.2 etc. headers, so we adjust for that to get the
// size starting at the IPX header.
//
SourceRoutingInfo->MaximumSendSize =
MaxUserData -
(Binding->DefHeaderSize - Binding->Adapter->MacInfo.MinHeaderLength);
break;
case IPX_QUERY_MAX_TYPE_20_NIC_ID:
MaximumNicId = (PUSHORT)Buffer;
*MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestType20NicId);
break;
case IPX_QUERY_DATA_LINK_ADDRESS:
case IPX_QUERY_NETWORK_ADDRESS:
//
// Call the TDI query equivalent here.
//
return IpxTdiQueryInformation(Device, (PREQUEST)Buffer);
case IPX_QUERY_MEDIA_TYPE:
Medium = (PNDIS_MEDIUM) Buffer;
*Medium = Binding->Adapter->MacInfo.MediumType;
IPX_DEBUG(CONFIG, ("The medium is %x\n", *Medium));
break;
case IPX_QUERY_DEVICE_RELATION:
PPDO = (PVOID *) Buffer;
*PPDO = Binding->Adapter->PNPContext;
IPX_DEBUG(CONFIG, ("The PDO is %p\n", *PPDO));
if (*PPDO == NULL) {
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
return STATUS_UNSUCCESSFUL;
}
break;
}
//
// If Binding was needed earlier, it was referenced, deref it now.
//
if (BindingNeeded) {
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
}
//
// If we haven't returned failure by now, succeed.
//
return STATUS_SUCCESS;
} /* IpxInternalQuery */
VOID
IpxInternalIncrementWanInactivity(
#ifdef _PNP_LATER
// RIP not converted yet...
//
IN NIC_HANDLE NicHandle
#else
IN USHORT NicId
#endif
)
/*++
Routine Description:
This routine is the entry point where rip calls us to increment
the inactivity counter on a wan binding. This is done every
minute.
Arguments:
NicId - The NIC ID of the wan binding.
Return Value:
None.
--*/
{
PBINDING Binding;
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
//
// Change to NIC_HANDLE_TO_BINDING later. Not done yet since RIP not changed to
// use NICHANDLE instead of NicId
//
Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
if ((Binding != NULL) &&
(Binding->Adapter->MacInfo.MediumAsync)) {
++Binding->WanInactivityCounter;
} else {
CTEAssert (FALSE);
}
IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
} /* IpxInternalIncrementWanInactivity */
ULONG
IpxInternalQueryWanInactivity(
#ifdef _PNP_LATER
IN NIC_HANDLE NicHandle
#else
IN USHORT NicId
#endif
)
/*++
Routine Description:
This routine is the entry point where rip calls us to query
the inactivity counter on a wan binding.
Arguments:
NicId - The NIC ID of the wan binding.
Return Value:
The inactivity counter for this binding.
--*/
{
PBINDING Binding;
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
// Binding = NIC_HANDLE_TO_BINDING(IpxDevice, &NicHandle);
Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
if ((Binding != NULL) &&
(Binding->Adapter->MacInfo.MediumAsync)) {
IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
return Binding->WanInactivityCounter;
} else {
IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
CTEAssert (FALSE);
return 0;
}
} /* IpxInternalQueryWanInactivity */
// Pre-condition: Loopback binding has been created.
//
// This routine is used to essure that we have indicated the loopback
// binding before indicate any other bindings.
//
// This routine returns true if we have informed NB about loopback bindings;
// false if we have not informed NB about loopback and if loopback binding
// does not exist.
BOOLEAN IpxHasInformedNbLoopback() {
BOOLEAN RetVal;
PBINDING Binding;
PDEVICE Device = IpxDevice;
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_ID_TO_BINDING(Device, LOOPBACK_NIC_ID);
if (Binding != NULL) {
RetVal = Binding->IsnInformed[IDENTIFIER_NB];
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
return RetVal;
} else {
DbgPrint("IPX:IpxHasInformedNbLoopback:Loopback binding is null.\n");
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
return FALSE;
}
}
// Pre-condition: Loopback binding has been created.
//
// This routine informs NB about IPX loopback binding.
//
// This should be the only place that we tell NB about loopback bindings.
// Loopback bindings must be the first device that we indicate to NB and the
// last device that we delete from NB. Thus, FirstOrLastDevice is only true
// when we inform NB about the loopback binding. It simply returns we already
// informed NB of loopback bindngs.
VOID IpxInformNbLoopback() {
PDEVICE Device = IpxDevice;
IPX_PNP_INFO IpxPnPInfo;
PBINDING Binding;
IPX_DEFINE_LOCK_HANDLE(LockHandle)
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
IPX_GET_LOCK(&Device->Lock, &LockHandle);
// IPX_GET_LOCK1 is no op.
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_ID_TO_BINDING(Device, LOOPBACK_NIC_ID);
if (!Binding) {
DbgPrint("IPX:IpxHasInformedNbLoopback:Loopback binding is null.\n");
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
IPX_FREE_LOCK(&Device->Lock, LockHandle);
return;
}
if (Binding->IsnInformed[IDENTIFIER_NB] != TRUE) {
Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
RtlZeroMemory(&IpxPnPInfo, sizeof(IpxPnPInfo));
IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
IpxPnPInfo.LineInfo.MaximumPacketSize =
Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
IpxPnPInfo.LineInfo.MaximumSendSize =
Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
IpxPnPInfo.FirstORLastDevice = TRUE;
IpxPnPInfo.NewReservedAddress = TRUE;
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, (USHORT) LOOPBACK_NIC_ID);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
IPX_FREE_LOCK(&Device->Lock, LockHandle);
//
// give the PnP indication
//
(*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
IPX_PNP_ADD_DEVICE,
&IpxPnPInfo);
IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to NB add: %lx\n", Binding));
} else {
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
IPX_FREE_LOCK(&Device->Lock, LockHandle);
}
}
VOID
IpxPnPIsnIndicate(
IN PVOID Param
)
/*++
Routine Description:
This routine goes through the list of adapters and informs (thru' PnP indications)
the ISN drivers bound to IPX about any new adapters that have appeared before the
bind took place.
This is queued as a work item in the InternalBind routine.
Arguments:
Param - the upper driver identifier.
Return Value:
None.
--*/
{
#ifdef SUNDOWN
ULONG_PTR Identifier = (ULONG_PTR)Param;
#else
ULONG Identifier = (ULONG)Param;
#endif
PDEVICE Device=IpxDevice;
ULONG i;
PBINDING Binding;
IPX_PNP_INFO IpxPnPInfo;
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
//
// Set up the LineInfo struct.
//
//
// Do we give Binding-specific information here?
//
IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
IpxPnPInfo.LineInfo.MaximumPacketSize =
Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
IpxPnPInfo.LineInfo.MaximumSendSize =
Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
switch(Identifier) {
case IDENTIFIER_NB:
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
//
// Inform about all the adapters
//
{
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
IpxInformNbLoopback();
KeSetEvent(
&Device->NbEvent,
0L,
FALSE);
for (i = LOOPBACK_NIC_ID + 1; i <= Index; i++) {
Binding = NIC_ID_TO_BINDING(Device, i);
if (!Binding) {
continue;
}
//
// We could have informed the upper driver from IpxBindAdapter
//
if (!Binding->IsnInformed[Identifier]) {
//
// Inform NB - the reserved network/node address is always that of the first
// binding
//
IpxPnPInfo.FirstORLastDevice = FALSE;
IpxPnPInfo.NewReservedAddress = FALSE;
IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, (USHORT)i);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
//
// give the PnP indication
//
ASSERT(IpxPnPInfo.FirstORLastDevice == FALSE);
ASSERT(IpxHasInformedNbLoopback());
(*Device->UpperDrivers[Identifier].PnPHandler) (
IPX_PNP_ADD_DEVICE,
&IpxPnPInfo);
Binding->IsnInformed[Identifier] = TRUE;
IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to NB add: %lx\n", Binding));
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
}
}
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
break;
case IDENTIFIER_SPX:
//
// For SPX this is called directly, with the IsnInformed flag appropriately set.
// This is done so that the IsnInformed flag cannot be changed under
// us by the BindAdapter routine.
//
#if 0
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
#endif
IpxPnPInfo.FirstORLastDevice = TRUE;
//
// Inform of the reserved address only
//
if (Device->VirtualNetwork) {
IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
} else {
IpxPnPInfo.NetworkAddress = NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NetworkAddress;
RtlCopyMemory(IpxPnPInfo.NodeAddress, NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NodeAddress, 6);
NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
}
IpxPnPInfo.NewReservedAddress = TRUE;
// IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
(*Device->UpperDrivers[Identifier].PnPHandler) (
IPX_PNP_ADD_DEVICE,
&IpxPnPInfo);
IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to SPX add: %lx\n", NIC_ID_TO_BINDING(Device, 1)));
#if 0
} else {
CTEAssert(FALSE);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
}
#endif
}
// DbgPrint("---------- 5. Done with IpxPnPIsnIndicate ----------\n");
IpxDereferenceDevice(Device, DREF_PNP);
}