mirror of https://github.com/lianthony/NT4.0
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.
2463 lines
62 KiB
2463 lines
62 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
initpnp.c
|
|
|
|
Abstract:
|
|
|
|
NDIS wrapper functions initializing drivers.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (jameelh) 11-Aug-1995
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#include <stdarg.h>
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_INITPNP
|
|
|
|
NDIS_STATUS
|
|
ndisInitializeAllAdapterInstances(
|
|
IN PNDIS_MAC_BLOCK MacBlock,
|
|
IN PNDIS_STRING DeviceInstance OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the driver registry bindings and calls add adapter for each one.
|
|
|
|
Arguments:
|
|
|
|
MacBlock - Pointer to NDIS_MAC_BLOCK allocated for this Mac.
|
|
or NDIS_M_DRIVER_BLOCK for the miniport.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Number of adapters added successfully
|
|
//
|
|
UINT i, AdaptersAdded = 0;
|
|
|
|
//
|
|
// Status of registry requests.
|
|
//
|
|
NTSTATUS RegistryStatus;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// These hold the REG_MULTI_SZ read from "Bind"
|
|
//
|
|
PWSTR BindData, ExportData, RouteData;
|
|
|
|
//
|
|
// These hold our place in the REG_MULTI_SZ read for "Bind".
|
|
//
|
|
PWSTR CurBind, CurExport, CurRoute;
|
|
|
|
//
|
|
// The path to our configuration data.
|
|
//
|
|
PUNICODE_STRING BaseNameString;
|
|
|
|
//
|
|
// Used to instruct RtlQueryRegistryValues to read the
|
|
// Linkage\Bind and Linkage\Export keys
|
|
//
|
|
RTL_QUERY_REGISTRY_TABLE LQueryTable[5];
|
|
|
|
PNDIS_M_DRIVER_BLOCK MiniBlock;
|
|
|
|
UNICODE_STRING BindString, ExportString, RouteString;
|
|
UNICODE_STRING InstanceString;
|
|
PWCHAR pPath, BaseFileName;
|
|
USHORT Len;
|
|
UINT Instances = 0;
|
|
|
|
MiniBlock = (PNDIS_M_DRIVER_BLOCK)MacBlock;
|
|
|
|
//
|
|
// Set up LQueryTable to do the following:
|
|
//
|
|
|
|
//
|
|
// 1) Switch to the Linkage key below this driver's key
|
|
//
|
|
LQueryTable[0].QueryRoutine = NULL;
|
|
LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
|
LQueryTable[0].Name = L"Linkage";
|
|
|
|
//
|
|
// 2) Call ndisSaveLinkage for "Bind" (as a single multi-string),
|
|
// which will allocate storage and save the data in BindData.
|
|
//
|
|
LQueryTable[1].QueryRoutine = ndisSaveLinkage;
|
|
LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LQueryTable[1].Name = L"Bind";
|
|
LQueryTable[1].EntryContext = (PVOID)&BindData;
|
|
LQueryTable[1].DefaultType = REG_NONE;
|
|
|
|
//
|
|
// 3) Call ndisSaveLinkage for "Export" (as a single multi-string),
|
|
// which will allocate storage and save the data in BindData.
|
|
//
|
|
LQueryTable[2].QueryRoutine = ndisSaveLinkage;
|
|
LQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LQueryTable[2].Name = L"Export";
|
|
LQueryTable[2].EntryContext = (PVOID)&ExportData;
|
|
LQueryTable[2].DefaultType = REG_NONE;
|
|
|
|
//
|
|
// 4) Call ndisSaveLinkage for "Route" (as a single multi-string),
|
|
// which will allocate storage and save the data in BindData.
|
|
//
|
|
LQueryTable[3].QueryRoutine = ndisSaveLinkage;
|
|
LQueryTable[3].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LQueryTable[3].Name = L"Route";
|
|
LQueryTable[3].EntryContext = (PVOID)&RouteData;
|
|
LQueryTable[3].DefaultType = REG_NONE;
|
|
|
|
//
|
|
// 5) Stop
|
|
//
|
|
LQueryTable[4].QueryRoutine = NULL;
|
|
LQueryTable[4].Flags = 0;
|
|
LQueryTable[4].Name = NULL;
|
|
|
|
|
|
//
|
|
// Allocate room for a null-terminated version of the config path
|
|
//
|
|
if ((MiniBlock->MiniportIdField == (NDIS_HANDLE)0x01))
|
|
{
|
|
BaseNameString = &MiniBlock->BaseName;
|
|
}
|
|
else
|
|
{
|
|
BaseNameString = &MacBlock->BaseName;
|
|
}
|
|
|
|
BindData = NULL;
|
|
RouteData = NULL;
|
|
ExportData = NULL;
|
|
|
|
RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
|
|
BaseNameString->Buffer,
|
|
LQueryTable,
|
|
(PVOID)NULL, // no context needed
|
|
NULL);
|
|
|
|
do
|
|
{
|
|
if (!NT_SUCCESS(RegistryStatus))
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("Could not read Bind for %Z: %lx\n",
|
|
BaseNameString, RegistryStatus));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// For each binding, initiate loading the driver
|
|
//
|
|
|
|
for (CurBind = BindData, CurExport = ExportData, CurRoute = RouteData;
|
|
*CurBind != 0;
|
|
CurBind = (PWCHAR)((PUCHAR)CurBind + BindString.MaximumLength),
|
|
CurExport = (PWCHAR)((PUCHAR)CurExport + ExportString.MaximumLength),
|
|
CurRoute = (PWCHAR)((PUCHAR)CurRoute + RouteString.MaximumLength))
|
|
{
|
|
RtlInitUnicodeString (&BindString, CurBind);
|
|
RtlInitUnicodeString (&ExportString, CurExport);
|
|
RtlInitUnicodeString (&RouteString, CurRoute);
|
|
|
|
Len = BindString.Length / sizeof(WCHAR);
|
|
pPath = BindString.Buffer + Len - 1;
|
|
|
|
//
|
|
// CurBindString is of the form '\Device\<DriverName><DriverInstance>
|
|
// e.g. \Device\Lance1.
|
|
// Get basename ("Lance1" in this example) from this and call
|
|
// ndisInitializeAdapter() to do the rest
|
|
//
|
|
BaseFileName = BindString.Buffer;
|
|
|
|
for (i = Len; i > 0; i--, pPath--)
|
|
{
|
|
//
|
|
// If pPath points to a directory separator, set fileBaseName to
|
|
// the character after the separator.
|
|
//
|
|
|
|
if (*pPath == OBJ_NAME_PATH_SEPARATOR)
|
|
{
|
|
BaseFileName = pPath + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RtlInitUnicodeString(&InstanceString, BaseFileName);
|
|
if ((DeviceInstance == NULL) ||
|
|
NDIS_EQUAL_UNICODE_STRING(DeviceInstance, &InstanceString))
|
|
{
|
|
Status = ndisUpdateDriverInstance(&InstanceString,
|
|
&BindString,
|
|
&ExportString,
|
|
&RouteString);
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Status = ndisInitializeAdapter(MiniBlock, &InstanceString);
|
|
if (NDIS_STATUS_SUCCESS == Status)
|
|
{
|
|
++Instances;
|
|
|
|
//
|
|
// Set the next available processor for the next
|
|
// NIC to use.
|
|
//
|
|
if (0 == ndisCurrentProcessor--)
|
|
{
|
|
ndisCurrentProcessor = ndisMaximumProcessor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (BindData != NULL)
|
|
FREE_POOL(BindData);
|
|
if (ExportData != NULL)
|
|
FREE_POOL(ExportData);
|
|
if (RouteData != NULL)
|
|
FREE_POOL(RouteData);
|
|
|
|
return ((Instances > 0) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisInitializeAdapter(
|
|
IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
|
|
IN PUNICODE_STRING ServiceName // Relative to Services key
|
|
)
|
|
{
|
|
PNDIS_MAC_BLOCK pMacBlock;
|
|
NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
|
|
#define PQueryTable ConfigurationHandle.ParametersQueryTable
|
|
#define Db ConfigurationHandle.Db
|
|
NDIS_CONFIGURATION_HANDLE TmpConfigHandle;
|
|
NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
|
|
NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber");
|
|
NDIS_STRING SlotNumberStr = NDIS_STRING_CONST("SlotNumber");
|
|
NDIS_STRING PcmciaStr = NDIS_STRING_CONST("Pcmcia");
|
|
NDIS_STRING PciIdStr = NDIS_STRING_CONST("AdapterCFID");
|
|
NDIS_STRING EisaIdStr = NDIS_STRING_CONST("EisaCompressedId");
|
|
NDIS_STRING McaIdStr = NDIS_STRING_CONST("McaPosId");
|
|
PWSTR Bind = NULL, Export = NULL;
|
|
UNICODE_STRING ExportName, ParmPath;
|
|
NDIS_STATUS NdisStatus;
|
|
NTSTATUS RegistryStatus;
|
|
BOOLEAN IsAMiniport, LayeredDriver, Pcmcia = FALSE;
|
|
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
|
|
#define LQueryTable ConfigurationHandle.ParametersQueryTable
|
|
|
|
do
|
|
{
|
|
pMacBlock = (PNDIS_MAC_BLOCK)pMiniBlock;
|
|
IsAMiniport = (pMiniBlock->MiniportIdField == (NDIS_HANDLE)0x01);
|
|
|
|
//
|
|
// Set up LQueryTable to do the following:
|
|
//
|
|
|
|
//
|
|
// 1.
|
|
// Switch to the Linkage key below this driver instance key
|
|
//
|
|
|
|
LQueryTable[0].QueryRoutine = NULL;
|
|
LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
|
LQueryTable[0].Name = L"Linkage";
|
|
|
|
//
|
|
// 2.
|
|
// Call ndisSaveLinkage for "Bind" (as a single multi-string),
|
|
// which will allocate storage and save the data in Bind.
|
|
//
|
|
|
|
LQueryTable[1].QueryRoutine = ndisSaveLinkage;
|
|
LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LQueryTable[1].Name = L"Bind";
|
|
LQueryTable[1].EntryContext = (PVOID)&Bind;
|
|
LQueryTable[1].DefaultType = REG_NONE;
|
|
|
|
//
|
|
// 3.
|
|
// Call ndisSaveLinkage for "Export" (as a single multi-string)
|
|
// which will allocate storage and save the data in Export.
|
|
//
|
|
|
|
LQueryTable[2].QueryRoutine = ndisSaveLinkage;
|
|
LQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LQueryTable[2].Name = L"Export";
|
|
LQueryTable[2].EntryContext = (PVOID)&Export;
|
|
LQueryTable[2].DefaultType = REG_NONE;
|
|
|
|
//
|
|
// 4.
|
|
// Call ndisCheckRoute for "Route" (as a single multi-string)
|
|
// which will set LayeredDriver to TRUE for a layered driver (this
|
|
// is optional, the default is FALSE).
|
|
//
|
|
|
|
LQueryTable[3].QueryRoutine = ndisCheckRoute;
|
|
LQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LQueryTable[3].Name = L"Route";
|
|
LQueryTable[3].EntryContext = (PVOID)&LayeredDriver;
|
|
LQueryTable[3].DefaultType = REG_NONE;
|
|
|
|
LayeredDriver = FALSE;
|
|
|
|
//
|
|
// 5.
|
|
// Stop
|
|
//
|
|
|
|
LQueryTable[4].QueryRoutine = NULL;
|
|
LQueryTable[4].Flags = 0;
|
|
LQueryTable[4].Name = NULL;
|
|
|
|
LayeredDriver = FALSE;
|
|
ParmPath.Buffer = NULL;
|
|
|
|
RegistryStatus = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
|
|
ServiceName->Buffer,
|
|
LQueryTable,
|
|
(PVOID)NULL, // no context needed
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(RegistryStatus))
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("Could not read Bind/Export/Route for %Z: %lx\n",
|
|
IsAMiniport ?
|
|
pMiniBlock->BaseName.Buffer :
|
|
pMacBlock->BaseName.Buffer,
|
|
RegistryStatus));
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// NdisReadConfiguration assumes that ParametersQueryTable[3].Name is
|
|
// a key below the services key where the Parameters should be read,
|
|
// for layered drivers we store the last piece of Configuration
|
|
// Path there, leading to the desired effect.
|
|
//
|
|
// I.e, ConfigurationPath == "...\Services\Driver".
|
|
//
|
|
// For a layered driver, ParameterQueryTable[3].Name is "Driver"
|
|
// for all calls to AddAdapter, and parameters are read from
|
|
// "...\Services\Driver\Parameters" for all calls.
|
|
//
|
|
// For a non-layered driver, ParametersQueryTable[3].Name might be
|
|
// "Driver1" for the first call to AddAdapter, "Driver2" for the
|
|
// second, etc., and parameters are read from
|
|
// "..\Services\Driver1\Parameters" for the first call to
|
|
// AddAdapter, "...\Services\Driver2\Parameters" for the second
|
|
// call, etc.
|
|
//
|
|
// Set up ParametersQueryTable. We set most of it up here,
|
|
// then call the MAC's AddAdapter (or Miniport's Initialize)
|
|
// routine with its address
|
|
// as a ConfigContext. Inside ReadConfiguration, we get
|
|
// the ConfigContext back and can then finish initializing
|
|
// the table and use RtlQueryRegistryValues (with a
|
|
// callback to ndisSaveParameter) to read the value
|
|
// specified.
|
|
//
|
|
|
|
//
|
|
// 1.
|
|
// Allocate space for the string "DriverInstance\Parameters" which is passed as a
|
|
// parameter to RtlQueryRegistryValues. Construct this string in that buffer and
|
|
// setup PQueryTable[3].
|
|
//
|
|
RtlInitUnicodeString(&ExportName, L"\\Parameters");
|
|
ParmPath.MaximumLength = ServiceName->Length + ExportName.Length + sizeof(WCHAR);
|
|
ParmPath.Length = 0;
|
|
if ((ParmPath.Buffer = (PWSTR)ALLOC_FROM_POOL(ParmPath.MaximumLength, NDIS_TAG_NAME_BUF)) == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
|
|
("Could not read allocate space for path to parameters\n"));
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
RtlCopyUnicodeString(&ParmPath, ServiceName);
|
|
RtlAppendUnicodeStringToString(&ParmPath, &ExportName);
|
|
|
|
//
|
|
// 2) Call ndisSaveParameter for a parameter, which
|
|
// will allocate storage for it.
|
|
//
|
|
// ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext
|
|
// are filled in inside ReadConfiguration, in preparation
|
|
// for the callback.
|
|
//
|
|
|
|
PQueryTable[0].QueryRoutine = ndisSaveParameters;
|
|
PQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
PQueryTable[0].DefaultType = REG_NONE;
|
|
//
|
|
// The following fields are filled in during NdisReadConfiguration
|
|
//
|
|
// PQueryTable[0].Name = KeywordBuffer;
|
|
// PQueryTable[0].EntryContext = ParameterValue;
|
|
|
|
//
|
|
// 3.
|
|
// Stop
|
|
//
|
|
|
|
PQueryTable[1].QueryRoutine = NULL;
|
|
PQueryTable[1].Flags = 0;
|
|
PQueryTable[1].Name = NULL;
|
|
|
|
//
|
|
// NOTE: Some fields in ParametersQueryTable[3 & 4] are used to
|
|
// store information for later retrieval.
|
|
//
|
|
PQueryTable[3].QueryRoutine = NULL;
|
|
PQueryTable[3].Name = ParmPath.Buffer;
|
|
PQueryTable[3].EntryContext = NULL;
|
|
PQueryTable[3].DefaultData = NULL;
|
|
|
|
//
|
|
// Save the driver name here; later we will use this as
|
|
// a parameter to RtlQueryRegistryValues.
|
|
//
|
|
if (LayeredDriver)
|
|
{
|
|
//
|
|
// This will be returned by NdisReadBindingInformation.
|
|
//
|
|
PQueryTable[3].EntryContext = Bind;
|
|
}
|
|
|
|
// Now read bustype/busnumber for this adapter and save it
|
|
TmpConfigHandle.KeyQueryTable = PQueryTable;
|
|
TmpConfigHandle.ParameterList = NULL;
|
|
|
|
Db.BusNumber = (ULONG)(-1);
|
|
Db.BusType = (NDIS_INTERFACE_TYPE)(-1);
|
|
Db.SlotNumber = (ULONG)(-1);
|
|
Db.BusId = 0;
|
|
|
|
//
|
|
// Read Bus Number
|
|
//
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&BusNumberStr,
|
|
NdisParameterInteger);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Db.BusNumber = ReturnedValue->ParameterData.IntegerData;
|
|
}
|
|
|
|
//
|
|
// Read Slot Number
|
|
//
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&SlotNumberStr,
|
|
NdisParameterInteger);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Db.SlotNumber = ReturnedValue->ParameterData.IntegerData;
|
|
}
|
|
|
|
//
|
|
// Read Bus Type
|
|
//
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&BusTypeStr,
|
|
NdisParameterInteger);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Db.BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData);
|
|
if (Db.BusType == NdisInterfacePcMcia)
|
|
Db.BusType = NdisInterfaceIsa; // Fix the folks who chose Pcmcia
|
|
|
|
//
|
|
// Now read the bus-id for Pci/Mca/Eisa
|
|
//
|
|
switch (Db.BusType)
|
|
{
|
|
case NdisInterfaceEisa:
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&EisaIdStr,
|
|
NdisParameterInteger);
|
|
break;
|
|
case NdisInterfaceMca:
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&McaIdStr,
|
|
NdisParameterInteger);
|
|
break;
|
|
case NdisInterfacePci:
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&PciIdStr,
|
|
NdisParameterInteger);
|
|
break;
|
|
}
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Db.BusId = ReturnedValue->ParameterData.IntegerData;
|
|
}
|
|
}
|
|
|
|
if (Db.BusId != 0)
|
|
{
|
|
switch (Db.BusType)
|
|
{
|
|
case NdisInterfaceEisa:
|
|
case NdisInterfaceMca:
|
|
case NdisInterfacePci:
|
|
NdisStatus = ndisFixBusInformation(&TmpConfigHandle, &Db);
|
|
break;
|
|
default:
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if this is pcmcia ?
|
|
//
|
|
NdisReadConfiguration(&NdisStatus,
|
|
&ReturnedValue,
|
|
&TmpConfigHandle,
|
|
&PcmciaStr,
|
|
NdisParameterInteger);
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Pcmcia = (ReturnedValue->ParameterData.IntegerData != 0);
|
|
}
|
|
|
|
if (Pcmcia)
|
|
{
|
|
NdisStatus = ndisCheckIfPcmciaCardPresent(pMiniBlock);
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
PQueryTable[3].DefaultType = Db.BusType;
|
|
PQueryTable[3].DefaultLength = Db.BusNumber;
|
|
PQueryTable[3].DefaultData = NULL;
|
|
PQueryTable[3].Flags = 0;
|
|
|
|
PQueryTable[4].DefaultLength = Db.SlotNumber;
|
|
|
|
//
|
|
// OK, Now lock down all the filter packages. If a MAC or
|
|
// Miniport driver uses any of these, then the filter package
|
|
// will reference itself, to keep the image in memory.
|
|
//
|
|
ArcReferencePackage();
|
|
EthReferencePackage();
|
|
FddiReferencePackage();
|
|
TrReferencePackage();
|
|
MiniportReferencePackage();
|
|
MacReferencePackage();
|
|
CoReferencePackage();
|
|
|
|
RtlInitUnicodeString (&ExportName, Export);
|
|
ConfigurationHandle.DriverBaseName = ServiceName;
|
|
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
if (IsAMiniport)
|
|
{
|
|
NdisStatus = ndisMInitializeAdapter(pMiniBlock,
|
|
&ConfigurationHandle,
|
|
&ExportName,
|
|
&Db);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Save the Driver Object with the Configuration Handle.
|
|
//
|
|
ConfigurationHandle.DriverObject = pMacBlock->NdisMacInfo->NdisWrapperDriver;
|
|
|
|
//
|
|
// NDIS 3.0 MAC
|
|
//
|
|
NdisStatus = (pMacBlock->MacCharacteristics.AddAdapterHandler)(pMacBlock->MacMacContext,
|
|
&ConfigurationHandle,
|
|
&ExportName);
|
|
//
|
|
// Free the slot information buffer
|
|
//
|
|
if (PQueryTable[3].DefaultData != NULL)
|
|
{
|
|
FREE_POOL(PQueryTable[3].DefaultData);
|
|
}
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Update the Db from the Config context
|
|
//
|
|
Db.SlotNumber= PQueryTable[4].DefaultLength;
|
|
Db.BusNumber = PQueryTable[3].DefaultLength;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the initialization failed, cleanup
|
|
//
|
|
if ((NdisStatus != NDIS_STATUS_SUCCESS) && (Db.BusId != 0))
|
|
{
|
|
ndisDeleteGlobalDb(Db.BusType,
|
|
Db.BusId,
|
|
Db.BusNumber,
|
|
Db.SlotNumber);
|
|
}
|
|
else if ((NdisStatus == NDIS_STATUS_SUCCESS) &&
|
|
(Db.BusId == 0))
|
|
{
|
|
//
|
|
// If this adapter did not have a bus-id in the registry,
|
|
// do it a favor and write it.
|
|
//
|
|
switch (Db.BusType)
|
|
{
|
|
case NdisInterfaceEisa:
|
|
case NdisInterfaceMca:
|
|
case NdisInterfacePci:
|
|
ndisAddBusInformation(&TmpConfigHandle, &Db);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// OK, Now dereference all the filter packages. If a MAC or
|
|
// Miniport driver uses any of these, then the filter package
|
|
// will reference itself, to keep the image in memory.
|
|
//
|
|
ArcDereferencePackage();
|
|
EthDereferencePackage();
|
|
FddiDereferencePackage();
|
|
TrDereferencePackage();
|
|
MiniportDereferencePackage();
|
|
MacDereferencePackage();
|
|
CoDereferencePackage();
|
|
|
|
} while (FALSE);
|
|
|
|
if (ParmPath.Buffer != NULL)
|
|
{
|
|
FREE_POOL(ParmPath.Buffer);
|
|
}
|
|
|
|
if (Bind != NULL)
|
|
{
|
|
FREE_POOL(Bind);
|
|
}
|
|
|
|
if (Export != NULL)
|
|
{
|
|
FREE_POOL(Export);
|
|
}
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMInitializeAdapter(
|
|
IN PNDIS_M_DRIVER_BLOCK pMiniBlock,
|
|
IN PNDIS_WRAPPER_CONFIGURATION_HANDLE pConfigurationHandle,
|
|
IN PUNICODE_STRING pExportName,
|
|
IN PBUS_SLOT_DB pDb
|
|
)
|
|
{
|
|
BOOLEAN FreeDevice;
|
|
BOOLEAN DerefDriver;
|
|
BOOLEAN FreeBuffer;
|
|
BOOLEAN FreeArcnetLookaheadBuffer;
|
|
BOOLEAN Dequeue;
|
|
BOOLEAN ExtendedError;
|
|
BOOLEAN FreeWorkItemStorage;
|
|
BOOLEAN FreeDeferredTimer;
|
|
BOOLEAN FreePacketArray;
|
|
PDEVICE_OBJECT pTmpDevice;
|
|
NTSTATUS NtStatus;
|
|
LONG ErrorCode;
|
|
PNDIS_MINIPORT_BLOCK Miniport = NULL;
|
|
UNICODE_STRING SymbolicLink;
|
|
WCHAR SymLnkBuf[40];
|
|
NDIS_STATUS MiniportInitializeStatus = NDIS_STATUS_SUCCESS;
|
|
NDIS_STATUS OpenErrorStatus;
|
|
NDIS_STATUS NdisStatus;
|
|
|
|
UINT SelectedMediumIndex;
|
|
|
|
ULONG MaximumLongAddresses;
|
|
UCHAR CurrentLongAddress[6];
|
|
ULONG MaximumShortAddresses;
|
|
UCHAR CurrentShortAddress[2];
|
|
UINT PacketFilter;
|
|
UCHAR i;
|
|
BOOLEAN LocalLock;
|
|
PARC_BUFFER_LIST Buffer;
|
|
PVOID DataBuffer;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
|
|
//
|
|
// Initialize device.
|
|
//
|
|
if (!ndisReferenceDriver((PNDIS_M_DRIVER_BLOCK)pMiniBlock))
|
|
{
|
|
//
|
|
// The driver is closing.
|
|
//
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
//
|
|
// Initialize locals.
|
|
//
|
|
ErrorCode = 0;
|
|
FreeDevice = FALSE;
|
|
DerefDriver = FALSE;
|
|
FreeBuffer = FALSE;
|
|
FreeArcnetLookaheadBuffer = FALSE;
|
|
Dequeue = FALSE;
|
|
ExtendedError = FALSE;
|
|
FreeWorkItemStorage = FALSE;
|
|
FreeDeferredTimer = FALSE;
|
|
FreePacketArray = FALSE;
|
|
PacketFilter = 0x1;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Save the Driver Object with the configuration handle.
|
|
//
|
|
pConfigurationHandle->DriverObject = pMiniBlock->NdisDriverInfo->NdisWrapperDriver;
|
|
|
|
DerefDriver = TRUE;
|
|
NtStatus = IoCreateDevice(pMiniBlock->NdisDriverInfo->NdisWrapperDriver,
|
|
sizeof(NDIS_MINIPORT_BLOCK) +
|
|
sizeof(NDIS_WRAPPER_CONTEXT) +
|
|
pConfigurationHandle->DriverBaseName->Length,
|
|
pExportName,
|
|
FILE_DEVICE_PHYSICAL_NETCARD,
|
|
0,
|
|
FALSE, // exclusive flag
|
|
&pTmpDevice);
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
FreeDevice = TRUE;
|
|
|
|
//
|
|
// Initialize the Miniport adapter block in the device object extension
|
|
//
|
|
// *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
|
|
// NDIS_MINIPORT_BLOCK, so we put it first in the extension.
|
|
//
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)pTmpDevice->DeviceExtension + 1);
|
|
ZeroMemory(Miniport, sizeof(PNDIS_MINIPORT_BLOCK));
|
|
|
|
//
|
|
// Setup debug information if needed.
|
|
//
|
|
ndisMInitializeDebugInformation(Miniport);
|
|
|
|
Miniport->WrapperContext = pTmpDevice->DeviceExtension;
|
|
Miniport->BaseName.Buffer = (PWSTR)((PUCHAR)Miniport + sizeof(NDIS_MINIPORT_BLOCK));
|
|
Miniport->BaseName.MaximumLength =
|
|
Miniport->BaseName.Length = pConfigurationHandle->DriverBaseName->Length;
|
|
RtlUpcaseUnicodeString(&Miniport->BaseName,
|
|
pConfigurationHandle->DriverBaseName,
|
|
FALSE);
|
|
|
|
//
|
|
// Create symbolic link for the device
|
|
//
|
|
SymbolicLink.Buffer = SymLnkBuf;
|
|
SymbolicLink.Length = sizeof(L"\\DosDevices\\") - sizeof(WCHAR);
|
|
SymbolicLink.MaximumLength = sizeof(SymLnkBuf);
|
|
RtlCopyMemory(SymLnkBuf, L"\\DosDevices\\", sizeof(L"\\DosDevices\\"));
|
|
RtlAppendUnicodeStringToString(&SymbolicLink, &Miniport->BaseName);
|
|
IoCreateSymbolicLink(&SymbolicLink, pExportName);
|
|
|
|
Miniport->BusType = pDb->BusType;
|
|
Miniport->BusId = pDb->BusId;
|
|
Miniport->SlotNumber = pDb->SlotNumber;
|
|
Miniport->BusNumber = pDb->BusNumber;
|
|
Miniport->DeviceObject = pTmpDevice;
|
|
Miniport->DriverHandle = pMiniBlock;
|
|
Miniport->MiniportName.Buffer = (PWSTR)ALLOC_FROM_POOL(pExportName->MaximumLength,
|
|
NDIS_TAG_NAME_BUF);
|
|
if (Miniport->MiniportName.Buffer == NULL)
|
|
{
|
|
break;
|
|
}
|
|
FreeBuffer = TRUE;
|
|
|
|
Miniport->MiniportName.MaximumLength = pExportName->MaximumLength;
|
|
Miniport->MiniportName.Length = pExportName->Length;
|
|
|
|
CopyMemory(Miniport->MiniportName.Buffer,
|
|
pExportName->Buffer,
|
|
pExportName->MaximumLength);
|
|
|
|
Miniport->AssignedProcessor = ndisValidProcessors[ndisCurrentProcessor];
|
|
Miniport->SendResourcesAvailable = 0x00FFFFFF;
|
|
NdisAllocateSpinLock(&Miniport->Lock);
|
|
|
|
// Start off with the null filter
|
|
Miniport->PacketIndicateHandler = ndisMIndicatePacket;
|
|
|
|
//
|
|
// Initialize the handlers to non-full duplex
|
|
//
|
|
Miniport->ProcessDeferredHandler = ndisMProcessDeferred;
|
|
Miniport->QueueWorkItemHandler = ndisMQueueWorkItem;
|
|
Miniport->QueueNewWorkItemHandler = ndisMQueueNewWorkItem;
|
|
Miniport->DeQueueWorkItemHandler = ndisMDeQueueWorkItem;
|
|
|
|
Miniport->SendCompleteHandler = NdisMSendComplete;
|
|
Miniport->SendResourcesHandler = NdisMSendResourcesAvailable;
|
|
Miniport->ResetCompleteHandler = NdisMResetComplete;
|
|
|
|
//
|
|
// And optimize Dpc/Isr stuff
|
|
//
|
|
Miniport->HandleInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
|
|
Miniport->DisableInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.DisableInterruptHandler;
|
|
Miniport->EnableInterruptHandler = Miniport->DriverHandle->MiniportCharacteristics.EnableInterruptHandler;
|
|
Miniport->DeferredSendHandler = ndisMStartSends;
|
|
|
|
//
|
|
// Set some flags describing the miniport.
|
|
//
|
|
if (pMiniBlock->MiniportCharacteristics.MajorNdisVersion == 4)
|
|
{
|
|
if (pMiniBlock->MiniportCharacteristics.MinorNdisVersion >= 0)
|
|
{
|
|
//
|
|
// This is an NDIS 4.0 miniport.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IS_NDIS_4_0);
|
|
|
|
//
|
|
// Does this miniport indicate packets?
|
|
//
|
|
if (pMiniBlock->MiniportCharacteristics.ReturnPacketHandler)
|
|
{
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_INDICATES_PACKETS);
|
|
}
|
|
|
|
//
|
|
// Can this miniport handle multiple sends?
|
|
//
|
|
if (pMiniBlock->MiniportCharacteristics.SendPacketsHandler)
|
|
{
|
|
MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY);
|
|
Miniport->DeferredSendHandler = ndisMStartSendPackets;
|
|
}
|
|
}
|
|
|
|
if (pMiniBlock->MiniportCharacteristics.MinorNdisVersion == 1)
|
|
{
|
|
//
|
|
// This is an NDIS 4.1 miniport.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, (fMINIPORT_IS_NDIS_4_1 | fMINIPORT_INDICATES_PACKETS));
|
|
if (pMiniBlock->MiniportCharacteristics.CoCreateVcHandler != NULL)
|
|
{
|
|
//
|
|
// This is a connection-oriented miniport.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IS_CO);
|
|
}
|
|
}
|
|
}
|
|
|
|
NdisInitializeRef(&Miniport->Ref);
|
|
|
|
INITIALIZE_DPC(&Miniport->Dpc,
|
|
(Miniport->Flags & fMINIPORT_IS_CO) ?
|
|
ndisMCoDpcTimer : ndisMDpcTimer,
|
|
Miniport);
|
|
|
|
Miniport->CheckForHangTimeout = 2000;
|
|
NdisInitializeTimer(&Miniport->WakeUpDpcTimer, ndisMWakeUpDpc, Miniport);
|
|
|
|
//
|
|
// Allocate a pool of work items to start with.
|
|
//
|
|
for (i = 0, WorkItem = NULL; i < 10; i++)
|
|
{
|
|
//
|
|
// Allocate a work item.
|
|
//
|
|
WorkItem = ALLOC_FROM_POOL(sizeof(NDIS_MINIPORT_WORK_ITEM), NDIS_TAG_WORK_ITEM);
|
|
if (NULL == WorkItem)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize the work item.
|
|
//
|
|
NdisZeroMemory(WorkItem, sizeof(NDIS_MINIPORT_WORK_ITEM));
|
|
|
|
//
|
|
// Place the work item on the free queue.
|
|
//
|
|
PushEntryList(&Miniport->WorkItemFreeQueue, &WorkItem->Link);
|
|
}
|
|
|
|
//
|
|
// Did we get work items allocate?
|
|
//
|
|
if (Miniport->WorkItemFreeQueue.Next != NULL)
|
|
{
|
|
FreeWorkItemStorage = TRUE;
|
|
}
|
|
|
|
//
|
|
// Did we get enough work items allocated?
|
|
// WorkItem will be NULL if we failed to allocate
|
|
// one of them.
|
|
//
|
|
if (NULL == WorkItem)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set up the list of workitems that only require one
|
|
// workitem at any given time.
|
|
//
|
|
for (i = 0; i < NUMBER_OF_SINGLE_WORK_ITEMS; i++)
|
|
{
|
|
Link = PopEntryList(&Miniport->WorkItemFreeQueue);
|
|
PushEntryList(&Miniport->SingleWorkItems[i], Link);
|
|
}
|
|
|
|
//
|
|
// Enqueue the miniport on the driver block.
|
|
//
|
|
if (!ndisQueueMiniportOnDriver(Miniport, pMiniBlock))
|
|
{
|
|
//
|
|
// The Driver is closing, undo what we have done.
|
|
//
|
|
break;
|
|
}
|
|
Dequeue = TRUE;
|
|
|
|
//
|
|
// Allocate memory for a timer structure.
|
|
//
|
|
Miniport->DeferredTimer = ALLOC_FROM_POOL(sizeof(NDIS_TIMER), NDIS_TAG_DFRD_TMR);
|
|
ASSERT(Miniport->DeferredTimer != NULL);
|
|
if (NULL == Miniport->DeferredTimer)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Failed to allocate memory for the full-duplex timer.\n"));
|
|
break;
|
|
}
|
|
|
|
FreeDeferredTimer = TRUE;
|
|
|
|
//
|
|
// Initialize the timer with the
|
|
//
|
|
NdisInitializeTimer(Miniport->DeferredTimer,
|
|
(PVOID)ndisMDeferredTimerDpc,
|
|
(PVOID)Miniport);
|
|
|
|
//
|
|
// Initialize work-item for returning orphaned packets
|
|
//
|
|
INITIALIZE_WORK_ITEM(&Miniport->WorkItem, ndisMLazyReturnPackets, Miniport);
|
|
|
|
//
|
|
// Now we do something really bogus. We create many
|
|
// temporary filter databases, just in case any indications
|
|
// happen.
|
|
//
|
|
|
|
if (!EthCreateFilter(1,
|
|
ndisMChangeEthAddresses,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
&Miniport->Lock,
|
|
&(Miniport->EthDB)) ||
|
|
!TrCreateFilter(ndisMChangeFunctionalAddress,
|
|
ndisMChangeGroupAddress,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
&Miniport->Lock,
|
|
&(Miniport->TrDB)) ||
|
|
!FddiCreateFilter(1,
|
|
1,
|
|
ndisMChangeFddiAddresses,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
CurrentShortAddress,
|
|
&Miniport->Lock,
|
|
&(Miniport->FddiDB)) ||
|
|
!ArcCreateFilter(Miniport,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress[0],
|
|
&Miniport->Lock,
|
|
&(Miniport->ArcDB)))
|
|
{
|
|
NdisWriteErrorLogEntry(
|
|
(NDIS_HANDLE)Miniport,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
0);
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Could not create the dummy filter!\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save the miniport block with the filter libraries.
|
|
//
|
|
Miniport->EthDB->Miniport = Miniport;
|
|
Miniport->TrDB->Miniport = Miniport;
|
|
Miniport->FddiDB->Miniport = Miniport;
|
|
|
|
//
|
|
// Call adapter callback. The current value for "Export"
|
|
// is what we tell him to name this device.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
MiniportInitializeStatus =
|
|
(pMiniBlock->MiniportCharacteristics.InitializeHandler)(
|
|
&OpenErrorStatus,
|
|
&SelectedMediumIndex,
|
|
ndisMediumArray,
|
|
ndisMediumArraySize/sizeof(NDIS_MEDIUM),
|
|
(NDIS_HANDLE)(Miniport),
|
|
(NDIS_HANDLE)pConfigurationHandle);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
|
|
|
|
//
|
|
// Free the slot information buffer
|
|
//
|
|
if (pConfigurationHandle->ParametersQueryTable[3].DefaultData != NULL)
|
|
{
|
|
FREE_POOL(pConfigurationHandle->ParametersQueryTable[3].DefaultData);
|
|
}
|
|
|
|
if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Update the Db from the Miniport
|
|
//
|
|
pDb->BusNumber = Miniport->BusNumber;
|
|
pDb->SlotNumber = Miniport->SlotNumber;
|
|
|
|
ASSERT(SelectedMediumIndex < (ndisMediumArraySize/sizeof(NDIS_MEDIUM)));
|
|
|
|
Miniport->MediaType = ndisMediumArray[SelectedMediumIndex];
|
|
|
|
INITIALIZE_EVENT(&Miniport->RequestEvent);
|
|
|
|
RESET_EVENT(&Miniport->RequestEvent);
|
|
|
|
//
|
|
// Set Maximumlookahead to 0 as default. For lan media query the real
|
|
// stuff.
|
|
//
|
|
if ((Miniport->MediaType < NdisMediumMax) &&
|
|
ndisMediaTypeCl[Miniport->MediaType])
|
|
{
|
|
//
|
|
// Query maximum lookahead
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
&MaximumLongAddresses,
|
|
sizeof(MaximumLongAddresses),
|
|
0x1);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying the OID_GEN_MAXIMUM_LOOKAHEAD\n"));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now adjust based on media type
|
|
//
|
|
|
|
switch(Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_3:
|
|
|
|
Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 14) < MaximumLongAddresses) ?
|
|
NDIS_M_MAX_LOOKAHEAD - 14 :
|
|
MaximumLongAddresses;
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
|
|
Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 32) < MaximumLongAddresses) ?
|
|
(NDIS_M_MAX_LOOKAHEAD - 32) :
|
|
MaximumLongAddresses;
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 16) < MaximumLongAddresses) ?
|
|
(NDIS_M_MAX_LOOKAHEAD - 16) :
|
|
MaximumLongAddresses;
|
|
break;
|
|
|
|
case NdisMediumArcnet878_2:
|
|
Miniport->MaximumLookahead = ((NDIS_M_MAX_LOOKAHEAD - 50) < MaximumLongAddresses) ?
|
|
NDIS_M_MAX_LOOKAHEAD - 50 :
|
|
MaximumLongAddresses;
|
|
|
|
//
|
|
// Assume we will succeed with the lookahead allocation.
|
|
//
|
|
ExtendedError = FALSE;
|
|
|
|
//
|
|
// allocate a lookahead buffer for arcnet.
|
|
//
|
|
Miniport->ArcnetLookaheadBuffer = ALLOC_FROM_POOL(
|
|
NDIS_M_MAX_LOOKAHEAD,
|
|
NDIS_TAG_LA_BUF);
|
|
|
|
ASSERT(Miniport->ArcnetLookaheadBuffer != NULL);
|
|
if (Miniport->ArcnetLookaheadBuffer == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Could not allocate arcnet lookahead buffer\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
}
|
|
else
|
|
{
|
|
FreeArcnetLookaheadBuffer = TRUE;
|
|
|
|
NdisZeroMemory(Miniport->ArcnetLookaheadBuffer,
|
|
Miniport->MaximumLookahead);
|
|
}
|
|
|
|
break;
|
|
|
|
case NdisMediumWan:
|
|
Miniport->MaximumLookahead = 1514;
|
|
break;
|
|
|
|
case NdisMediumIrda:
|
|
case NdisMediumWirelessWan:
|
|
case NdisMediumLocalTalk:
|
|
Miniport->MaximumLookahead = MaximumLongAddresses;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Was there an error?
|
|
//
|
|
if (ExtendedError)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Extended error when processing OID_GEN_MAXIMUM_LOOOKAHEAD\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set MacOptions to 0 as default. For lan media query the real
|
|
// stuff. We also need to call this for lan drivers.
|
|
//
|
|
Miniport->MacOptions = 0;
|
|
if (((Miniport->MediaType < NdisMediumMax) &&
|
|
ndisMediaTypeCl[Miniport->MediaType]) ||
|
|
(NdisMediumWan == Miniport->MediaType))
|
|
{
|
|
//
|
|
// Query mac options
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_GEN_MAC_OPTIONS,
|
|
&MaximumLongAddresses,
|
|
sizeof(MaximumLongAddresses),
|
|
0x3);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_GEN_MAC_OPTIONS\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
Miniport->MacOptions = (UINT)MaximumLongAddresses;
|
|
}
|
|
else
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// We can't call process deferred at a low irql and
|
|
// we need to get the local lock.
|
|
//
|
|
RAISE_IRQL_TO_DISPATCH(&OldIrql);
|
|
BLOCK_LOCK_MINIPORT_DPC(Miniport, LocalLock);
|
|
|
|
//
|
|
// Queue a dpc to fire.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Miniport->Dpc, NULL);
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
LOWER_IRQL(OldIrql);
|
|
}
|
|
|
|
//
|
|
// This is a full duplex driver if the miniport says it is
|
|
// and they say they are going to handle loopback and the
|
|
// number of system processors is more than one.
|
|
//
|
|
if (((Miniport->MacOptions & NDIS_MAC_OPTION_FULL_DUPLEX) &&
|
|
(NdisSystemProcessorCount() > 1))
|
|
||
|
|
MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
|
|
{
|
|
//
|
|
// Allocate a workitem lock.
|
|
//
|
|
INITIALIZE_SPIN_LOCK(&Miniport->WorkLock);
|
|
|
|
//
|
|
// Is this an intermediate driver?
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
|
|
{
|
|
Miniport->ProcessDeferredHandler = ndisMProcessDeferredFullDuplex;
|
|
Miniport->QueueWorkItemHandler = ndisIMQueueWorkItem;
|
|
Miniport->QueueNewWorkItemHandler = ndisIMQueueNewWorkItem;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Regular full-duplex miniport.
|
|
//
|
|
Miniport->ProcessDeferredHandler = ndisMProcessDeferredFullDuplex;
|
|
Miniport->QueueWorkItemHandler = ndisMQueueWorkItemFullDuplex;
|
|
Miniport->QueueNewWorkItemHandler = ndisMQueueNewWorkItemFullDuplex;
|
|
}
|
|
|
|
//
|
|
// Allocate a separate spin lock for the send path.
|
|
//
|
|
NdisAllocateSpinLock(&Miniport->SendLock);
|
|
|
|
//
|
|
// Use the full duplex send complete and resources
|
|
// available handler.
|
|
//
|
|
Miniport->SendCompleteHandler = ndisMSendCompleteFullDuplex;
|
|
Miniport->SendResourcesHandler = ndisMSendResourcesAvailableFullDuplex;
|
|
Miniport->ResetCompleteHandler = ndisMResetCompleteFullDuplex;
|
|
|
|
//
|
|
// Do we need a send packets handler or a send handler?
|
|
//
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
|
|
{
|
|
Miniport->DeferredSendHandler = ndisMStartSendPacketsFullDuplex;
|
|
}
|
|
else
|
|
{
|
|
Miniport->DeferredSendHandler = ndisMStartSendsFullDuplex;
|
|
}
|
|
|
|
//
|
|
// Set the full duplex flag.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_FULL_DUPLEX);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Make sure this is clear if something doesn't match.
|
|
//
|
|
Miniport->MacOptions &= ~NDIS_MAC_OPTION_FULL_DUPLEX;
|
|
}
|
|
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
|
|
{
|
|
//
|
|
// If this is a NDIS 4.0 miniport that supports the
|
|
// SendPacketsHandler then we need to query the number of
|
|
// packets that the miniport supports.
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
&MaximumLongAddresses,
|
|
sizeof(MaximumLongAddresses),
|
|
0x3);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_GEN_MAXIMUM_SEND_PACKETS\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
Miniport->MaximumSendPackets = (UINT)MaximumLongAddresses;
|
|
|
|
//
|
|
// Allocate memory for the send packet array.
|
|
//
|
|
Miniport->PacketArray = ALLOC_FROM_POOL(
|
|
sizeof(PNDIS_PACKET) * MaximumLongAddresses,
|
|
NDIS_TAG_DEFAULT);
|
|
if (NULL == Miniport->PacketArray)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(Miniport->PacketArray,
|
|
sizeof(PNDIS_PACKET) * Miniport->MaximumSendPackets);
|
|
|
|
FreePacketArray = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Create filter package
|
|
//
|
|
switch(Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_3:
|
|
|
|
//
|
|
// Query maximum MulticastAddress
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
&MaximumLongAddresses,
|
|
sizeof(MaximumLongAddresses),
|
|
0x5);
|
|
if (ErrorCode != 0)
|
|
{
|
|
ExtendedError = TRUE;
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_802_3_MAXIMUM_LIST_SIZE\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST)
|
|
{
|
|
MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
|
|
}
|
|
|
|
Miniport->MaximumLongAddresses = MaximumLongAddresses;
|
|
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
&CurrentLongAddress,
|
|
sizeof(CurrentLongAddress),
|
|
0x7);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_802_3_CURRENT_ADDRESS\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now undo the bogus filter package. We lock
|
|
// the miniport so that no dpcs will get queued.
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
ndisMUndoBogusFilters(Miniport);
|
|
|
|
if (!EthCreateFilter(MaximumLongAddresses,
|
|
ndisMChangeEthAddresses,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
&Miniport->Lock,
|
|
&Miniport->EthDB))
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error creating the Ethernet filter database\n"));
|
|
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
ErrorCode = 0x9;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save the miniport block with the filter library.
|
|
//
|
|
Miniport->EthDB->Miniport = Miniport;
|
|
|
|
// Set the indicate handler
|
|
Miniport->PacketIndicateHandler = EthFilterDprIndicateReceivePacket;
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
|
|
ErrorCode = ndisMDoMiniportOp(
|
|
Miniport,
|
|
TRUE,
|
|
OID_802_5_CURRENT_ADDRESS,
|
|
&CurrentLongAddress,
|
|
sizeof(CurrentLongAddress),
|
|
0xA);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_802_5_CURRENT_ADDRESS\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now undo the bogus filter package. We lock
|
|
// the miniport so that no dpcs will get queued.
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
ndisMUndoBogusFilters(Miniport);
|
|
|
|
if (!TrCreateFilter(
|
|
ndisMChangeFunctionalAddress,
|
|
ndisMChangeGroupAddress,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
&Miniport->Lock,
|
|
&Miniport->TrDB))
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error creating the Token Ring filter database\n"));
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
ErrorCode = 0xC;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save the miniport block with the filter library.
|
|
//
|
|
Miniport->TrDB->Miniport = Miniport;
|
|
|
|
// Set the indicate handler
|
|
Miniport->PacketIndicateHandler = TrFilterDprIndicateReceivePacket;
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
|
|
//
|
|
// Query maximum MulticastAddress
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(
|
|
Miniport,
|
|
TRUE,
|
|
OID_FDDI_LONG_MAX_LIST_SIZE,
|
|
&MaximumLongAddresses,
|
|
sizeof(MaximumLongAddresses),
|
|
0xD);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_FDDI_LONG_MAX_LIST_SIZE\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST)
|
|
{
|
|
MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
|
|
}
|
|
|
|
Miniport->MaximumLongAddresses = MaximumLongAddresses;
|
|
|
|
//
|
|
// Query maximum MulticastAddress
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_FDDI_SHORT_MAX_LIST_SIZE,
|
|
&MaximumShortAddresses,
|
|
sizeof(MaximumShortAddresses),
|
|
0xF);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_FDDI_SHORT_MAX_LIST_SIZE\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST)
|
|
{
|
|
MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST;
|
|
}
|
|
|
|
Miniport->MaximumShortAddresses = MaximumShortAddresses;
|
|
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_FDDI_LONG_CURRENT_ADDR,
|
|
&CurrentLongAddress,
|
|
sizeof(CurrentLongAddress),
|
|
0x11);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_FDDI_LONG_CURRENT_ADDR\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_FDDI_SHORT_CURRENT_ADDR,
|
|
&CurrentShortAddress,
|
|
sizeof(CurrentShortAddress),
|
|
0x13);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_FDDI_SHORT_CURRENT_ADDR\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now undo the bogus filter package. We lock
|
|
// the miniport so that no dpcs will get queued.
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
ndisMUndoBogusFilters(Miniport);
|
|
|
|
if (!FddiCreateFilter(MaximumLongAddresses,
|
|
MaximumShortAddresses,
|
|
ndisMChangeFddiAddresses,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
CurrentShortAddress,
|
|
&Miniport->Lock,
|
|
&Miniport->FddiDB))
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error creating the FDDI filter database\n"));
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
ErrorCode = 0x15;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save the miniport block with the filter library.
|
|
//
|
|
Miniport->FddiDB->Miniport = Miniport;
|
|
|
|
// Set the indicate handler
|
|
Miniport->PacketIndicateHandler = FddiFilterDprIndicateReceivePacket;
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
break;
|
|
|
|
case NdisMediumArcnet878_2:
|
|
|
|
//
|
|
// In case of an encapsulated ethernet binding, we need
|
|
// to return the maximum number of multicast addresses
|
|
// possible.
|
|
//
|
|
|
|
Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
|
|
|
|
//
|
|
// Allocate Buffer pools
|
|
//
|
|
NdisAllocateBufferPool(&NdisStatus,
|
|
&Miniport->ArcnetBufferPool,
|
|
WRAPPER_ARC_BUFFERS);
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Failed to allocate buffer pool for arcnet\n"));
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
ErrorCode = 0x16;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
NdisAllocateMemory((PVOID)&Buffer,
|
|
sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
|
|
0,
|
|
HighestAcceptableMax);
|
|
if (Buffer == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Failed to allocate memory for arcnet buffers\n"));
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NdisFreeBufferPool(Miniport->ArcnetBufferPool);
|
|
ErrorCode = 0x17;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
NdisAllocateMemory((PVOID)&DataBuffer,
|
|
WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
|
|
0,
|
|
HighestAcceptableMax);
|
|
if (DataBuffer == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Failed to allocate memory for arcnet data buffers\n"));
|
|
|
|
//
|
|
// Halt the miniport driver.
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NdisFreeMemory(
|
|
Buffer,
|
|
sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeBufferPool(Miniport->ArcnetBufferPool);
|
|
ErrorCode = 0x18;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
for (i = WRAPPER_ARC_BUFFERS; i != 0; i--)
|
|
{
|
|
Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE;
|
|
Buffer->Buffer = DataBuffer;
|
|
Buffer->Next = Miniport->ArcnetFreeBufferList;
|
|
Miniport->ArcnetFreeBufferList = Buffer;
|
|
|
|
Buffer++;
|
|
DataBuffer = (PVOID)(((PUCHAR)DataBuffer) +
|
|
WRAPPER_ARC_HEADER_SIZE);
|
|
}
|
|
|
|
//
|
|
// Get current address
|
|
//
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_ARCNET_CURRENT_ADDRESS,
|
|
&CurrentLongAddress[5], // address = 00-00-00-00-00-XX
|
|
1,
|
|
0x19);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_ARCNET_CURRENT_ADDRESS\n"));
|
|
|
|
NdisFreeMemory(Buffer,
|
|
sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeMemory(DataBuffer,
|
|
WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeBufferPool(Miniport->ArcnetBufferPool);
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
Miniport->ArcnetAddress = CurrentLongAddress[5];
|
|
|
|
//
|
|
// Now undo the bogus filter package. We lock
|
|
// the miniport so that no dpcs will get queued.
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
ndisMUndoBogusFilters(Miniport);
|
|
|
|
if (!ArcCreateFilter(Miniport,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress[5],
|
|
&Miniport->Lock,
|
|
&(Miniport->ArcDB)))
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error creating the Arcnet filter database\n"));
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NdisFreeMemory(Buffer,
|
|
sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeMemory(DataBuffer,
|
|
WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeBufferPool(Miniport->ArcnetBufferPool);
|
|
ErrorCode = 0x1B;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Zero all but the last one.
|
|
|
|
CurrentLongAddress[0] = 0;
|
|
CurrentLongAddress[1] = 0;
|
|
CurrentLongAddress[2] = 0;
|
|
CurrentLongAddress[3] = 0;
|
|
CurrentLongAddress[4] = 0;
|
|
|
|
if (!EthCreateFilter(32,
|
|
ndisMChangeEthAddresses,
|
|
ndisMChangeClass,
|
|
ndisMCloseAction,
|
|
CurrentLongAddress,
|
|
&Miniport->Lock,
|
|
&Miniport->EthDB))
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error creating the Arcnet filter database for encapsulated ethernet\n"));
|
|
|
|
//
|
|
// Delete the arcnet filter.
|
|
//
|
|
ArcDeleteFilter(Miniport->ArcDB);
|
|
|
|
//
|
|
// Halt the miniport driver
|
|
//
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NdisFreeMemory(Buffer,
|
|
sizeof(ARC_BUFFER_LIST) * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeMemory(DataBuffer,
|
|
WRAPPER_ARC_HEADER_SIZE * WRAPPER_ARC_BUFFERS,
|
|
0);
|
|
NdisFreeBufferPool(Miniport->ArcnetBufferPool);
|
|
ErrorCode = 0x1C;
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Save a pointer to the miniport block with the
|
|
// ethernet filter.
|
|
//
|
|
Miniport->EthDB->Miniport = Miniport;
|
|
|
|
// Set the indicate handler
|
|
Miniport->PacketIndicateHandler = EthFilterDprIndicateReceivePacket;
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
break;
|
|
|
|
case NdisMediumWan:
|
|
|
|
ErrorCode = ndisMDoMiniportOp(Miniport,
|
|
TRUE,
|
|
OID_WAN_CURRENT_ADDRESS,
|
|
&CurrentLongAddress,
|
|
sizeof(CurrentLongAddress),
|
|
0x1D);
|
|
if (ErrorCode != 0)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Error querying OID_WAN_CURRENT_ADDRESS\n"));
|
|
|
|
ExtendedError = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Fall through
|
|
//
|
|
case NdisMediumAtm:
|
|
//
|
|
// Now undo the bogus filter package. We lock
|
|
// the miniport so that no dpcs will get queued.
|
|
//
|
|
BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
ndisMUndoBogusFilters(Miniport);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_IN_INITIALIZE);
|
|
CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Do we need to log an error?
|
|
//
|
|
if (ExtendedError)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("Extended error while initializing the miniport\n"));
|
|
|
|
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
|
|
NDIS_ERROR_CODE_DRIVER_FAILURE,
|
|
2,
|
|
0xFF00FF00,
|
|
ErrorCode);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Done with adding this MINIPORT!!!
|
|
//
|
|
Miniport->MiniportRequest = NULL;
|
|
|
|
IoRegisterShutdownNotification(Miniport->DeviceObject);
|
|
|
|
// Set to not cleanup
|
|
FreeDevice = DerefDriver = FreeBuffer = Dequeue = FALSE;
|
|
FreeWorkItemStorage = FALSE;
|
|
FreeArcnetLookaheadBuffer = FALSE;
|
|
FreeDeferredTimer = FALSE;
|
|
FreePacketArray = FALSE;
|
|
|
|
//
|
|
// Finally mark the device as *NOT* initializing. This is to let
|
|
// layered miniports initialize their device instance *OUTSIDE*
|
|
// of their driver entry. If this flag is on, then NdisOpenAdapter
|
|
// to this device will not work. This is also true of subsequent
|
|
// instances of a driver initializing outside of its DriverEntry
|
|
// as a result of a PnP event.
|
|
//
|
|
Miniport->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
}
|
|
else
|
|
{
|
|
ErrorCode = MiniportInitializeStatus;
|
|
}
|
|
} while (FALSE);
|
|
|
|
if ((Miniport != NULL) && (Miniport->Resources != NULL) && (ErrorCode != 0))
|
|
{
|
|
ndisMReleaseResources(Miniport);
|
|
}
|
|
|
|
//
|
|
// Perform any necessary cleanup.
|
|
//
|
|
//
|
|
if (FreeDevice)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Deleting the device.\n"));
|
|
|
|
IoDeleteDevice(pTmpDevice);
|
|
}
|
|
|
|
if (DerefDriver)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Dereferencing the miniport block.\n"));
|
|
|
|
ndisDereferenceDriver(pMiniBlock);
|
|
}
|
|
|
|
if (FreeBuffer)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Freeing the miniport name.\n"));
|
|
|
|
(Miniport->MiniportName.Buffer);
|
|
}
|
|
|
|
if (FreeArcnetLookaheadBuffer)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Freeing the arcnet lookahead buffer.\n"));
|
|
|
|
FREE_POOL(Miniport->ArcnetLookaheadBuffer);
|
|
}
|
|
|
|
if (FreeWorkItemStorage)
|
|
{
|
|
PSINGLE_LIST_ENTRY Link;
|
|
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Freeing the workitems.\n"));
|
|
|
|
//
|
|
// Walk the list and free the work items that
|
|
// were allocated.
|
|
//
|
|
while (Miniport->WorkItemFreeQueue.Next != NULL)
|
|
{
|
|
Link = PopEntryList(&Miniport->WorkItemFreeQueue);
|
|
WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
|
|
FREE_POOL(WorkItem);
|
|
}
|
|
|
|
//
|
|
// Free the single workitem list.
|
|
//
|
|
for (i = 0; i < NUMBER_OF_SINGLE_WORK_ITEMS; i++)
|
|
{
|
|
//
|
|
// Is there a work item here?
|
|
//
|
|
Link = PopEntryList(&Miniport->SingleWorkItems[i]);
|
|
if (Link != NULL)
|
|
{
|
|
WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
|
|
FREE_POOL(WorkItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FreeDeferredTimer)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Freeing memory allocated for the Full-Duplex timer.\n"));
|
|
FREE_POOL(Miniport->DeferredTimer);
|
|
}
|
|
|
|
if (FreePacketArray)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Freeing memory for the miniport's packet array\n"));
|
|
FREE_POOL(Miniport->PacketArray);
|
|
}
|
|
|
|
if (Dequeue)
|
|
{
|
|
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
|
|
("INIT FAILURE: Dequeueing the miniport from the driver block.\n"));
|
|
|
|
ndisDequeueMiniportOnDriver(Miniport, pMiniBlock);
|
|
}
|
|
|
|
return ErrorCode;
|
|
}
|
|
|
|
BOOLEAN
|
|
ndisCheckProtocolBinding(
|
|
IN PNDIS_PROTOCOL_BLOCK Protocol,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PUNICODE_STRING BaseName,
|
|
OUT PUNICODE_STRING ProtocolSection
|
|
)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
|
|
NTSTATUS Status;
|
|
BOOLEAN rc = FALSE;
|
|
PWSTR Bind = NULL;
|
|
|
|
//
|
|
// Set up LinkQueryTable to do the following:
|
|
//
|
|
|
|
//
|
|
// 1) Switch to the Linkage key below the xports registry key
|
|
//
|
|
|
|
LinkQueryTable[0].QueryRoutine = NULL;
|
|
LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
|
LinkQueryTable[0].Name = L"Linkage";
|
|
|
|
//
|
|
// 2) Call ndisSaveLinkage for "Bind" (as a single multi-string),
|
|
// which will allocate storage and save the data in Bind.
|
|
//
|
|
|
|
LinkQueryTable[1].QueryRoutine = ndisSaveLinkage;
|
|
LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
LinkQueryTable[1].Name = L"Bind";
|
|
LinkQueryTable[1].EntryContext = (PVOID)&Bind;
|
|
LinkQueryTable[1].DefaultType = REG_NONE;
|
|
|
|
//
|
|
// 3) Stop
|
|
//
|
|
|
|
LinkQueryTable[2].QueryRoutine = NULL;
|
|
LinkQueryTable[2].Flags = 0;
|
|
LinkQueryTable[2].Name = NULL;
|
|
|
|
do
|
|
{
|
|
UNICODE_STRING Us, Parms;
|
|
PWSTR CurBind;
|
|
|
|
RtlInitUnicodeString(&Parms, L"\\Parameters\\");
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
|
|
Protocol->ProtocolCharacteristics.Name.Buffer,
|
|
LinkQueryTable,
|
|
(PVOID)NULL, // no context needed
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
// Walk the list of bindings and see if any match
|
|
for (CurBind = Bind;
|
|
*CurBind != 0;
|
|
CurBind = (PWCHAR)((PUCHAR)CurBind + Us.MaximumLength))
|
|
{
|
|
RtlInitUnicodeString (&Us, CurBind);
|
|
|
|
if (RtlEqualUnicodeString(&Us, DeviceName, TRUE))
|
|
{
|
|
//
|
|
// Allocate space for the protocol section under the adapter
|
|
// to pass to the protocol. The string looks like this.
|
|
//
|
|
// Sonic1\Parameters\tcpip
|
|
//
|
|
ProtocolSection->MaximumLength = BaseName->Length + // "Sonic1"
|
|
Parms.Length + // "\Parameters\"
|
|
Protocol->ProtocolCharacteristics.Name.Length +// "tcpip"
|
|
sizeof(WCHAR);
|
|
ProtocolSection->Length = BaseName->Length;
|
|
ProtocolSection->Buffer = (PWSTR)ALLOC_FROM_POOL(ProtocolSection->MaximumLength,
|
|
NDIS_TAG_DEFAULT);
|
|
if (ProtocolSection->Buffer != NULL)
|
|
{
|
|
ZeroMemory(ProtocolSection->Buffer, ProtocolSection->MaximumLength);
|
|
CopyMemory(ProtocolSection->Buffer,
|
|
BaseName->Buffer,
|
|
BaseName->Length);
|
|
RtlAppendUnicodeStringToString(ProtocolSection,
|
|
&Parms);
|
|
RtlAppendUnicodeStringToString(ProtocolSection,
|
|
&Protocol->ProtocolCharacteristics.Name);
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (Bind != NULL)
|
|
FREE_POOL(Bind);
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOLEAN
|
|
ndisProtocolAlreadyBound(
|
|
IN PNDIS_PROTOCOL_BLOCK Protocol,
|
|
IN PUNICODE_STRING AdapterName
|
|
)
|
|
{
|
|
PNDIS_OPEN_BLOCK pOpen;
|
|
BOOLEAN rc = FALSE;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
|
|
|
|
for (pOpen = Protocol->OpenQueue;
|
|
pOpen != NULL;
|
|
pOpen = pOpen->ProtocolNextOpen)
|
|
{
|
|
if (NDIS_EQUAL_UNICODE_STRING(AdapterName, &pOpen->AdapterName))
|
|
{
|
|
rc = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
|
|
return rc;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisUpdateDriverInstance(
|
|
IN PUNICODE_STRING BaseString,
|
|
IN PUNICODE_STRING BindString,
|
|
IN PUNICODE_STRING ExportString,
|
|
IN PUNICODE_STRING RouteString
|
|
)
|
|
{
|
|
UNICODE_STRING Path, Linkage;
|
|
UINT SavedLen;
|
|
NDIS_STATUS Status = NDIS_STATUS_RESOURCES;
|
|
|
|
RtlInitUnicodeString(&Linkage, L"\\Linkage");
|
|
Path.MaximumLength = BaseString->Length + Linkage.Length + sizeof(WCHAR);
|
|
Path.Length = 0;
|
|
Path.Buffer = (PWSTR)ALLOC_FROM_POOL(Path.MaximumLength, NDIS_TAG_DEFAULT);
|
|
if (Path.Buffer != NULL)
|
|
{
|
|
//
|
|
// Add the Bind/Route/Linkage sections to the driver instance
|
|
//
|
|
ZeroMemory(Path.Buffer, Path.MaximumLength);
|
|
RtlCopyUnicodeString(&Path, BaseString);
|
|
RtlAppendUnicodeStringToString(&Path, &Linkage);
|
|
|
|
RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
|
|
Path.Buffer,
|
|
L"Bind",
|
|
REG_MULTI_SZ,
|
|
BindString->Buffer,
|
|
BindString->Length);
|
|
RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
|
|
Path.Buffer,
|
|
L"Export",
|
|
REG_MULTI_SZ,
|
|
ExportString->Buffer,
|
|
ExportString->Length);
|
|
RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
|
|
Path.Buffer,
|
|
L"Route",
|
|
REG_MULTI_SZ,
|
|
RouteString->Buffer,
|
|
RouteString->Length);
|
|
FREE_POOL(Path.Buffer);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisCheckIfPcmciaCardPresent(
|
|
IN PNDIS_M_DRIVER_BLOCK pMiniBlock
|
|
)
|
|
{
|
|
PNDIS_MAC_BLOCK pMacBlock = (PNDIS_MAC_BLOCK)pMiniBlock;
|
|
NTSTATUS RegStatus;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
BOOLEAN Found = FALSE;
|
|
#define PCMCIA_HW_SECTION L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs"
|
|
|
|
//
|
|
// Setup to enumerate the values in the registry section (shown above).
|
|
// For each such value, we'll check against the driver name.
|
|
//
|
|
QueryTable[0].QueryRoutine = ndisValidatePcmciaDriver;
|
|
QueryTable[0].DefaultType = REG_FULL_RESOURCE_DESCRIPTOR;
|
|
QueryTable[0].DefaultLength = 0;
|
|
QueryTable[0].EntryContext = &Found;
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
|
|
QueryTable[0].Name = (pMiniBlock->MiniportIdField == (NDIS_HANDLE)0x01) ?
|
|
pMiniBlock->BaseName.Buffer : pMacBlock->BaseName.Buffer;
|
|
|
|
//
|
|
// Query terminator
|
|
//
|
|
QueryTable[1].QueryRoutine = NULL;
|
|
QueryTable[1].Flags = 0;
|
|
QueryTable[1].Name = NULL;
|
|
|
|
RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
PCMCIA_HW_SECTION,
|
|
QueryTable,
|
|
(PVOID)NULL, // no context needed
|
|
NULL);
|
|
return(Found ? NDIS_STATUS_SUCCESS : NDIS_STATUS_ADAPTER_NOT_FOUND);
|
|
#undef PCMCIA_HW_SECTION
|
|
}
|
|
|
|
NTSTATUS
|
|
ndisValidatePcmciaDriver(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
if (ValueLength != 0)
|
|
*(BOOLEAN *)EntryContext = TRUE;
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisQueuedBindNotification(
|
|
IN PQUEUED_PROTOCOL_NOTIFICATION pQPN
|
|
)
|
|
{
|
|
KIRQL OldIrql;
|
|
PNDIS_M_DRIVER_BLOCK MiniBlock = pQPN->MiniBlock;
|
|
PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
|
|
|
|
//
|
|
// Initiate upcalls to protocols to bind to it. First reference the
|
|
// miniport.
|
|
//
|
|
NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
|
|
|
|
for (Miniport = MiniBlock->MiniportQueue;
|
|
Miniport != NULL;
|
|
Miniport = NextMiniport)
|
|
{
|
|
if (NDIS_EQUAL_UNICODE_STRING(&pQPN->UpCaseDeviceInstance, &Miniport->BaseName) &&
|
|
ndisReferenceMiniport(Miniport))
|
|
{
|
|
NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
|
|
|
|
ndisInitializeBindings(&Miniport->MiniportName,
|
|
&Miniport->BaseName,
|
|
FALSE);
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
NextMiniport = Miniport->NextMiniport;
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisIMInitializeDeviceInstance(
|
|
IN NDIS_HANDLE DriverHandle,
|
|
IN PNDIS_STRING DeviceInstance
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize an instance of a miniport device.
|
|
|
|
Arguments:
|
|
|
|
DriverHandle - Handle returned by NdisMRegisterLayeredMiniport.
|
|
It is a pointer to NDIS_M_DRIVER_BLOCK.
|
|
DeviceInstance -Points to the instance of the driver that must now
|
|
be initialized.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_M_DRIVER_BLOCK MiniBlock = (PNDIS_M_DRIVER_BLOCK)DriverHandle;
|
|
|
|
Status = ndisInitializeAllAdapterInstances((PNDIS_MAC_BLOCK)MiniBlock,
|
|
DeviceInstance);
|
|
|
|
//
|
|
// Queue a thread to do protocol notifications
|
|
//
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
NTSTATUS s;
|
|
PQUEUED_PROTOCOL_NOTIFICATION pQPN;
|
|
|
|
pQPN = (PQUEUED_PROTOCOL_NOTIFICATION)ALLOC_FROM_POOL(sizeof(QUEUED_PROTOCOL_NOTIFICATION) +
|
|
DeviceInstance->MaximumLength,
|
|
NDIS_TAG_DEFAULT);
|
|
if (pQPN == NULL)
|
|
{
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
|
|
("Cannot allocate memory for protocol notifications for intermediate driver %Z\n",
|
|
DeviceInstance));
|
|
return(NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
pQPN->MiniBlock = MiniBlock;
|
|
pQPN->UpCaseDeviceInstance.Buffer = pQPN->Buffer;
|
|
pQPN->UpCaseDeviceInstance.Length = DeviceInstance->MaximumLength;
|
|
pQPN->UpCaseDeviceInstance.MaximumLength = DeviceInstance->MaximumLength;
|
|
|
|
s = RtlUpcaseUnicodeString(&pQPN->UpCaseDeviceInstance, DeviceInstance, FALSE);
|
|
if (!NT_SUCCESS(s))
|
|
{
|
|
return s;
|
|
}
|
|
|
|
INITIALIZE_WORK_ITEM(&pQPN->WorkItem, ndisQueuedBindNotification, pQPN);
|
|
QUEUE_WORK_ITEM(&pQPN->WorkItem, DelayedWorkQueue);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|