Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

4447 lines
120 KiB

/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
driver.c
Abstract:
This module contains the DriverEntry and other initialization
code for the IPX module of the ISN transport.
Author:
Adam Barr (adamba) 2-September-1993
Environment:
Kernel mode
Revision History:
Sanjay Anand (SanjayAn) - 22-Sept-1995
BackFill optimization changes added under #if BACK_FILL
Sanjay Anand (SanjayAn) 18-Sept-1995
Changes to support Plug and Play (in _PNP_POWER)
--*/
#include "precomp.h"
#pragma hdrstop
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
PDEVICE IpxDevice = NULL;
PIPX_PADDING_BUFFER IpxPaddingBuffer = NULL;
#if DBG
UCHAR IpxTempDebugBuffer[150];
ULONG IpxDebug = 0x0;
ULONG IpxMemoryDebug = 0xffffffd3;
UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
PUCHAR IpxDebugMemoryLoc = IpxDebugMemory[0];
PUCHAR IpxDebugMemoryEnd = IpxDebugMemory[IPX_MEMORY_LOG_SIZE];
VOID
IpxDebugMemoryLog(
IN PUCHAR FormatString,
...
)
{
INT ArgLen;
va_list ArgumentPointer;
va_start(ArgumentPointer, FormatString);
//
// To avoid any overflows, copy this in a temp buffer first.
RtlZeroMemory (IpxTempDebugBuffer, 150);
ArgLen = vsprintf(IpxTempDebugBuffer, FormatString, ArgumentPointer);
va_end(ArgumentPointer);
if ( ArgLen > 64 ) {
CTEAssert( FALSE );
} else {
RtlZeroMemory (IpxDebugMemoryLoc, 64);
RtlCopyMemory( IpxDebugMemoryLoc, IpxTempDebugBuffer, ArgLen );
IpxDebugMemoryLoc += 64;
if (IpxDebugMemoryLoc >= IpxDebugMemoryEnd) {
IpxDebugMemoryLoc = IpxDebugMemory[0];
}
}
}
DEFINE_LOCK_STRUCTURE(IpxMemoryInterlock);
MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
DEFINE_LOCK_STRUCTURE(IpxGlobalInterlock);
#endif
#if DBG
//
// Use for debug printouts
//
PUCHAR FrameTypeNames[5] = { "Ethernet II", "802.3", "802.2", "SNAP", "Arcnet" };
#define OutputFrameType(_Binding) \
(((_Binding)->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) ? \
FrameTypeNames[4] : \
FrameTypeNames[(_Binding)->FrameType])
#endif
#ifdef IPX_PACKET_LOG
ULONG IpxPacketLogDebug = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_SEND_OTHER;
USHORT IpxPacketLogSocket = 0;
DEFINE_LOCK_STRUCTURE(IpxPacketLogLock);
IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc = IpxPacketLog;
PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd = &IpxPacketLog[IPX_PACKET_LOG_LENGTH];
VOID
IpxLogPacket(
IN BOOLEAN Send,
IN PUCHAR DestMac,
IN PUCHAR SrcMac,
IN USHORT Length,
IN PVOID IpxHeader,
IN PVOID Data
)
{
CTELockHandle LockHandle;
PIPX_PACKET_LOG_ENTRY PacketLog;
LARGE_INTEGER TickCount;
ULONG DataLength;
CTEGetLock (&IpxPacketLogLock, &LockHandle);
PacketLog = IpxPacketLogLoc;
++IpxPacketLogLoc;
if (IpxPacketLogLoc >= IpxPacketLogEnd) {
IpxPacketLogLoc = IpxPacketLog;
}
*(UNALIGNED ULONG *)IpxPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
CTEFreeLock (&IpxPacketLogLock, LockHandle);
RtlZeroMemory (PacketLog, sizeof(IPX_PACKET_LOG_ENTRY));
PacketLog->SendReceive = Send ? '>' : '<';
KeQueryTickCount(&TickCount);
_itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
PacketLog->Length[0] = Length / 256;
PacketLog->Length[1] = Length % 256;
if (Length < sizeof(IPX_HEADER)) {
RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, Length);
} else {
RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, sizeof(IPX_HEADER));
}
DataLength = Length - sizeof(IPX_HEADER);
if (DataLength < 14) {
RtlCopyMemory(PacketLog->Data, Data, DataLength);
} else {
RtlCopyMemory(PacketLog->Data, Data, 14);
}
} /* IpxLogPacket */
#endif // IPX_PACKET_LOG
//
// Forward declaration of various routines used in this module.
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
//
// This is now shared with other modules
//
#ifndef _PNP_POWER
ULONG
IpxResolveAutoDetect(
IN PDEVICE Device,
IN ULONG ValidBindings,
IN PUNICODE_STRING RegistryPath
);
VOID
IpxResolveBindingSets(
IN PDEVICE Device,
IN ULONG ValidBindings
);
NTSTATUS
IpxBindToAdapter(
IN PDEVICE Device,
IN PBINDING_CONFIG ConfigAdapter,
IN ULONG FrameTypeIndex
);
NTSTATUS
IpxUnBindFromAdapter(
IN PBINDING Binding
);
#endif _PNP_POWER
VOID
IpxUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
IpxDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
IpxDispatchOpenClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
IpxDispatchInternal (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
//
// These routines can be called at any time in case of PnP.
//
#ifndef _PNP_POWER
#pragma alloc_text(INIT,IpxResolveAutoDetect)
#pragma alloc_text(INIT,IpxResolveBindingSets)
#pragma alloc_text(INIT,IpxBindToAdapter)
#endif
#endif
UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
//
// This prevents us from having a bss section.
//
ULONG _setjmpexused = 0;
ULONG IpxFailLoad = FALSE;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine performs initialization of the IPX ISN module.
It creates the device objects for the transport
provider and performs other driver initialization.
Arguments:
DriverObject - Pointer to driver object created by the system.
RegistryPath - The name of IPX's node in the registry.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
NTSTATUS status;
UINT SuccessfulOpens, ValidBindings;
#ifdef _PNP_POWER
static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("NWLNKIPX");
#else
static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("IPX Transport");
#endif
PDEVICE Device;
PBINDING Binding;
PADAPTER Adapter;
ULONG BindingCount, BindingIndex;
PBINDING * BindingArray;
PLIST_ENTRY p;
ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
ULONG LinkSpeed, MacOptions;
ULONG Temp;
UINT i;
BOOLEAN CountedWan;
PCONFIG Config = NULL;
PBINDING_CONFIG ConfigBinding;
#if 0
DbgPrint ("IPX: FailLoad at %lx\n", &IpxFailLoad);
if (IpxFailLoad) {
return STATUS_UNSUCCESSFUL;
}
#endif
//
// This ordering matters because we use it to quickly
// determine if packets are internally generated or not.
//
CTEAssert (IDENTIFIER_NB < IDENTIFIER_IPX);
CTEAssert (IDENTIFIER_SPX < IDENTIFIER_IPX);
CTEAssert (IDENTIFIER_RIP < IDENTIFIER_IPX);
CTEAssert (IDENTIFIER_RIP_INTERNAL > IDENTIFIER_IPX);
//
// We assume that this structure is not packet in between
// the fields.
//
CTEAssert (FIELD_OFFSET (TDI_ADDRESS_IPX, Socket) + sizeof(USHORT) == 12);
//
// Initialize the Common Transport Environment.
//
if (CTEInitialize() == 0) {
IPX_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_TRANSPORT_REGISTER_FAILED,
101,
STATUS_UNSUCCESSFUL,
NULL,
0,
NULL);
return STATUS_UNSUCCESSFUL;
}
#if DBG
CTEInitLock (&IpxGlobalInterlock);
CTEInitLock (&IpxMemoryInterlock);
for (i = 0; i < MEMORY_MAX; i++) {
IpxMemoryTag[i].Tag = i;
IpxMemoryTag[i].BytesAllocated = 0;
}
#endif
#ifdef IPX_PACKET_LOG
CTEInitLock (&IpxPacketLogLock);
#endif
#ifdef IPX_OWN_PACKETS
CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
#endif
IPX_DEBUG (DEVICE, ("IPX loaded\n"));
//
// This allocates the CONFIG structure and returns
// it in Config.
//
status = IpxGetConfiguration(DriverObject, RegistryPath, &Config);
if (!NT_SUCCESS (status)) {
//
// If it failed, it logged an error.
//
PANIC (" Failed to initialize transport, IPX initialization failed.\n");
return status;
}
#ifdef _PNP_POWER
//
// Initialize the TDI layer.
//
TdiInitialize();
#endif
//
// make ourselves known to the NDIS wrapper.
//
status = IpxRegisterProtocol ((PNDIS_STRING)&ProtocolName);
if (!NT_SUCCESS (status)) {
IpxFreeConfiguration(Config);
PANIC ("IpxInitialize: RegisterProtocol failed!\n");
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_TRANSPORT_REGISTER_FAILED,
607,
status,
NULL,
0,
NULL);
return status;
}
//
// Initialize the driver object with this driver's entry points.
//
DriverObject->MajorFunction [IRP_MJ_CREATE] = IpxDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_CLOSE] = IpxDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_CLEANUP] = IpxDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = IpxDispatchInternal;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = IpxDispatchDeviceControl;
DriverObject->DriverUnload = IpxUnload;
SuccessfulOpens = 0;
status = IpxCreateDevice(
DriverObject,
&Config->DeviceName,
Config->Parameters[CONFIG_RIP_TABLE_SIZE],
&Device);
if (!NT_SUCCESS (status)) {
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_IPX_CREATE_DEVICE,
801,
status,
NULL,
0,
NULL);
IpxFreeConfiguration(Config);
IpxDeregisterProtocol();
return status;
}
IpxDevice = Device;
//
// Save the relevant configuration parameters.
//
Device->DedicatedRouter = (BOOLEAN)(Config->Parameters[CONFIG_DEDICATED_ROUTER] != 0);
Device->InitDatagrams = Config->Parameters[CONFIG_INIT_DATAGRAMS];
Device->MaxDatagrams = Config->Parameters[CONFIG_MAX_DATAGRAMS];
Device->RipAgeTime = Config->Parameters[CONFIG_RIP_AGE_TIME];
Device->RipCount = Config->Parameters[CONFIG_RIP_COUNT];
Device->RipTimeout =
((Config->Parameters[CONFIG_RIP_TIMEOUT] * 500) + (RIP_GRANULARITY/2)) /
RIP_GRANULARITY;
Device->RipUsageTime = Config->Parameters[CONFIG_RIP_USAGE_TIME];
Device->SourceRouteUsageTime = Config->Parameters[CONFIG_ROUTE_USAGE_TIME];
Device->SocketUniqueness = Config->Parameters[CONFIG_SOCKET_UNIQUENESS];
Device->SocketStart = (USHORT)Config->Parameters[CONFIG_SOCKET_START];
Device->SocketEnd = (USHORT)Config->Parameters[CONFIG_SOCKET_END];
Device->MemoryLimit = Config->Parameters[CONFIG_MAX_MEMORY_USAGE];
Device->VerifySourceAddress = (BOOLEAN)(Config->Parameters[CONFIG_VERIFY_SOURCE_ADDRESS] != 0);
Device->InitReceivePackets = (Device->InitDatagrams + 1) / 2;
Device->InitReceiveBuffers = (Device->InitDatagrams + 1) / 2;
Device->MaxReceivePackets = 10; // BUGBUG: config this?
Device->MaxReceiveBuffers = 10;
InitializeListHead(&Device->NicNtfQueue);
InitializeListHead(&Device->NicNtfComplQueue);
#ifdef _PNP_POWER
Device->InitBindings = 5; // BUGBUG: config this?
//
// RAS max is 240 (?) + 10 max LAN
//
Device->MaxPoolBindings = 250; // BUGBUG: config this?
#endif
#ifdef SNMP
IPX_MIB_ENTRY(Device, SysConfigSockets) = (Device->SocketEnd - Device->SocketStart)
/ ((Device->SocketUniqueness > 1) ? Device->SocketUniqueness : 1);
;
#endif SNMP
//
// Have to reverse this.
//
#ifndef _PNP_POWER
//
// Look at this only when the first adapter appears.
//
Temp = Config->Parameters[CONFIG_VIRTUAL_NETWORK];
Device->VirtualNetworkNumber = REORDER_ULONG (Temp);
#endif
Device->VirtualNetworkOptional = (BOOLEAN)(Config->Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
Device->CurrentSocket = Device->SocketStart;
Device->EthernetPadToEven = (BOOLEAN)(Config->Parameters[CONFIG_ETHERNET_PAD] != 0);
Device->EthernetExtraPadding = (Config->Parameters[CONFIG_ETHERNET_LENGTH] & 0xfffffffe) + 1;
Device->SingleNetworkActive = (BOOLEAN)(Config->Parameters[CONFIG_SINGLE_NETWORK] != 0);
Device->DisableDialoutSap = (BOOLEAN)(Config->Parameters[CONFIG_DISABLE_DIALOUT_SAP] != 0);
Device->DisableDialinNetbios = (UCHAR)(Config->Parameters[CONFIG_DISABLE_DIALIN_NB]);
#ifdef _PNP_POWER
//
// Used later to access the registry.
//
Device->RegistryPathBuffer = Config->RegistryPathBuffer;
Device->RegistryPath.Length = RegistryPath->Length;
Device->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
Device->RegistryPath.Buffer = Device->RegistryPathBuffer;
#endif _PNP_POWER
//
// ActiveNetworkWan will start as FALSE, which is correct.
//
//
// Allocate our initial packet pool. We do not allocate
// receive and receive buffer pools until we need them,
// because in many cases we never do.
//
#if BACK_FILL
IpxAllocateBackFillPool (Device);
#endif
IpxAllocateSendPool (Device);
#ifdef _PNP_POWER
IpxAllocateBindingPool (Device);
#endif
//
// Allocate one 1-byte buffer for odd length packets.
//
IpxPaddingBuffer = IpxAllocatePaddingBuffer(Device);
if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_TRANSPORT_RESOURCE_POOL,
801,
STATUS_INSUFFICIENT_RESOURCES,
NULL,
0,
NULL);
IpxFreeConfiguration(Config);
IpxDeregisterProtocol();
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the loopback structures
//
IpxInitLoopback();
//
// All this will be done on appearance of adapters.
//
#ifndef _PNP_POWER
//
// Bind to all the configured adapters.
//
InitializeListHead (&Device->InitialBindingList);
p = Config->BindingList.Flink;
while (p != &Config->BindingList) {
ConfigBinding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
p = p->Flink;
for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
//
// If successful, this queues them on Device->InitialBindingList.
//
status = IpxBindToAdapter (Device, ConfigBinding, i);
//
// If this failed because the adapter could not be bound
// to, then don't try any more frame types on this adapter.
// For other failures we do try the other frame types.
//
if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
break;
}
if (status != STATUS_SUCCESS) {
continue;
}
if (ConfigBinding->AutoDetect[i]) {
Device->AutoDetect = TRUE;
}
++SuccessfulOpens;
}
}
IpxFreeConfiguration(Config);
if (SuccessfulOpens == 0) {
IpxDereferenceDevice (Device, DREF_CREATE);
} else {
IPX_DEFINE_SYNC_CONTEXT (SyncContext);
//
// Allocate the device binding array and transfer those
// on the list to it. First count up the bindings.
//
BindingCount = 0;
for (p = Device->InitialBindingList.Flink;
p != &Device->InitialBindingList;
p = p->Flink) {
Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
Adapter = Binding->Adapter;
if (Adapter->MacInfo.MediumAsync) {
Adapter->FirstWanNicId = (USHORT)(BindingCount+1);
Adapter->LastWanNicId = (USHORT)(BindingCount + Adapter->WanNicIdCount);
BindingCount += Adapter->WanNicIdCount;
} else {
++BindingCount;
}
}
BindingArray = (PBINDING *)IpxAllocateMemory ((BindingCount+1) * sizeof(BINDING), MEMORY_BINDING, "Binding array");
if (BindingArray == NULL) {
while (!IsListEmpty (&Device->InitialBindingList)) {
p = RemoveHeadList (&Device->InitialBindingList);
Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
IpxDestroyBinding (Binding);
}
IpxDereferenceDevice (Device, DREF_CREATE);
SuccessfulOpens = 0;
goto InitFailed;
}
RtlZeroMemory (BindingArray, (BindingCount+1) * sizeof(BINDING));
//
// Now walk the list transferring bindings to the array.
//
BindingIndex = 1;
for (p = Device->InitialBindingList.Flink;
p != &Device->InitialBindingList;
) {
Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
p = p->Flink; // we overwrite the linkage in here, so save it.
BindingArray[BindingIndex] = Binding;
Binding->NicId = (USHORT)BindingIndex;
if (Binding->ConfiguredNetworkNumber != 0) {
//
// If the configured network number is non-zero, then
// use it, unless we are unable to insert a rip table
// entry for it (duplicates are OK because they will
// become binding set members -- BUGBUG: What if the
// duplicate is a different media or frame type, then
// it won't get noted as a binding set).
//
status = RipInsertLocalNetwork(
Binding->ConfiguredNetworkNumber,
Binding->NicId,
Binding->Adapter->NdisBindingHandle,
(USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
if ((status == STATUS_SUCCESS) ||
(status == STATUS_DUPLICATE_NAME)) {
Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
}
}
//
// These are a union with the InitialLinkage fields.
//
Binding->NextBinding = NULL;
Binding->CurrentSendBinding = NULL;
Adapter = Binding->Adapter;
if (Adapter->MacInfo.MediumAsync) {
CTEAssert (Adapter->FirstWanNicId == BindingIndex);
BindingIndex += Adapter->WanNicIdCount;
} else {
++BindingIndex;
}
}
CTEAssert (BindingIndex == BindingCount+1);
Device->Bindings = BindingArray;
Device->BindingCount = BindingCount;
//
// Queue a request to discover our locally attached
// adapter addresses. This must succeed because we
// just allocated our send packet pool. We need
// to wait for this, either because we are
// auto-detecting or because we need to determine
// if there are multiple cards on the same network.
//
KeInitializeEvent(
&Device->AutoDetectEvent,
NotificationEvent,
FALSE
);
Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
//
// Make this 0; after we are done waiting, which means
// the packet has been completed, we set it to the
// correct value.
//
Device->IncludedHeaderOffset = 0;
IPX_BEGIN_SYNC (&SyncContext);
status = RipQueueRequest (0xffffffff, RIP_REQUEST);
IPX_END_SYNC (&SyncContext);
CTEAssert (status == STATUS_PENDING);
//
// This is set when this rip send completes.
//
IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
KeWaitForSingleObject(
&Device->AutoDetectEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL
);
Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
//
// Now that we are done receiving responses, insert the
// current network number for every auto-detect binding
// to the rip database.
//
for (i = 1; i <= Device->BindingCount; i++) {
Binding = Device->Bindings[i];
//
// Skip empty WAN slots or bindings that were configured
// for a certain network number, we inserted those above.
// If no network number was detected, also skip it.
//
if ((!Binding) ||
(Binding->ConfiguredNetworkNumber != 0) ||
(Binding->TentativeNetworkAddress == 0)) {
continue;
}
IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
REORDER_ULONG(Binding->TentativeNetworkAddress),
Binding,
Binding->MatchingResponses,
Binding->NonMatchingResponses));
//
// We don't care about the status.
//
status = RipInsertLocalNetwork(
Binding->TentativeNetworkAddress,
Binding->NicId,
Binding->Adapter->NdisBindingHandle,
(USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
if ((status != STATUS_SUCCESS) &&
(status != STATUS_DUPLICATE_NAME)) {
//
// We failed to insert, keep it at zero, hopefully
// we will be able to update later.
//
#if DBG
DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
Binding);
#endif
CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
} else {
Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
}
}
ValidBindings = Device->BindingCount;
if (Device->AutoDetect) {
ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, RegistryPath);
}
Device->ValidBindings = ValidBindings;
//
// Now see if any bindings are actually on the same
// network. This sets Device->HighestExternalNicId
// and Device->HighestType20NicId.
//
IpxResolveBindingSets (Device, ValidBindings);
//
// For multiple adapters, use the offset of the first...why not.
//
#if 0
Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
#endif
Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
//
// Success; see if there is a virtual network configured.
//
if (Device->VirtualNetworkNumber != 0) {
status = RipInsertLocalNetwork(
Device->VirtualNetworkNumber,
0, // NIC ID
Device->Bindings[1]->Adapter->NdisBindingHandle,
1);
if (status != STATUS_SUCCESS) {
//
// Log the appropriate error, then ignore the
// virtual network. If the error was
// INSUFFICIENT_RESOURCES, the RIP module
// will have already logged an error.
//
if (status == STATUS_DUPLICATE_NAME) {
IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
IpxWriteResourceErrorLog(
Device->DeviceObject,
EVENT_IPX_INTERNAL_NET_INVALID,
0,
REORDER_ULONG (Device->VirtualNetworkNumber));
}
Device->VirtualNetworkNumber = 0;
goto NoVirtualNetwork;
}
Device->VirtualNetwork = TRUE;
Device->MultiCardZeroVirtual = FALSE;
RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
//
// This will get set to FALSE if RIP binds.
//
Device->RipResponder = TRUE;
} else {
NoVirtualNetwork:
Device->VirtualNetwork = FALSE;
//
// See if we need to be set up for the fake
// virtual network.
//
if (ValidBindings > 1) {
CTEAssert (Device->VirtualNetworkOptional);
//
// In this case we return as our local node the
// address of the first card. We will also only
// direct SAP sends to that card.
//
Device->MultiCardZeroVirtual = TRUE;
} else {
Device->MultiCardZeroVirtual = FALSE;
}
RtlCopyMemory(&Device->SourceAddress, &Device->Bindings[1]->LocalAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
}
//
// Now get SapNicCount -- regular adapters are counted
// as one, but all the WAN lines together only count for one.
// We also calculate FirstLanNicId and FirstWanNicId here.
//
CountedWan = FALSE;
Device->SapNicCount = 0;
Device->FirstLanNicId = (USHORT)-1;
Device->FirstWanNicId = (USHORT)-1;
{
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
for (i = 1; i <= Index; i++) {
if (Device->Bindings[i]) {
if (Device->Bindings[i]->Adapter->MacInfo.MediumAsync) {
if (Device->FirstWanNicId == (USHORT)-1) {
Device->FirstWanNicId = i;
}
if (CountedWan) {
continue;
} else {
CountedWan = TRUE;
}
} else {
if (Device->FirstLanNicId == (USHORT)-1) {
Device->FirstLanNicId = i;
}
}
} else {
//
// NULL bindings are WANs and are not the first one,
// so don't count them.
//
CTEAssert (Device->FirstWanNicId != -1);
CTEAssert (CountedWan);
continue;
}
++Device->SapNicCount;
}
}
if (Device->FirstLanNicId == (USHORT)-1) {
Device->FirstLanNicId = 1;
}
if (Device->FirstWanNicId == (USHORT)-1) {
Device->FirstWanNicId = 1;
}
//
// Calculate some values based on all the bindings.
//
MaxLookahead = Device->Bindings[1]->MaxLookaheadData; // largest binding value
AnnouncedMaxDatagram = Device->Bindings[1]->AnnouncedMaxDatagramSize; // smallest binding value
RealMaxDatagram = Device->Bindings[1]->RealMaxDatagramSize; // smallest binding value
if (Device->Bindings[1]->LineUp) {
LinkSpeed = Device->Bindings[1]->MediumSpeed; // smallest binding value
} else {
LinkSpeed = 0xffffffff;
}
MacOptions = Device->Bindings[1]->Adapter->MacInfo.MacOptions; // AND of binding values
for (i = 2; i <= ValidBindings; i++) {
Binding = Device->Bindings[i];
if (!Binding) {
continue;
}
if (Binding->MaxLookaheadData > MaxLookahead) {
MaxLookahead = Binding->MaxLookaheadData;
}
if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
}
if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
RealMaxDatagram = Binding->RealMaxDatagramSize;
}
if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
LinkSpeed = Binding->MediumSpeed;
}
MacOptions &= Binding->Adapter->MacInfo.MacOptions;
}
Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
Device->RealMaxDatagramSize = RealMaxDatagram;
Device->Information.MaximumLookaheadData = MaxLookahead;
//
// If we couldn't find anything better, use the speed from
// the first binding.
//
if (LinkSpeed == 0xffffffff) {
Device->LinkSpeed = Device->Bindings[1]->MediumSpeed;
} else {
Device->LinkSpeed = LinkSpeed;
}
Device->MacOptions = MacOptions;
Device->State = DEVICE_STATE_OPEN;
Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
IPX_DEBUG (DEVICE, ("Network is %lx\n",
REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
//
// Start the timer which updates the RIP database
// periodically. For the first one we do a ten
// second timeout (hopefully this is enough time
// for RIP to start if it is going to).
//
IpxReferenceDevice (Device, DREF_LONG_TIMER);
CTEStartTimer(
&Device->RipLongTimer,
10000,
RipLongTimeout,
(PVOID)Device);
//
// We use this event when unloading to signal that we
// can proceed...initialize it here so we know it is
// ready to go when unload is called.
//
KeInitializeEvent(
&IpxDevice->UnloadEvent,
NotificationEvent,
FALSE
);
}
InitFailed:
if (SuccessfulOpens == 0) {
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_IPX_NO_ADAPTERS,
802,
STATUS_DEVICE_DOES_NOT_EXIST,
NULL,
0,
NULL);
return STATUS_DEVICE_DOES_NOT_EXIST;
} else {
return STATUS_SUCCESS;
}
#else // _PNP_POWER
{
PBIND_ARRAY_ELEM BindingArray;
PTA_ADDRESS TdiRegistrationAddress;
//
// Pre-allocate the binding array
// Later, we will allocate the LAN/WAN and SLAVE bindings separately
// [BUGBUGZZ] Read the array size from registry?
//
BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM),
MEMORY_BINDING,
"Binding array");
if (BindingArray == NULL) {
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_IPX_NO_ADAPTERS,
802,
STATUS_DEVICE_DOES_NOT_EXIST,
NULL,
0,
NULL);
IpxDereferenceDevice (Device, DREF_CREATE);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
Device->MaxBindings = MAX_BINDINGS - EXTRA_BINDINGS;
//
// Allocate the TA_ADDRESS structure - this will be used in all TdiRegisterNetAddress
// notifications.
//
TdiRegistrationAddress = (PTA_ADDRESS)IpxAllocateMemory (
(2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
MEMORY_ADDRESS,
"Tdi Address");
if (TdiRegistrationAddress == NULL) {
IpxWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_IPX_NO_ADAPTERS,
802,
STATUS_DEVICE_DOES_NOT_EXIST,
NULL,
0,
NULL);
IpxFreeMemory(BindingArray, sizeof(BindingArray), MEMORY_BINDING, "Binding Array");
IpxDereferenceDevice (Device, DREF_CREATE);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
RtlZeroMemory (BindingArray, MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM));
RtlZeroMemory (TdiRegistrationAddress, 2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX));
//
// We keep BindingArray[-1] as a placeholder for demand dial bindings.
// This NicId is returned by the Fwd when a FindRoute is done on a demand
// dial Nic. At the time of the InternalSend, the true Nic is returned.
// We create a placeholder here to avoid special checks in the critical send path.
//
// NOTE: we need to free this demand dial binding as well as ensure that the
// true binding array pointer is freed at Device Destroy time.
//
//
// Increment beyond the first pointer - we will refer to the just incremented
// one as Device->Bindings[-1].
//
BindingArray += EXTRA_BINDINGS;
Device->Bindings = BindingArray;
TdiRegistrationAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
TdiRegistrationAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
//
// Store the pointer in the Device.
//
Device->TdiRegistrationAddress = TdiRegistrationAddress;
//
// Device state is loaded, but not opened. It is opened when at least
// one adapter has appeared.
//
Device->State = DEVICE_STATE_LOADED;
Device->FirstLanNicId = Device->FirstWanNicId = (USHORT)1; // will be changed later
IpxFreeConfiguration(Config);
//
// We use this event when unloading to signal that we
// can proceed...initialize it here so we know it is
// ready to go when unload is called.
//
KeInitializeEvent(
&IpxDevice->UnloadEvent,
NotificationEvent,
FALSE
);
return STATUS_SUCCESS;
}
#endif // _PNP_POWER
} /* DriverEntry */
ULONG
IpxResolveAutoDetect(
IN PDEVICE Device,
IN ULONG ValidBindings,
#ifdef _PNP_POWER
IN CTELockHandle *LockHandle1,
#endif
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine is called for auto-detect bindings to
remove any bindings that were not successfully found.
It also updates "DefaultAutoDetectType" in the registry
if needed.
Arguments:
Device - The IPX device object.
ValidBindings - The total number of bindings present.
RegistryPath - The path to the ipx registry, used if we have
to write a value back.
Return Value:
The updated number of bindings.
--*/
{
PBINDING Binding, TmpBinding;
UINT i, j;
//
// Get rid of any auto-detect devices which we
// could not find nets for. We also remove any
// devices which are not the first ones
// auto-detected on a particular adapter.
//
for (i = 1; i <= ValidBindings; i++) {
#ifdef _PNP_POWER
Binding = NIC_ID_TO_BINDING(Device, i);
#else
Binding = Device->Bindings[i];
#endif
if (!Binding) {
continue;
}
//
// If this was auto-detected and was not the default,
// or it was the default, but nothing was detected for
// it *and* something else *was* detected (which means
// we will use that frame type when we get to it),
// we may need to remove this binding.
//
if (Binding->AutoDetect &&
(!Binding->DefaultAutoDetect ||
(Binding->DefaultAutoDetect &&
(Binding->LocalAddress.NetworkAddress == 0) &&
Binding->Adapter->AutoDetectResponse))) {
if ((Binding->LocalAddress.NetworkAddress == 0) ||
(Binding->Adapter->AutoDetectFound)) {
//
// Remove this binding.
//
if (Binding->LocalAddress.NetworkAddress == 0) {
IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) no net found\n",
i, Binding->FrameType));
} else {
IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) adapter already auto-detected\n",
i, Binding->FrameType));
}
CTEAssert (Binding->NicId == i);
CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
//
// Remove any routes through this NIC, and
// adjust any NIC ID's above this one in the
// database down by one.
//
RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
Binding->Adapter->Bindings[Binding->FrameType] = NULL;
for (j = i+1; j <= ValidBindings; j++) {
#ifndef _PNP_POWER
TmpBinding = Device->Bindings[j];
Device->Bindings[j-1] = TmpBinding;
#else
TmpBinding = NIC_ID_TO_BINDING(Device, j);
INSERT_BINDING(Device, j-1, TmpBinding);
#endif _PNP_POWER
if (TmpBinding) {
if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
(TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
--TmpBinding->Adapter->FirstWanNicId;
--TmpBinding->Adapter->LastWanNicId;
}
--TmpBinding->NicId;
}
}
#ifdef _PNP_POWER
INSERT_BINDING(Device, ValidBindings, NULL);
#else
Device->Bindings[ValidBindings] = NULL;
#endif
--Binding->Adapter->BindingCount;
--ValidBindings;
--i; // so we check the binding that was just moved.
//
// Wait 100 ms before freeing the binding,
// in case an indication is using it.
//
KeStallExecutionProcessor(100000);
IpxDestroyBinding (Binding);
} else {
IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detected OK\n",
i, Binding->FrameType));
#if DBG
DbgPrint ("IPX: Auto-detected non-default frame type %s, net %lx\n",
OutputFrameType(Binding),
REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
#endif
//
// Save it in the registry for the next boot.
//
#ifdef _PNP_POWER
//
// This cannot be done at DPC, so, drop the IRQL
//
IPX_FREE_LOCK1(&Device->BindAccessLock, *LockHandle1);
IpxWriteDefaultAutoDetectType(
RegistryPath,
Binding->Adapter,
Binding->FrameType);
IPX_GET_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
IpxWriteDefaultAutoDetectType(
RegistryPath,
Binding->Adapter,
Binding->FrameType);
#endif
Binding->Adapter->AutoDetectFound = TRUE;
}
} else {
if (Binding->AutoDetect) {
IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detect default\n",
i, Binding->FrameType));
#if DBG
if (Binding->LocalAddress.NetworkAddress != 0) {
DbgPrint ("IPX: Auto-detected default frame type %s, net %lx\n",
OutputFrameType(Binding),
REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
} else {
DbgPrint ("IPX: Using default auto-detect frame type %s\n",
OutputFrameType(Binding));
}
#endif
Binding->Adapter->AutoDetectFound = TRUE;
} else {
IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) not auto-detected\n",
i, Binding->FrameType));
}
}
}
for (i = 1; i <= ValidBindings; i++) {
#ifdef _PNP_POWER
if (Binding = NIC_ID_TO_BINDING(Device, i)) {
#else
if (Binding = Device->Bindings[i]) {
#endif
CTEAssert (Binding->NicId == i);
IPX_DEBUG (AUTO_DETECT, ("Binding %lx, type %d, auto %d\n",
Binding, Binding->FrameType, Binding->AutoDetect));
}
}
return ValidBindings;
} /* IpxResolveAutoDetect */
VOID
IpxResolveBindingSets(
IN PDEVICE Device,
IN ULONG ValidBindings
)
/*++
Routine Description:
This routine is called to determine if we have any
binding sets and rearrange the bindings the way we
like. The order is as follows:
- First comes the first binding to each LAN network
- Following that are all WAN bindings
- Following that are any duplicate bindings to LAN networks
(the others in the "binding set").
If "global wan net" is true we will advertise up to
and including the first wan binding as the highest nic
id; otherwise we advertise up to and including the last
wan binding. In all cases the duplicate bindings are
hidden.
Arguments:
Device - The IPX device object.
ValidBindings - The total number of bindings present.
Return Value:
None.
--*/
{
PBINDING Binding, MasterBinding, TmpBinding;
UINT i, j;
ULONG WanCount, DuplicateCount;
//
// First loop through and push all the wan bindings
// to the end.
//
#ifdef _PNP_POWER
WanCount = Device->HighestExternalNicId - Device->HighestLanNicId;
#else
WanCount = 0;
//
// For PnP, we dont do this as the bindings are in order
// at the time of insertion
//
for (i = 1; i <= (ValidBindings-WanCount); ) {
Binding = Device->Bindings[i];
if ((Binding == NULL) || Binding->Adapter->MacInfo.MediumAsync) {
//
// Put this binding at the end, and slide all the
// others down. If it is a NULL WAN binding then we
// don't have to do some of this.
//
#if DBG
//
// Any non-NULL bindings should be correct in this
// respect at any point.
//
if (Binding != NULL) {
CTEAssert (Binding->NicId == i);
}
#endif
//
// If the Binding is NULL we won't have anything in the
// database at this binding, but we still need to adjust
// any NIC ID's in the database which are above this.
//
RipAdjustForBindingChange ((USHORT)i, (USHORT)ValidBindings, IpxBindingMoved);
//
// Slide the bindings above this down.
//
for (j = i+1; j <= ValidBindings; j++) {
TmpBinding = Device->Bindings[j];
Device->Bindings[j-1] = TmpBinding;
if (TmpBinding) {
if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
(TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
--TmpBinding->Adapter->FirstWanNicId;
--TmpBinding->Adapter->LastWanNicId;
}
--TmpBinding->NicId;
}
}
//
// Put this binding at the end.
//
Device->Bindings[ValidBindings] = Binding;
if (Binding != NULL) {
if ((Binding->Adapter->MacInfo.MediumAsync) &&
(Binding->Adapter->FirstWanNicId == Binding->NicId)) {
Binding->Adapter->FirstWanNicId = (USHORT)ValidBindings;
Binding->Adapter->LastWanNicId += (USHORT)(ValidBindings - Binding->NicId);
}
Binding->NicId = (USHORT)ValidBindings;
}
++WanCount;
//
// Keep i the same, to check the new binding at
// this position.
//
} else {
i++;
}
}
#endif _PNP_POWER
//
// Now go through and find the LAN duplicates and
// create binding sets from them.
//
DuplicateCount = 0;
for (i = 1; i <= (ValidBindings-(WanCount+DuplicateCount)); ) {
#ifdef _PNP_POWER
Binding = NIC_ID_TO_BINDING(Device, i);
#else
Binding = Device->Bindings[i];
#endif
CTEAssert (Binding != NULL); // because we are only looking at LAN bindings
CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
if (Binding->LocalAddress.NetworkAddress == 0) {
i++;
continue;
}
//
// See if any previous bindings match the
// frame type, medium type, and number of
// this network (for the moment we match on
// frame type and medium type too so that we
// don't have to worry about different frame
// formats and header offsets within a set).
//
for (j = 1; j < i; j++) {
#ifdef _PNP_POWER
MasterBinding = NIC_ID_TO_BINDING(Device, j);
#else
MasterBinding = Device->Bindings[j];
#endif
if ((MasterBinding->LocalAddress.NetworkAddress == Binding->LocalAddress.NetworkAddress) &&
(MasterBinding->FrameType == Binding->FrameType) &&
(MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
break;
}
}
if (j == i) {
i++;
continue;
}
//
// We have a duplicate. First slide it down to the
// end. Note that we change any router entries that
// use our real NicId to use the real NicId of the
// master (there should be no entries in the rip
// database that have the NicId of a binding slave).
//
RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
for (j = i+1; j <= ValidBindings; j++) {
#ifdef _PNP_POWER
TmpBinding = NIC_ID_TO_BINDING(Device, j);
INSERT_BINDING(Device, j-1, TmpBinding);
#else
TmpBinding = Device->Bindings[j];
Device->Bindings[j-1] = TmpBinding;
#endif
if (TmpBinding) {
if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
(TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
--TmpBinding->Adapter->FirstWanNicId;
--TmpBinding->Adapter->LastWanNicId;
}
--TmpBinding->NicId;
}
}
#ifdef _PNP_POWER
INSERT_BINDING(Device, ValidBindings, Binding);
#else
Device->Bindings[ValidBindings] = Binding;
#endif
Binding->NicId = (USHORT)ValidBindings;
++DuplicateCount;
//
// Now make MasterBinding the head of a binding set.
//
if (MasterBinding->BindingSetMember) {
//
// Just insert ourselves in the chain.
//
#if DBG
DbgPrint ("IPX: %lx is also on network %lx\n",
Binding->Adapter->AdapterName,
REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
#endif
IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
CTEAssert (MasterBinding->CurrentSendBinding);
Binding->NextBinding = MasterBinding->NextBinding;
} else {
//
// Start the chain with the two bindings in it.
//
#if DBG
DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
#endif
IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
MasterBinding->BindingSetMember = TRUE;
MasterBinding->CurrentSendBinding = MasterBinding;
MasterBinding->MasterBinding = MasterBinding;
Binding->NextBinding = MasterBinding;
}
MasterBinding->NextBinding = Binding;
Binding->BindingSetMember = TRUE;
Binding->ReceiveBroadcast = FALSE;
Binding->CurrentSendBinding = NULL;
Binding->MasterBinding = MasterBinding;
//
// Since the master binding looks like all members of
// the binding set to people querying from above, we have
// to make it the worst-case of all the elements. Generally
// these will be equal since the frame type and media is
// the same.
//
if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
}
if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
}
if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
}
if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
MasterBinding->MediumSpeed = Binding->MediumSpeed;
}
//
// Keep i the same, to check the new binding at
// this position.
//
}
#ifndef _PNP_POWER
Device->HighestExternalNicId = (USHORT)(ValidBindings - DuplicateCount);
Device->HighestType20NicId = (USHORT)(ValidBindings-(WanCount+DuplicateCount));
#else
Device->HighestLanNicId -= (USHORT)DuplicateCount;
if (Device->HighestLanNicId == 0) {
CTEAssert(FALSE);
}
Device->HighestExternalNicId -= (USHORT)DuplicateCount;
Device->HighestType20NicId -= (USHORT)DuplicateCount;
Device->SapNicCount -= (USHORT)DuplicateCount;
#endif _PNP_POWER
} /* IpxResolveBindingSets */
NTSTATUS
IpxBindToAdapter(
IN PDEVICE Device,
IN PBINDING_CONFIG ConfigBinding,
#ifdef _PNP_POWER
IN PADAPTER *AdapterPtr,
#endif
IN ULONG FrameTypeIndex
)
/*++
Routine Description:
This routine handles binding the transport to a new
adapter. It can be called at any point during the life
of the transport.
Arguments:
Device - The IPX device object.
ConfigBinding - The configuration info for this binding.
AdapterPtr - pointer to the adapter to bind to in case of PnP.
FrameTypeIndex - The index into ConfigBinding's array of frame
types for this adapter. The routine is called once for
every valid frame type.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
NTSTATUS status;
#ifndef _PNP_POWER
//
// Adapter came in as a parameter
//
PADAPTER Adapter = NULL;
#else
PADAPTER Adapter = *AdapterPtr;
#endif
PBINDING Binding, OldBinding;
ULONG FrameType, MappedFrameType;
PLIST_ENTRY p;
//
// We can't bind more than one adapter unless we have a
// virtual network configured or we are allowed to run
// with a virtual network of 0.
//
if (Device->BindingCount == 1) {
if ((Device->VirtualNetworkNumber == 0) &&
(!Device->VirtualNetworkOptional)) {
IPX_DEBUG (ADAPTER, ("Cannot bind to more than one adapter\n"));
DbgPrint ("IPX: Disallowing multiple bind ==> VirtualNetwork is 0\n");
IpxWriteGeneralErrorLog(
Device->DeviceObject,
EVENT_TRANSPORT_BINDING_FAILED,
666,
STATUS_NOT_SUPPORTED,
ConfigBinding->AdapterName.Buffer,
0,
NULL);
return STATUS_NOT_SUPPORTED;
}
}
//
// First allocate the memory for the binding.
//
status = IpxCreateBinding(
Device,
ConfigBinding,
FrameTypeIndex,
ConfigBinding->AdapterName.Buffer,
&Binding);
if (status != STATUS_SUCCESS) {
return status;
}
FrameType = ConfigBinding->FrameType[FrameTypeIndex];
//
// In PnP case, we dont need to check for existing adapters since
// we supply a NULL adapter in the parameters if it needs to be created
//
#ifndef _PNP_POWER
//
// Check if there is already an NDIS binding to this adapter,
// and if so, that there is not already a binding with this
// frame type.
//
for (p = Device->InitialBindingList.Flink;
p != &Device->InitialBindingList;
p = p->Flink) {
OldBinding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
if (RtlEqualMemory(
OldBinding->Adapter->AdapterName,
ConfigBinding->AdapterName.Buffer,
OldBinding->Adapter->AdapterNameLength)) {
Adapter = OldBinding->Adapter;
MacMapFrameType(
Adapter->MacInfo.RealMediumType,
FrameType,
&MappedFrameType);
if (Adapter->Bindings[MappedFrameType] != NULL) {
IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
Adapter->AdapterName,
MappedFrameType));
//
// If this was the auto-detect default for this
// adapter and it failed, we need to make the
// previous one the default, so that at least
// one binding will stick around.
//
if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
FrameType, MappedFrameType));
Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
}
IpxDestroyBinding (Binding);
return STATUS_NOT_SUPPORTED;
}
IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
Adapter->AdapterName,
MappedFrameType));
break;
}
}
#endif _PNP_POWER
if (Adapter == NULL) {
//
// No binding to this adapter exists, so create a
// new one.
//
status = IpxCreateAdapter(
Device,
&ConfigBinding->AdapterName,
&Adapter);
if (status != STATUS_SUCCESS) {
IpxDestroyBinding(Binding);
return status;
}
//
// Save these now (they will be the same for all bindings
// on this adapter).
//
Adapter->ConfigMaxPacketSize = ConfigBinding->Parameters[BINDING_MAX_PKT_SIZE];
Adapter->SourceRouting = (BOOLEAN)ConfigBinding->Parameters[BINDING_SOURCE_ROUTE];
Adapter->EnableFunctionalAddress = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_FUNC_ADDR];
Adapter->EnableWanRouter = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_WAN];
Adapter->BindSap = (USHORT)ConfigBinding->Parameters[BINDING_BIND_SAP];
Adapter->BindSapNetworkOrder = REORDER_USHORT(Adapter->BindSap);
CTEAssert (Adapter->BindSap == 0x8137);
CTEAssert (Adapter->BindSapNetworkOrder == 0x3781);
//
// Now fire up NDIS so this adapter talks
//
status = IpxInitializeNdis(
Adapter,
ConfigBinding);
if (!NT_SUCCESS (status)) {
//
// Log an error.
//
IpxWriteGeneralErrorLog(
Device->DeviceObject,
EVENT_TRANSPORT_BINDING_FAILED,
601,
status,
ConfigBinding->AdapterName.Buffer,
0,
NULL);
IpxDestroyAdapter (Adapter);
IpxDestroyBinding (Binding);
//
// Returning this status informs the caller to not
// try any more frame types on this adapter.
//
return STATUS_DEVICE_DOES_NOT_EXIST;
}
//
// For 802.5 bindings we need to start the source routing
// timer to time out old entries.
//
if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
(Adapter->SourceRouting)) {
if (!Device->SourceRoutingUsed) {
Device->SourceRoutingUsed = TRUE;
IpxReferenceDevice (Device, DREF_SR_TIMER);
CTEStartTimer(
&Device->SourceRoutingTimer,
60000, // one minute timeout
MacSourceRoutingTimeout,
(PVOID)Device);
}
}
MacMapFrameType(
Adapter->MacInfo.RealMediumType,
FrameType,
&MappedFrameType);
IPX_DEBUG (ADAPTER, ("Create new bind to adapter %ws, type %d\n",
ConfigBinding->AdapterName.Buffer,
MappedFrameType));
IpxAllocateReceiveBufferPool (Adapter);
#ifdef _PNP_POWER
*AdapterPtr = Adapter;
#endif
}
#ifdef _PNP_POWER
else {
//
// get the mapped frame type
//
MacMapFrameType(
Adapter->MacInfo.RealMediumType,
FrameType,
&MappedFrameType);
if (Adapter->Bindings[MappedFrameType] != NULL) {
IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
Adapter->AdapterName,
MappedFrameType));
//
// If this was the auto-detect default for this
// adapter and it failed, we need to make the
// previous one the default, so that at least
// one binding will stick around.
//
if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
FrameType, MappedFrameType));
Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
}
IpxDestroyBinding (Binding);
return STATUS_NOT_SUPPORTED;
}
IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
Adapter->AdapterName,
MappedFrameType));
}
#endif _PNP_POWER
//
// The local node address starts out the same as the
// MAC address of the adapter (on WAN this will change).
// The local MAC address can also change for WAN.
//
RtlCopyMemory (Binding->LocalAddress.NodeAddress, Adapter->LocalMacAddress.Address, 6);
RtlCopyMemory (Binding->LocalMacAddress.Address, Adapter->LocalMacAddress.Address, 6);
//
// Save the send handler.
//
Binding->SendFrameHandler = NULL;
Binding->FrameType = MappedFrameType;
//
// BUGBUG: Put this in InitializeBindingInfo.
//
switch (Adapter->MacInfo.RealMediumType) {
case NdisMedium802_3:
switch (MappedFrameType) {
case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrame802_3802_3; break;
case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_3802_2; break;
case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrame802_3EthernetII; break;
case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_3Snap; break;
}
break;
case NdisMedium802_5:
switch (MappedFrameType) {
case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_5802_2; break;
case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_5Snap; break;
}
break;
case NdisMediumFddi:
switch (MappedFrameType) {
case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameFddi802_3; break;
case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrameFddi802_2; break;
case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrameFddiSnap; break;
}
break;
case NdisMediumArcnet878_2:
switch (MappedFrameType) {
case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameArcnet878_2; break;
}
break;
case NdisMediumWan:
switch (MappedFrameType) {
case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrameWanEthernetII; break;
}
break;
}
if (Binding->SendFrameHandler == NULL) {
DbgPrint ("BUGBUG!: SendFrameHandler is NULL\n");
}
Adapter->Bindings[MappedFrameType] = Binding;
++Adapter->BindingCount;
Binding->Adapter = Adapter;
#ifndef _PNP_POWER
InsertTailList (&Device->InitialBindingList, &Binding->InitialLinkage);
#endif _PNP_POWER
//
// NicId and ExternalNicId will be filled in later when the binding
// is assigned a spot in the Device->Bindings array.
//
//
// Initialize the per-binding MAC information
//
if ((Adapter->ConfigMaxPacketSize == 0) ||
(Adapter->MaxSendPacketSize < Adapter->ConfigMaxPacketSize)) {
Binding->MaxSendPacketSize = Adapter->MaxSendPacketSize;
} else {
Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
}
Binding->MediumSpeed = Adapter->MediumSpeed;
if (Adapter->MacInfo.MediumAsync) {
Binding->LineUp = FALSE;
} else {
Binding->LineUp = TRUE;
}
MacInitializeBindingInfo(
Binding,
Adapter);
return STATUS_SUCCESS;
} /* IpxBindToAdapter */
BOOLEAN
IpxIsAddressLocal(
IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
)
/*++
Routine Description:
This routine returns TRUE if the specified SourceAddress indicates
the packet was sent by us, and FALSE otherwise.
Arguments:
SourceAddress - The source IPX address.
Return Value:
TRUE if the address is local.
--*/
{
PBINDING Binding;
UINT i;
//
// First see if it is a virtual network address or not.
//
if (RtlEqualMemory (VirtualNode, SourceAddress->NodeAddress, 6)) {
//
// This is us if we have a virtual network configured.
// If we don't have a virtual node, we fall through to the
// other check -- an arcnet card configured as node 1 will
// have what we think of as the "virtual node" as its
// real node address.
//
if ((IpxDevice->VirtualNetwork) &&
(IpxDevice->VirtualNetworkNumber == SourceAddress->NetworkAddress)) {
return TRUE;
}
}
//
// Check through our list of adapters to see if one of
// them is the source node.
//
{
ULONG Index = MIN (IpxDevice->MaxBindings, IpxDevice->ValidBindings);
for (i = 1; i <= Index; i++) {
#ifdef _PNP_POWER
if (((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) &&
#else
if (((Binding = IpxDevice->Bindings[i]) != NULL) &&
#endif _PNP_POWER
(RtlEqualMemory (Binding->LocalAddress.NodeAddress, SourceAddress->NodeAddress, 6))) {
return TRUE;
}
}
}
return FALSE;
} /* IpxIsAddressLocal */
NTSTATUS
IpxUnBindFromAdapter(
IN PBINDING Binding
)
/*++
Routine Description:
This routine handles unbinding the transport from an
adapter. It can be called at any point during the life
of the transport.
Arguments:
Binding - The adapter to unbind.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
PADAPTER Adapter = Binding->Adapter;
Adapter->Bindings[Binding->FrameType] = NULL;
--Adapter->BindingCount;
IpxDereferenceBinding (Binding, BREF_BOUND);
if (Adapter->BindingCount == 0) {
//
// DereferenceAdapter is a NULL macro for load-only.
//
// BUGBUG: Revisit Post 4.0
//
#ifdef _PNP_LATER
//
// Take away the creation reference. When the in-use ref is taken off,
// we destroy this adapter.
//
IpxDereferenceAdapter(Adapter);
#else
//
// Free the packet pools, etc. and close the
// adapter.
//
IpxCloseNdis (Adapter);
IpxDestroyAdapter (Adapter);
#endif
}
return STATUS_SUCCESS;
} /* IpxUnBindFromAdapter */
VOID
IpxUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine unloads the sample transport driver.
It unbinds from any NDIS drivers that are open and frees all resources
associated with the transport. The I/O system will not call us until
nobody above has IPX open.
Arguments:
DriverObject - Pointer to driver object created by the system.
Return Value:
None. When the function returns, the driver is unloaded.
--*/
{
PBINDING Binding;
PREQUEST Request;
PLIST_ENTRY p;
UINT i;
UNREFERENCED_PARAMETER (DriverObject);
IpxDevice->State = DEVICE_STATE_STOPPING;
//
// Complete any pending address notify requests.
//
while ((p = ExInterlockedRemoveHeadList(
&IpxDevice->AddressNotifyQueue,
&IpxDevice->Lock)) != NULL) {
Request = LIST_ENTRY_TO_REQUEST(p);
REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
IpxCompleteRequest (Request);
IpxFreeRequest (IpxDevice, Request);
IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
}
//
// Cancel the source routing timer if used.
//
if (IpxDevice->SourceRoutingUsed) {
IpxDevice->SourceRoutingUsed = FALSE;
if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
}
}
//
// Cancel the RIP long timer, and if we do that then
// send a RIP DOWN message if needed.
//
if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
if (IpxDevice->RipResponder) {
if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
//
// If we queue a request, it will stop the timer.
//
KeWaitForSingleObject(
&IpxDevice->UnloadEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL
);
}
}
IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
} else {
//
// We couldn't stop the timer, which means it is running,
// so we need to wait for the event that is kicked when
// the RIP DOWN messages are done.
//
if (IpxDevice->RipResponder) {
KeWaitForSingleObject(
&IpxDevice->UnloadEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL
);
}
}
//
// Walk the list of device contexts.
//
for (i = 1; i <= IpxDevice->BindingCount; i++) {
#ifdef _PNP_POWER
if ((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) {
INSERT_BINDING(IpxDevice, i, NULL);
#else
if (IpxDevice->Bindings[i] != NULL) {
Binding = IpxDevice->Bindings[i];
IpxDevice->Bindings[i] = NULL;
#endif _PNP_POWER
IpxUnBindFromAdapter (Binding);
}
}
//
// Backup the pointer to free the demand dial location.
//
IpxDevice->Bindings -= EXTRA_BINDINGS;
#ifdef _PNP_POWER
IpxFreeMemory ( IpxDevice->Bindings,
IpxDevice->MaxBindings * sizeof(BIND_ARRAY_ELEM),
MEMORY_BINDING,
"Binding array");
//
// Deallocate the TdiRegistrationAddress and RegistryPathBuffer.
//
IpxFreeMemory ( IpxDevice->TdiRegistrationAddress,
(2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
MEMORY_ADDRESS,
"Tdi Address");
IpxFreeMemory ( IpxDevice->RegistryPathBuffer,
IpxDevice->RegistryPath.Length + sizeof(WCHAR),
MEMORY_CONFIG,
"RegistryPathBuffer");
#endif
KeResetEvent(
&IpxDevice->UnloadEvent
);
IpxDevice->UnloadWaiting = TRUE;
//
// Remove the reference for us being loaded.
//
IpxDereferenceDevice (IpxDevice, DREF_CREATE);
//
// Wait for our count to drop to zero.
//
KeWaitForSingleObject(
&IpxDevice->UnloadEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL
);
//
// Now free the padding buffer.
//
IpxFreePaddingBuffer (IpxDevice);
//
// Now do the cleanup that has to happen at IRQL 0.
//
ExDeleteResource (&IpxDevice->AddressResource);
IoDeleteDevice (IpxDevice->DeviceObject);
//
// Finally, remove ourselves as an NDIS protocol.
//
IpxDeregisterProtocol();
} /* IpxUnload */
NTSTATUS
IpxDispatchOpenClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the main dispatch routine for the IPX device driver.
It accepts an I/O Request Packet, performs the request, and then
returns with the appropriate status.
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;
PDEVICE Device = IpxDevice;
NTSTATUS Status;
PFILE_FULL_EA_INFORMATION openType;
BOOLEAN found;
PADDRESS_FILE AddressFile;
PREQUEST Request;
UINT i;
ULONG Type;
ASSERT( DeviceObject->DeviceExtension == IpxDevice );
#ifdef _PNP_POWER
if ((Device->State == DEVICE_STATE_CLOSED) ||
(Device->State == DEVICE_STATE_STOPPING)) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INVALID_DEVICE_STATE;
}
#else
if (Device->State != DEVICE_STATE_OPEN) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INVALID_DEVICE_STATE;
}
#endif
//
// Allocate a request to track this IRP.
//
Request = IpxAllocateRequest (Device, Irp);
IF_NOT_ALLOCATED(Request) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Make sure status information is consistent every time.
//
MARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = STATUS_PENDING;
REQUEST_INFORMATION(Request) = 0;
//
// Case on the function that is being performed by the requestor. If the
// operation is a valid one for this device, then make it look like it was
// successfully completed, where possible.
//
switch (REQUEST_MAJOR_FUNCTION(Request)) {
//
// The Create function opens a transport object (either address or
// connection). Access checking is performed on the specified
// address to ensure security of transport-layer addresses.
//
case IRP_MJ_CREATE:
openType = OPEN_REQUEST_EA_INFORMATION(Request);
if (openType != NULL) {
found = TRUE;
for (i=0;i<openType->EaNameLength;i++) {
if (openType->EaName[i] == TdiTransportAddress[i]) {
continue;
} else {
found = FALSE;
break;
}
}
if (found) {
Status = IpxOpenAddress (Device, Request);
break;
}
//
// Router
//
if (strncmp(openType->EaName, ROUTER_INTERFACE,
openType->EaNameLength) == 0)
{
found = TRUE;
}
if (found) {
Status = OpenRtAddress (Device, Request);
break;
}
//
// Connection?
//
found = TRUE;
for (i=0;i<openType->EaNameLength;i++) {
if (openType->EaName[i] == TdiConnectionContext[i]) {
continue;
} else {
found = FALSE;
break;
}
}
if (found) {
Status = STATUS_NOT_SUPPORTED;
break;
}
else
{
Status = STATUS_NONEXISTENT_EA_ENTRY;
}
} else {
CTEGetLock (&Device->Lock, &LockHandle);
//
// LowPart is in the OPEN_CONTEXT directly.
// HighPart goes into the upper 2 bytes of the OPEN_TYPE.
//
REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier.LowPart);
(ULONG)(REQUEST_OPEN_TYPE(Request)) = (Device->ControlChannelIdentifier.HighPart << 16);
(ULONG)(REQUEST_OPEN_TYPE(Request)) |= IPX_FILE_TYPE_CONTROL;
++(Device->ControlChannelIdentifier.QuadPart);
if (Device->ControlChannelIdentifier.QuadPart > MAX_CCID) {
Device->ControlChannelIdentifier.QuadPart = 1;
}
CTEFreeLock (&Device->Lock, LockHandle);
Status = STATUS_SUCCESS;
}
break;
case IRP_MJ_CLOSE:
//
// The Close function closes a transport endpoint, terminates
// all outstanding transport activity on the endpoint, and unbinds
// the endpoint from its transport address, if any. If this
// is the last transport endpoint bound to the address, then
// the address is removed from the provider.
//
switch (Type = ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK)) {
default:
if ((Type >= ROUTER_ADDRESS_FILE) &&
(Type <= (ROUTER_ADDRESS_FILE + IPX_RT_MAX_ADDRESSES)))
{
CloseRtAddress(Device, Request);
}
else
{
Status = STATUS_INVALID_HANDLE;
break;
}
// fall through
case TDI_TRANSPORT_ADDRESS_FILE:
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
//
// This creates a reference to AddressFile->Address
// which is removed by IpxCloseAddressFile.
//
Status = IpxVerifyAddressFile(AddressFile);
if (!NT_SUCCESS (Status)) {
Status = STATUS_INVALID_HANDLE;
} else {
Status = IpxCloseAddressFile (Device, Request);
IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
}
break;
case IPX_FILE_TYPE_CONTROL:
{
LARGE_INTEGER ControlChannelId;
CCID_FROM_REQUEST(ControlChannelId, Request);
//
// See if it is one of the upper driver's control channels.
//
Status = STATUS_SUCCESS;
IPX_DEBUG (DEVICE, ("CCID: (%d, %d)\n", ControlChannelId.HighPart, ControlChannelId.LowPart));
for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
if (Device->UpperDriverControlChannel[i].QuadPart ==
ControlChannelId.QuadPart) {
Status = IpxInternalUnbind (Device, i);
break;
}
}
break;
}
}
break;
case IRP_MJ_CLEANUP:
//
// Handle the two stage IRP for a file close operation. When the first
// stage hits, run down all activity on the object of interest. This
// do everything to it but remove the creation hold. Then, when the
// CLOSE irp hits, actually close the object.
//
switch (Type = ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK)) {
default:
if ((Type >= ROUTER_ADDRESS_FILE) &&
(Type <= (ROUTER_ADDRESS_FILE + IPX_RT_MAX_ADDRESSES)))
{
CleanupRtAddress(Device, Request);
}
else
{
Status = STATUS_INVALID_HANDLE;
break;
}
//
// fall through
//
case TDI_TRANSPORT_ADDRESS_FILE:
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
Status = IpxVerifyAddressFile(AddressFile);
if (!NT_SUCCESS (Status)) {
Status = STATUS_INVALID_HANDLE;
} else {
IpxStopAddressFile (AddressFile);
IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
Status = STATUS_SUCCESS;
}
break;
case IPX_FILE_TYPE_CONTROL:
{
LARGE_INTEGER ControlChannelId;
CCID_FROM_REQUEST(ControlChannelId, Request);
//
// Check for any line change IRPs submitted by this
// address.
//
IpxAbortLineChanges ((PVOID)&ControlChannelId);
IpxAbortNtfChanges ((PVOID)&ControlChannelId);
Status = STATUS_SUCCESS;
break;
}
}
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
} /* major function switch */
if (Status != STATUS_PENDING) {
UNMARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = Status;
IpxCompleteRequest (Request);
IpxFreeRequest (Device, Request);
}
//
// Return the immediate status code to the caller.
//
return Status;
} /* IpxDispatchOpenClose */
#define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
NTSYSAPI
NTSTATUS
NTAPI
ZwLoadDriver(
IN PUNICODE_STRING DriverServiceName
);
NTSTATUS
IpxDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine dispatches TDI request types to different handlers based
on the minor IOCTL function code in the IRP's current stack location.
In addition to cracking the minor function code, this routine also
reaches into the IRP and passes the packetized parameters stored there
as parameters to the various TDI request handlers so that they are
not IRP-dependent.
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.
--*/
{
NTSTATUS Status;
PDEVICE Device = IpxDevice;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
static NDIS_STRING SpxServiceName = NDIS_STRING_CONST ("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkSpx");
ASSERT( DeviceObject->DeviceExtension == IpxDevice );
//
// Branch to the appropriate request handler. Preliminary checking of
// the size of the request block is performed here so that it is known
// in the handlers that the minimum input parameters are readable. It
// is *not* determined here whether variable length input fields are
// passed correctly; this is a check which must be made within each routine.
//
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER: {
PULONG EntryPoint;
//
// This is the LanmanServer trying to get the send
// entry point.
//
IPX_DEBUG (BIND, ("Direct send entry point being returned\n"));
EntryPoint = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
*EntryPoint = (ULONG)IpxTdiSendDatagram;
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = Status;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
break;
}
case IOCTL_IPX_INTERNAL_BIND:
//
// This is a client trying to bind.
//
CTEAssert ((IOCTL_IPX_INTERNAL_BIND & 0x3) == METHOD_BUFFERED);
CTEAssert (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
#ifdef _PNP_POWER
if ((Device->State == DEVICE_STATE_CLOSED) ||
(Device->State == DEVICE_STATE_STOPPING)) {
#else
if (Device->State != DEVICE_STATE_OPEN) {
#endif
Status = STATUS_INVALID_DEVICE_STATE;
} else {
Status = IpxInternalBind (Device, Irp);
}
CTEAssert (Status != STATUS_PENDING);
Irp->IoStatus.Status = Status;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
break;
case IOCTL_IPX_LOAD_SPX:
//
// The SPX helper dll is asking us to load SPX.
//
Status = ZwLoadDriver (&SpxServiceName);
Irp->IoStatus.Status = Status;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
break;
#ifdef SNMP
case IOCTL_IPX_MIB_GET: {
//
// Get the Base MIB entries out of the device. All Host-side
// entries, appearing in the MS and Novell MIBs are returned.
//
PNOVIPXMIB_BASE UserBuffer;
UserBuffer = (PNOVIPXMIB_BASE)Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Information = sizeof(NOVIPXMIB_BASE);
RtlCopyMemory( UserBuffer,
&Device->MibBase,
sizeof(NOVIPXMIB_BASE));
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
Status = STATUS_SUCCESS;
break;
}
#endif SNMP
case MIPX_SEND_DATAGRAM:
MARK_REQUEST_PENDING(Irp);
Status = SendIrpFromRt (Device, Irp);
if (Status == STATUS_PENDING) {
return STATUS_PENDING;
} else {
UNMARK_REQUEST_PENDING(Irp);
REQUEST_STATUS(Irp) = Status;
IpxCompleteRequest (Irp);
IpxFreeRequest (Device, Irp);
return Status;
}
break;
case MIPX_RCV_DATAGRAM:
MARK_REQUEST_PENDING(Irp);
Status = RcvIrpFromRt (Device, Irp);
if (Status == STATUS_PENDING) {
return STATUS_PENDING;
} else {
UNMARK_REQUEST_PENDING(Irp);
REQUEST_STATUS(Irp) = Status;
IpxCompleteRequest (Irp);
IpxFreeRequest (Device, Irp);
return Status;
}
break;
default:
//
// Convert the user call to the proper internal device call.
//
Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
if (Status == STATUS_SUCCESS) {
//
// If TdiMapUserRequest returns SUCCESS then the IRP
// has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
// IRP, so we dispatch it as usual. The IRP will
// be completed by this call.
//
Status = IpxDispatchInternal (DeviceObject, Irp);
} else {
Irp->IoStatus.Status = Status;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
}
break;
}
return Status;
} /* IpxDispatchDeviceControl */
NTSTATUS
IpxDispatchInternal (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine dispatches TDI request types to different handlers based
on the minor IOCTL function code in the IRP's current stack location.
In addition to cracking the minor function code, this routine also
reaches into the IRP and passes the packetized parameters stored there
as parameters to the various TDI request handlers so that they are
not IRP-dependent.
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.
--*/
{
NTSTATUS Status;
PDEVICE Device = IpxDevice;
PREQUEST Request;
ASSERT( DeviceObject->DeviceExtension == IpxDevice );
if (Device->State == DEVICE_STATE_OPEN) {
//
// Allocate a request to track this IRP.
//
Request = IpxAllocateRequest (Device, Irp);
IF_NOT_ALLOCATED(Request) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Make sure status information is consistent every time.
//
MARK_REQUEST_PENDING(Request);
#if DBG
REQUEST_STATUS(Request) = STATUS_PENDING;
REQUEST_INFORMATION(Request) = 0;
#endif
//
// Branch to the appropriate request handler. Preliminary checking of
// the size of the request block is performed here so that it is known
// in the handlers that the minimum input parameters are readable. It
// is *not* determined here whether variable length input fields are
// passed correctly; this is a check which must be made within each routine.
//
switch (REQUEST_MINOR_FUNCTION(Request)) {
case TDI_SEND_DATAGRAM:
Status = IpxTdiSendDatagram (DeviceObject, Request);
break;
case TDI_ACTION:
Status = IpxTdiAction (Device, Request);
break;
case TDI_QUERY_INFORMATION:
Status = IpxTdiQueryInformation (Device, Request);
break;
case TDI_RECEIVE_DATAGRAM:
Status = IpxTdiReceiveDatagram (Request);
break;
case TDI_SET_EVENT_HANDLER:
Status = IpxTdiSetEventHandler (Request);
break;
case TDI_SET_INFORMATION:
Status = IpxTdiSetInformation (Device, Request);
break;
//
// Something we don't know about was submitted.
//
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
}
//
// Return the immediate status code to the caller.
//
if (Status == STATUS_PENDING) {
return STATUS_PENDING;
} else {
UNMARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = Status;
IpxCompleteRequest (Request);
IpxFreeRequest (Device, Request);
return Status;
}
} else {
//
// The device was not open.
//
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INVALID_DEVICE_STATE;
}
} /* IpxDispatchInternal */
PVOID
IpxpAllocateMemory(
IN ULONG BytesNeeded,
IN ULONG Tag,
IN BOOLEAN ChargeDevice
)
/*++
Routine Description:
This routine allocates memory, making sure it is within
the limit allowed by the device.
Arguments:
BytesNeeded - The number of bytes to allocated.
ChargeDevice - TRUE if the device should be charged.
Return Value:
None.
--*/
{
PVOID Memory;
PDEVICE Device = IpxDevice;
if (ChargeDevice) {
if ((Device->MemoryLimit != 0) &&
(((LONG)(Device->MemoryUsage + BytesNeeded) >
Device->MemoryLimit))) {
IpxPrint1 ("IPX: Could not allocate %d: limit\n", BytesNeeded);
IpxWriteResourceErrorLog(
Device->DeviceObject,
EVENT_TRANSPORT_RESOURCE_POOL,
BytesNeeded,
Tag);
return NULL;
}
}
#if ISN_NT
Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' XPI');
#else
Memory = CTEAllocMem (BytesNeeded);
#endif
if (Memory == NULL) {
IpxPrint1("IPX: Could not allocate %d: no pool\n", BytesNeeded);
if (ChargeDevice) {
IpxWriteResourceErrorLog(
Device->DeviceObject,
EVENT_TRANSPORT_RESOURCE_POOL,
BytesNeeded,
Tag);
}
return NULL;
}
if (ChargeDevice) {
Device->MemoryUsage += BytesNeeded;
}
return Memory;
} /* IpxpAllocateMemory */
VOID
IpxpFreeMemory(
IN PVOID Memory,
IN ULONG BytesAllocated,
IN BOOLEAN ChargeDevice
)
/*++
Routine Description:
This routine frees memory allocated with IpxpAllocateMemory.
Arguments:
Memory - The memory allocated.
BytesAllocated - The number of bytes to freed.
ChargeDevice - TRUE if the device should be charged.
Return Value:
None.
--*/
{
PDEVICE Device = IpxDevice;
#if ISN_NT
ExFreePool (Memory);
#else
CTEFreeMem (Memory);
#endif
if (ChargeDevice) {
Device->MemoryUsage -= BytesAllocated;
}
} /* IpxpFreeMemory */
#if DBG
PVOID
IpxpAllocateTaggedMemory(
IN ULONG BytesNeeded,
IN ULONG Tag,
IN PUCHAR Description
)
/*++
Routine Description:
This routine allocates memory, charging it to the device.
If it cannot allocate memory it uses the Tag and Descriptor
to log an error.
Arguments:
BytesNeeded - The number of bytes to allocated.
Tag - A unique ID used in the error log.
Description - A text description of the allocation.
Return Value:
None.
--*/
{
PVOID Memory;
UNREFERENCED_PARAMETER(Description);
Memory = IpxpAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
if (Memory) {
(VOID)IPX_ADD_ULONG(
&IpxMemoryTag[Tag].BytesAllocated,
BytesNeeded,
&IpxMemoryInterlock);
}
return Memory;
} /* IpxpAllocateTaggedMemory */
VOID
IpxpFreeTaggedMemory(
IN PVOID Memory,
IN ULONG BytesAllocated,
IN ULONG Tag,
IN PUCHAR Description
)
/*++
Routine Description:
This routine frees memory allocated with IpxpAllocateTaggedMemory.
Arguments:
Memory - The memory allocated.
BytesAllocated - The number of bytes to freed.
Tag - A unique ID used in the error log.
Description - A text description of the allocation.
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER(Description);
(VOID)IPX_ADD_ULONG(
&IpxMemoryTag[Tag].BytesAllocated,
(ULONG)(-(LONG)BytesAllocated),
&IpxMemoryInterlock);
IpxpFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
} /* IpxpFreeTaggedMemory */
#endif
VOID
IpxWriteResourceErrorLog(
IN PDEVICE_OBJECT DeviceObject,
IN NTSTATUS ErrorCode,
IN ULONG BytesNeeded,
IN ULONG UniqueErrorValue
)
/*++
Routine Description:
This routine allocates and writes an error log entry which has
a %3 value that needs to be converted to a string. It is currently
used for EVENT_TRANSPORT_RESOURCE_POOL and EVENT_IPX_INTERNAL_NET_
INVALID.
Arguments:
DeviceObject - Pointer to the system device object.
ErrorCode - The transport event code.
BytesNeeded - If applicable, the number of bytes that could not
be allocated -- will be put in the dump data.
UniqueErrorValue - Used as the UniqueErrorValue in the error log
packet and converted for use as the %3 string.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
UCHAR EntrySize;
PUCHAR StringLoc;
ULONG TempUniqueError;
PDEVICE Device = IpxDevice;
static WCHAR UniqueErrorBuffer[9] = L"00000000";
UINT CurrentDigit;
INT i;
//
// Convert the error value into a buffer.
//
TempUniqueError = UniqueErrorValue;
i = 8;
do {
CurrentDigit = TempUniqueError & 0xf;
TempUniqueError >>= 4;
i--;
if (CurrentDigit >= 0xa) {
UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
} else {
UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit + L'0');
}
} while (TempUniqueError);
EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
Device->DeviceNameLength +
sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR));
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
DeviceObject,
EntrySize
);
if (errorLogEntry != NULL) {
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
errorLogEntry->RetryCount = (UCHAR)-1;
errorLogEntry->DumpDataSize = sizeof(ULONG);
errorLogEntry->NumberOfStrings = 2;
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
errorLogEntry->EventCategory = 0;
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
errorLogEntry->SequenceNumber = (ULONG)-1;
errorLogEntry->IoControlCode = 0;
errorLogEntry->DumpData[0] = BytesNeeded;
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
StringLoc += Device->DeviceNameLength;
RtlCopyMemory (StringLoc, UniqueErrorBuffer + i, sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR)));
IoWriteErrorLogEntry(errorLogEntry);
}
} /* IpxWriteResourceErrorLog */
VOID
IpxWriteGeneralErrorLog(
IN PDEVICE_OBJECT DeviceObject,
IN NTSTATUS ErrorCode,
IN ULONG UniqueErrorValue,
IN NTSTATUS FinalStatus,
IN PWSTR SecondString,
IN ULONG DumpDataCount,
IN ULONG DumpData[]
)
/*++
Routine Description:
This routine allocates and writes an error log entry indicating
a general problem as indicated by the parameters. It handles
event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
events have messages with one or two strings in them.
Arguments:
DeviceObject - Pointer to the system device object, or this may be
a driver object instead.
ErrorCode - The transport event code.
UniqueErrorValue - Used as the UniqueErrorValue in the error log
packet.
FinalStatus - Used as the FinalStatus in the error log packet.
SecondString - If not NULL, the string to use as the %3
value in the error log packet.
DumpDataCount - The number of ULONGs of dump data.
DumpData - Dump data for the packet.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
UCHAR EntrySize;
ULONG SecondStringSize;
PUCHAR StringLoc;
PDEVICE Device = IpxDevice;
static WCHAR DriverName[9] = L"NwlnkIpx";
EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
(DumpDataCount * sizeof(ULONG));
if (DeviceObject->Type == IO_TYPE_DEVICE) {
EntrySize += (UCHAR)Device->DeviceNameLength;
} else {
EntrySize += sizeof(DriverName);
}
if (SecondString) {
SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
EntrySize += (UCHAR)SecondStringSize;
}
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
DeviceObject,
EntrySize
);
if (errorLogEntry != NULL) {
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
errorLogEntry->RetryCount = (UCHAR)-1;
errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
errorLogEntry->StringOffset =
sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
errorLogEntry->EventCategory = 0;
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
errorLogEntry->FinalStatus = FinalStatus;
errorLogEntry->SequenceNumber = (ULONG)-1;
errorLogEntry->IoControlCode = 0;
if (DumpDataCount) {
RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
}
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
if (DeviceObject->Type == IO_TYPE_DEVICE) {
RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
StringLoc += Device->DeviceNameLength;
} else {
RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
StringLoc += sizeof(DriverName);
}
if (SecondString) {
RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
}
IoWriteErrorLogEntry(errorLogEntry);
}
} /* IpxWriteGeneralErrorLog */
VOID
IpxWriteOidErrorLog(
IN PDEVICE_OBJECT DeviceObject,
IN NTSTATUS ErrorCode,
IN NTSTATUS FinalStatus,
IN PWSTR AdapterString,
IN ULONG OidValue
)
/*++
Routine Description:
This routine allocates and writes an error log entry indicating
a problem querying or setting an OID on an adapter. It handles
event codes SET_OID_FAILED and QUERY_OID_FAILED.
Arguments:
DeviceObject - Pointer to the system device object.
ErrorCode - Used as the ErrorCode in the error log packet.
FinalStatus - Used as the FinalStatus in the error log packet.
AdapterString - The name of the adapter we were bound to.
OidValue - The OID which could not be set or queried.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
UCHAR EntrySize;
ULONG AdapterStringSize;
PUCHAR StringLoc;
PDEVICE Device = IpxDevice;
static WCHAR OidBuffer[9] = L"00000000";
INT i;
UINT CurrentDigit;
AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
sizeof(ULONG) +
Device->DeviceNameLength +
AdapterStringSize +
sizeof(OidBuffer);
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
DeviceObject,
EntrySize
);
//
// Convert the OID into a buffer.
//
for (i=7; i>=0; i--) {
CurrentDigit = OidValue & 0xf;
OidValue >>= 4;
if (CurrentDigit >= 0xa) {
OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
} else {
OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
}
}
if (errorLogEntry != NULL) {
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
errorLogEntry->RetryCount = (UCHAR)-1;
errorLogEntry->DumpDataSize = 0;
errorLogEntry->NumberOfStrings = 3;
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
errorLogEntry->EventCategory = 0;
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->UniqueErrorValue = 0;
errorLogEntry->FinalStatus = FinalStatus;
errorLogEntry->SequenceNumber = (ULONG)-1;
errorLogEntry->IoControlCode = 0;
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
StringLoc += Device->DeviceNameLength;
RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
StringLoc += sizeof(OidBuffer);
RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
IoWriteErrorLogEntry(errorLogEntry);
}
} /* IpxWriteOidErrorLog */
#ifdef _PNP_POWER
VOID
IpxPnPUpdateDevice(
IN PDEVICE Device
)
/*++
Routine Description:
Updates datagram sizes, lookahead sizes, etc. in the Device as a result
of a new binding coming in.
Arguments:
Device - The IPX device object.
Return Value:
None.
--*/
{
ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
ULONG LinkSpeed, MacOptions;
ULONG i;
PBINDING Binding;
IPX_DEFINE_LOCK_HANDLE (LockHandle)
IPX_GET_LOCK(&Device->BindAccessLock, &LockHandle);
//
// Calculate some values based on all the bindings.
//
MaxLookahead = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MaxLookaheadData; // largest binding value
AnnouncedMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->AnnouncedMaxDatagramSize; // smallest binding value
RealMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->RealMaxDatagramSize; // smallest binding value
if (NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->LineUp) {
LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed; // smallest binding value
} else {
LinkSpeed = 0xffffffff;
}
MacOptions = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->Adapter->MacInfo.MacOptions; // AND of binding values
for (i = 2; i <= Device->ValidBindings; i++) {
Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, i);
if (!Binding) {
continue;
}
if (Binding->MaxLookaheadData > MaxLookahead) {
MaxLookahead = Binding->MaxLookaheadData;
}
if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
}
if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
RealMaxDatagram = Binding->RealMaxDatagramSize;
}
if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
LinkSpeed = Binding->MediumSpeed;
}
MacOptions &= Binding->Adapter->MacInfo.MacOptions;
}
Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
Device->RealMaxDatagramSize = RealMaxDatagram;
Device->Information.MaximumLookaheadData = MaxLookahead;
//
// If we couldn't find anything better, use the speed from
// the first binding.
//
if (LinkSpeed == 0xffffffff) {
Device->LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed;
} else {
Device->LinkSpeed = LinkSpeed;
}
Device->MacOptions = MacOptions;
IPX_FREE_LOCK(&Device->BindAccessLock, LockHandle);
}
VOID
IpxPnPUpdateBindingArray(
IN PDEVICE Device,
IN PADAPTER Adapter,
IN PBINDING_CONFIG ConfigBinding
)
/*++
Routine Description:
This routine is called to update the binding array to
add the new bindings that appeared in this PnP event.
The order of bindings in the array is as follows:
- First comes the first binding to each LAN network
- Following that are all WAN bindings
- Following that are any duplicate bindings to LAN networks
(the others in the "binding set").
This routine inserts the bindings while maintaining this
order by resolving binding sets.
The bindings are also inserted into the RIP database.
If "global wan net" is true we will advertise up to
and including the first wan binding as the highest nic
id; otherwise we advertise up to and including the last
wan binding. In all cases the duplicate bindings are
hidden.
Updates the SapNicCount, Device->FirstLanNicId and Device->FirstWanNicId
Arguments:
Device - The IPX device object.
Adapter - The adapter added in this PnP event
ValidBindings - the number of bindings valid for this adapter (if LAN)
Return Value:
None.
--*/
{
ULONG i, j;
PBINDING Binding, MasterBinding;
NTSTATUS status;
//
// Insert in proper place; if WAN, after all the WAN bindings
// If LAN, check for binding sets and insert in proper place
// Also, insert into the Rip Tables.
//
//
// Go thru' the bindings for this adapter, inserting into the
// binding array in place
//
for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
ULONG MappedFrameType;
//
// Store in the preference order.
// Map the frame types since we could have a case where the user selects a FrameType (say, EthernetII on FDDI)
// which maps to a different FrameType (802.2). Then we would fail to find the binding in the adapter array;
// we could potentialy add a binding twice (if two frame types map to the same Frame, then we would go to the
// mapped one twice). This is taken care of by purging dups from the ConfigBinding->FrameType array when we
// create the bindings off of the Adapter (see call to IpxBindToAdapter).
//
MacMapFrameType(
Adapter->MacInfo.RealMediumType,
ConfigBinding->FrameType[i],
&MappedFrameType);
Binding = Adapter->Bindings[MappedFrameType];
if (!Binding){
continue;
}
CTEAssert(Binding->FrameType == MappedFrameType);
Binding->fInfoIndicated = FALSE;
if (Adapter->MacInfo.MediumAsync) {
PBINDING DemandDialBinding;
//
// WAN: Place after the HighestExternalNicId, with space for WanLine # of bindings.
// Update the First/LastWanNicId.
//
Adapter->FirstWanNicId = (USHORT)Device->HighestExternalNicId+1;
Adapter->LastWanNicId = (USHORT)(Device->HighestExternalNicId + Adapter->WanNicIdCount);
//
// Make sure we dont overflow the array
// Re-alloc the array to fit the new bindings
//
if (Device->ValidBindings+Adapter->WanNicIdCount >= Device->MaxBindings) {
status = IpxPnPReallocateBindingArray(Device, Adapter->WanNicIdCount);
CTEAssert(status == STATUS_SUCCESS);
}
//
// Move Slaves down by WanNicIdCount# of entries
//
for (j = Device->ValidBindings; j > Device->HighestExternalNicId; j--) {
INSERT_BINDING(Device, j+Adapter->WanNicIdCount, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)) {
NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)->NicId += (USHORT)Adapter->WanNicIdCount;
}
}
//
// Insert the WAN binding in the place just allocated
//
INSERT_BINDING(Device, Device->HighestExternalNicId+1, Binding);
SET_VERSION(Device, Device->HighestExternalNicId+1);
Binding->NicId = (USHORT)Device->HighestExternalNicId+1;
//
// Update the indices
//
Device->HighestExternalNicId += (USHORT)Adapter->WanNicIdCount;
Device->ValidBindings += (USHORT)Adapter->WanNicIdCount;
Device->BindingCount += (USHORT)Adapter->WanNicIdCount;
Device->SapNicCount++;
//
// Since we initialize FirstWanNicId to 1, we need to compare against that.
// In case of no LAN bindings, we are fine since we have only one WAN binding initally
// (all the other WAN lines have place holders).
//
if (Device->FirstWanNicId == (USHORT)1) {
Device->FirstWanNicId = Binding->NicId;
}
//
// Prime the DemandDial binding too.
//
//
// First allocate the memory for the binding.
//
status = IpxCreateBinding(
Device,
NULL,
0,
Adapter->AdapterName,
&DemandDialBinding);
if (status != STATUS_SUCCESS) {
CTEAssert(FALSE);
}
//
// Copy over all the values from the first WAN binding created above.
//
RtlCopyMemory(DemandDialBinding, Binding, sizeof(BINDING));
INSERT_BINDING(Device, (SHORT)DEMAND_DIAL_ADAPTER_CONTEXT, DemandDialBinding);
DemandDialBinding->NicId = (USHORT)DEMAND_DIAL_ADAPTER_CONTEXT;
DemandDialBinding->FwdAdapterContext = INVALID_CONTEXT_VALUE;
IpxReferenceBinding(DemandDialBinding, BREF_FWDOPEN); // so it appears the FWD opened it.
//
// BUGBUGZZ Make this inline later
//
// This should be done after all the auto-detect bindings have been thrown away.
//
// IpxPnPUpdateDevice(Device, Binding);
//
// Since WAN can have only one frame type, break
//
break;
} else {
Device->BindingCount++;
//
// Make sure we dont overflow the array
// Re-alloc the array to fit the new bindings
//
if (Device->ValidBindings+1 >= Device->MaxBindings) {
status = IpxPnPReallocateBindingArray(Device, 1);
CTEAssert(status == STATUS_SUCCESS);
}
//
// LAN: Figure out if it is a slave binding only for non-auto-detect bindings.
//
{
ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
for (j = 1; j < Index; j++) {
MasterBinding = NIC_ID_TO_BINDING_NO_ILOCK(Device, j);
if (MasterBinding &&
(MasterBinding->ConfiguredNetworkNumber) &&
(MasterBinding->ConfiguredNetworkNumber == Binding->ConfiguredNetworkNumber) &&
(MasterBinding->FrameType == Binding->FrameType) &&
(MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
CTEAssert(Binding->ConfiguredNetworkNumber);
break;
}
}
}
if (j < Device->HighestExternalNicId) {
//
// Slave binding
//
//
// Now make MasterBinding the head of a binding set.
//
if (MasterBinding->BindingSetMember) {
//
// Just insert ourselves in the chain.
//
#if DBG
DbgPrint ("IPX: %ws is also on network %lx\n",
Binding->Adapter->AdapterName,
REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
#endif
IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
CTEAssert (MasterBinding->CurrentSendBinding);
Binding->NextBinding = MasterBinding->NextBinding;
} else {
//
// Start the chain with the two bindings in it.
//
#if DBG
DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
#endif
IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
MasterBinding->BindingSetMember = TRUE;
MasterBinding->CurrentSendBinding = MasterBinding;
MasterBinding->MasterBinding = MasterBinding;
Binding->NextBinding = MasterBinding;
}
MasterBinding->NextBinding = Binding;
Binding->BindingSetMember = TRUE;
Binding->ReceiveBroadcast = FALSE;
Binding->CurrentSendBinding = NULL;
Binding->MasterBinding = MasterBinding;
//
// Since the master binding looks like all members of
// the binding set to people querying from above, we have
// to make it the worst-case of all the elements. Generally
// these will be equal since the frame type and media is
// the same.
//
if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
}
if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
}
if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
}
if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
MasterBinding->MediumSpeed = Binding->MediumSpeed;
}
//
// Place the binding after the last slave binding
//
INSERT_BINDING(Device, Device->ValidBindings+1, Binding);
SET_VERSION(Device, Device->ValidBindings+1);
Binding->NicId = (USHORT)Device->ValidBindings+1;
//
// Update the indices
//
Device->ValidBindings++;
} else {
PBINDING WanBinding=NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
if (WanBinding) {
WanBinding->Adapter->LastWanNicId++;
WanBinding->Adapter->FirstWanNicId++;
}
//
// Not a binding set slave binding - just add it after the last LAN binding
//
//
// Move WAN and Slaves down by 1 entry
//
for (j = Device->ValidBindings; j > Device->HighestLanNicId; j--) {
INSERT_BINDING(Device, j+1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)) {
NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)->NicId++;
}
}
//
// Increment the WAN counters in the adapter.
//
//
// Insert the LAN binding in the place just allocated
//
INSERT_BINDING(Device, Device->HighestLanNicId+1, Binding);
SET_VERSION(Device, Device->HighestLanNicId+1);
Binding->NicId = (USHORT)Device->HighestLanNicId+1;
//
// Update the indices
//
Device->HighestLanNicId++;
Device->HighestExternalNicId++;
Device->ValidBindings++;
Device->HighestType20NicId++;
Device->SapNicCount++;
if (Device->FirstLanNicId == (USHORT)-1) {
Device->FirstLanNicId = Binding->NicId;
}
if (!NIC_ID_TO_BINDING(Device, (SHORT)LOOPBACK_NIC_ID)) {
PBINDING LoopbackBinding;
//
// Prime the Loopback binding too.
//
//
// First allocate the memory for the binding.
//
status = IpxCreateBinding(
Device,
NULL,
0,
Adapter->AdapterName,
&LoopbackBinding);
if (status != STATUS_SUCCESS) {
CTEAssert(FALSE);
}
//
// Copy over all the values from the first WAN binding created above.
//
RtlCopyMemory(LoopbackBinding, Binding, sizeof(BINDING));
INSERT_BINDING(Device, (SHORT)LOOPBACK_NIC_ID, LoopbackBinding);
LoopbackBinding->NicId = (USHORT)LOOPBACK_NIC_ID;
LoopbackBinding->FwdAdapterContext = VIRTUAL_NET_FORWARDER_CONTEXT;
IpxReferenceBinding(LoopbackBinding, BREF_FWDOPEN); // so it appears the FWD opened it.
}
}
}
//
// Insert this binding in the RIP Tables
//
if (Binding->ConfiguredNetworkNumber != 0) {
status = RipInsertLocalNetwork(
Binding->ConfiguredNetworkNumber,
Binding->NicId,
Binding->Adapter->NdisBindingHandle,
(USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
if ((status == STATUS_SUCCESS) ||
(status == STATUS_DUPLICATE_NAME)) {
Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
}
}
//
// BUGBUGZZ Make this inline later
//
// This should be done after all the auto-detect bindings have been thrown away.
//
// IpxPnPUpdateDevice(Device, Binding);
}
} /* IpxPnPUpdateBindingArray */
VOID
IpxPnPToLoad()
/*++
Routine Description:
This routine takes the driver to LOADED state (from OPEN) when all
PnP adapters have been removed from the machine.
Arguments:
None.
Return Value:
None. When the function returns, the driver is in LOADED state.
--*/
{
PBINDING Binding;
PREQUEST Request;
PLIST_ENTRY p;
UINT i;
NTSTATUS ntStatus;
IPX_DEBUG(PNP, ("Going back to loaded state\n"));
//
// Inform TDI clients about the close of our device object.
//
if ((ntStatus = TdiDeregisterDeviceObject(IpxDevice->TdiRegistrationHandle)) != STATUS_SUCCESS) {
IPX_DEBUG(PNP, ("TdiDeRegisterDeviceObject failed: %lx", ntStatus));
}
//
// Complete any pending address notify requests.
//
while ((p = ExInterlockedRemoveHeadList(
&IpxDevice->AddressNotifyQueue,
&IpxDevice->Lock)) != NULL) {
Request = LIST_ENTRY_TO_REQUEST(p);
REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
IpxCompleteRequest (Request);
IpxFreeRequest (IpxDevice, Request);
IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
}
//
// Cancel the source routing timer if used.
//
if (IpxDevice->SourceRoutingUsed) {
IpxDevice->SourceRoutingUsed = FALSE;
if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
}
}
//
// Cancel the RIP long timer, and if we do that then
// send a RIP DOWN message if needed.
//
if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
if (IpxDevice->RipResponder) {
if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
//
// If we queue a request, it will stop the timer.
//
KeWaitForSingleObject(
&IpxDevice->UnloadEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL
);
}
}
IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
} else {
//
// We couldn't stop the timer, which means it is running,
// so we need to wait for the event that is kicked when
// the RIP DOWN messages are done.
//
if (IpxDevice->RipResponder) {
KeWaitForSingleObject(
&IpxDevice->UnloadEvent,
Executive,
KernelMode,
TRUE,
(PLARGE_INTEGER)NULL
);
}
}
} /* IpxPnPToLoad */
NTSTATUS
IpxPnPReallocateBindingArray(
IN PDEVICE Device,
IN ULONG Size
)
/*++
Routine Description:
This routine reallocates the binding array when the number of bindings go above
Device->MaxBindings.
Arguments:
Device - pointer to the device.
Size - the number of new entries required.
Return Value:
None.
--*/
{
PBIND_ARRAY_ELEM BindingArray;
PBIND_ARRAY_ELEM OldBindingArray;
ULONG Pad=2; // extra bindings we keep around
ULONG NewSize = Size + Pad + Device->MaxBindings;
//
// The absolute max WAN bindings.
//
CTEAssert(Size < 2048);
//
// Re-allocate the new array
//
BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
NewSize * sizeof(BIND_ARRAY_ELEM),
MEMORY_BINDING,
"Binding array");
if (BindingArray == NULL) {
IpxWriteGeneralErrorLog(
(PVOID)Device->DeviceObject,
EVENT_IPX_NO_ADAPTERS,
802,
STATUS_DEVICE_DOES_NOT_EXIST,
NULL,
0,
NULL);
IpxDereferenceDevice (Device, DREF_CREATE);
DbgPrint ("Failed to allocate memory in binding array expansion\n");
//
// Unload the driver here? In case of WAN, we can tolerate this failure. What about LAN? [BUGBUGZZ]
//
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory (BindingArray, NewSize * sizeof(BIND_ARRAY_ELEM));
//
// Backup the pointer to free the demand dial location.
//
OldBindingArray = Device->Bindings - EXTRA_BINDINGS;
//
// Copy the old array into the new one.
//
RtlCopyMemory (BindingArray, OldBindingArray, (Device->ValidBindings+1+EXTRA_BINDINGS) * sizeof(BIND_ARRAY_ELEM));
//
// Free the old one.
//
IpxFreeMemory ( OldBindingArray,
(Device->MaxBindings+EXTRA_BINDINGS) * sizeof(BIND_ARRAY_ELEM),
MEMORY_BINDING,
"Binding array");
IPX_DEBUG(PNP, ("Expand bindarr old: %lx, new: %lx, oldsize: %lx\n",
Device->Bindings, BindingArray, Device->MaxBindings));
//
// We keep BindingArray[-1] as a placeholder for demand dial bindings.
// This NicId is returned by the Fwd when a FindRoute is done on a demand
// dial Nic. At the time of the InternalSend, the true Nic is returned.
// We create a placeholder here to avoid special checks in the critical send path.
//
// NOTE: we need to free this demand dial binding as well as ensure that the
// true binding array pointer is freed at Device Destroy time.
//
//
// Increment beyond the first pointer - we will refer to the just incremented
// one as Device->Bindings[-1].
//
BindingArray += EXTRA_BINDINGS;
//
// Use interlocked exchange to assign this since we dont take the BindAccessLock anymore.
//
// Device->Bindings = BindingArray;
SET_VALUE(Device->Bindings, BindingArray);
Device->MaxBindings = (USHORT)NewSize - EXTRA_BINDINGS;
return STATUS_SUCCESS;
}
#endif _PNP_POWER