Windows NT 4.0 source code leak
 
 
 
 
 
 

4619 lines
94 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Detect.c
Abstract:
This is the main file for the autodetection DLL for all the net cards
which MS is shipping with Windows NT.
Author:
Sean Selitrennikoff (SeanSe) October 1992.
Environment:
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ntddnetd.h"
#include "detect.h"
#if DBG
#define DBGPRINT(x) DbgPrint x
#define STATIC
#else
#define STATIC static
#define DBGPRINT(x)
#endif
//
// This is the structure for all the cards which MS is shipping in this DLL.
// To add detection for a new adapter(s), simply add the proper routines to
// this structure. The rest is automatic.
//
DETECT_ADAPTER DetectAdapters[] = {
#ifdef _M_MRX000
{
MipsIdentifyHandler,
MipsFirstNextHandler,
MipsOpenHandleHandler,
MipsCreateHandleHandler,
MipsCloseHandleHandler,
MipsQueryCfgHandler,
MipsVerifyCfgHandler,
MipsQueryMaskHandler,
MipsParamRangeHandler,
MipsQueryParameterNameHandler,
0
},
#endif
{
PcmciaIdentifyHandler,
PcmciaFirstNextHandler,
PcmciaOpenHandleHandler,
PcmciaCreateHandleHandler,
PcmciaCloseHandleHandler,
PcmciaQueryCfgHandler,
PcmciaVerifyCfgHandler,
PcmciaQueryMaskHandler,
PcmciaParamRangeHandler,
PcmciaQueryParameterNameHandler,
0
},
{
McaIdentifyHandler,
McaFirstNextHandler,
McaOpenHandleHandler,
McaCreateHandleHandler,
McaCloseHandleHandler,
McaQueryCfgHandler,
McaVerifyCfgHandler,
McaQueryMaskHandler,
McaParamRangeHandler,
McaQueryParameterNameHandler,
0
},
{
EisaIdentifyHandler,
EisaFirstNextHandler,
EisaOpenHandleHandler,
EisaCreateHandleHandler,
EisaCloseHandleHandler,
EisaQueryCfgHandler,
EisaVerifyCfgHandler,
EisaQueryMaskHandler,
EisaParamRangeHandler,
EisaQueryParameterNameHandler,
0
},
{
PciIdentifyHandler,
PciFirstNextHandler,
PciOpenHandleHandler,
PciCreateHandleHandler,
PciCloseHandleHandler,
PciQueryCfgHandler,
PciVerifyCfgHandler,
PciQueryMaskHandler,
PciParamRangeHandler,
PciQueryParameterNameHandler,
0
},
{
LanceIdentifyHandler,
LanceFirstNextHandler,
LanceOpenHandleHandler,
LanceCreateHandleHandler,
LanceCloseHandleHandler,
LanceQueryCfgHandler,
LanceVerifyCfgHandler,
LanceQueryMaskHandler,
LanceParamRangeHandler,
LanceQueryParameterNameHandler,
0
},
{
IbmtokIdentifyHandler,
IbmtokFirstNextHandler,
IbmtokOpenHandleHandler,
IbmtokCreateHandleHandler,
IbmtokCloseHandleHandler,
IbmtokQueryCfgHandler,
IbmtokVerifyCfgHandler,
IbmtokQueryMaskHandler,
IbmtokParamRangeHandler,
IbmtokQueryParameterNameHandler,
0
},
{
WdIdentifyHandler,
WdFirstNextHandler,
WdOpenHandleHandler,
WdCreateHandleHandler,
WdCloseHandleHandler,
WdQueryCfgHandler,
WdVerifyCfgHandler,
WdQueryMaskHandler,
WdParamRangeHandler,
WdQueryParameterNameHandler,
0
},
{
ElnkiiIdentifyHandler,
ElnkiiFirstNextHandler,
ElnkiiOpenHandleHandler,
ElnkiiCreateHandleHandler,
ElnkiiCloseHandleHandler,
ElnkiiQueryCfgHandler,
ElnkiiVerifyCfgHandler,
ElnkiiQueryMaskHandler,
ElnkiiParamRangeHandler,
ElnkiiQueryParameterNameHandler,
0
},
{
Ne2000IdentifyHandler,
Ne2000FirstNextHandler,
Ne2000OpenHandleHandler,
Ne2000CreateHandleHandler,
Ne2000CloseHandleHandler,
Ne2000QueryCfgHandler,
Ne2000VerifyCfgHandler,
Ne2000QueryMaskHandler,
Ne2000ParamRangeHandler,
Ne2000QueryParameterNameHandler,
0
},
{
Ne1000IdentifyHandler,
Ne1000FirstNextHandler,
Ne1000OpenHandleHandler,
Ne1000CreateHandleHandler,
Ne1000CloseHandleHandler,
Ne1000QueryCfgHandler,
Ne1000VerifyCfgHandler,
Ne1000QueryMaskHandler,
Ne1000ParamRangeHandler,
Ne1000QueryParameterNameHandler,
0
},
{
UbIdentifyHandler,
UbFirstNextHandler,
UbOpenHandleHandler,
UbCreateHandleHandler,
UbCloseHandleHandler,
UbQueryCfgHandler,
UbVerifyCfgHandler,
UbQueryMaskHandler,
UbParamRangeHandler,
UbQueryParameterNameHandler,
0
},
{
ProteonIdentifyHandler,
ProteonFirstNextHandler,
ProteonOpenHandleHandler,
ProteonCreateHandleHandler,
ProteonCloseHandleHandler,
ProteonQueryCfgHandler,
ProteonVerifyCfgHandler,
ProteonQueryMaskHandler,
ProteonParamRangeHandler,
ProteonQueryParameterNameHandler,
0
},
{
Elnk16IdentifyHandler,
Elnk16FirstNextHandler,
Elnk16OpenHandleHandler,
Elnk16CreateHandleHandler,
Elnk16CloseHandleHandler,
Elnk16QueryCfgHandler,
Elnk16VerifyCfgHandler,
Elnk16QueryMaskHandler,
Elnk16ParamRangeHandler,
Elnk16QueryParameterNameHandler,
0
},
{
Ee16IdentifyHandler,
Ee16FirstNextHandler,
Ee16OpenHandleHandler,
Ee16CreateHandleHandler,
Ee16CloseHandleHandler,
Ee16QueryCfgHandler,
Ee16VerifyCfgHandler,
Ee16QueryMaskHandler,
Ee16ParamRangeHandler,
Ee16QueryParameterNameHandler,
0
},
{
EProIdentifyHandler,
EProFirstNextHandler,
EProOpenHandleHandler,
EProCreateHandleHandler,
EProCloseHandleHandler,
EProQueryCfgHandler,
EProVerifyCfgHandler,
EProQueryMaskHandler,
EProParamRangeHandler,
EProQueryParameterNameHandler,
0
},
{
Elnk3IdentifyHandler,
Elnk3FirstNextHandler,
Elnk3OpenHandleHandler,
Elnk3CreateHandleHandler,
Elnk3CloseHandleHandler,
Elnk3QueryCfgHandler,
Elnk3VerifyCfgHandler,
Elnk3QueryMaskHandler,
Elnk3ParamRangeHandler,
Elnk3QueryParameterNameHandler,
0
},
{
Tok162IdentifyHandler,
Tok162FirstNextHandler,
Tok162OpenHandleHandler,
Tok162CreateHandleHandler,
Tok162CloseHandleHandler,
Tok162QueryCfgHandler,
Tok162VerifyCfgHandler,
Tok162QueryMaskHandler,
Tok162ParamRangeHandler,
Tok162QueryParameterNameHandler,
0
}
};
//
// Constant strings for parameters
//
WCHAR IrqString[] = L"IRQ";
WCHAR IrqTypeString[] = L"IRQTYPE";
WCHAR IoAddrString[] = L"IOADDR";
WCHAR IoLengthString[] = L"IOADDRLENGTH";
WCHAR MemAddrString[] = L"MEMADDR";
WCHAR MemLengthString[] = L"MEMADDRLENGTH";
WCHAR TransceiverString[] = L"TRANSCEIVER";
WCHAR ZeroWaitStateString[] = L"ZEROWAITSTATE";
WCHAR SlotNumberString[] = L"SLOTNUMBER";
WCHAR IoChannelReadyString[] = L"IOCHANNELREADY";
WCHAR CardTypeString[] = L"CARDTYPE";
WCHAR PcmciaString[] = L"PCMCIA";
WCHAR PCCARDAttributeMemLengthString[] = L"PCCARDATTRIBUTEMEMLENGTH";
WCHAR PCCARDAttributeMemString[] = L"PCCARDATTRIBUTEMEM";
//
// Variables for keeping track of the resources that the DLL currently has
// claimed.
//
PNETDTECT_RESOURCE ResourceList;
ULONG NumberOfResources = 0;
ULONG NumberOfAllocatedResourceSlots = 0;
//
// Variables for detecting non-network related hardware
//
typedef struct _DETECT_CONFIG {
INTERFACE_TYPE InterfaceType;
ULONG BusNumber;
struct _DETECT_CONFIG *Next;
}DETECT_CONFIG, *PDETECT_CONFIG;
PDETECT_CONFIG DetectConfigs = NULL;
VOID
NcDetectFindOtherHardware(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber
);
BOOLEAN
NcDetectInitialInit(
IN PVOID DllHandle,
IN ULONG Reason,
IN PCONTEXT Context OPTIONAL
)
/*++
Routine Description:
This routine calls CreateFile to open the device driver.
Arguments:
DllHandle - Not Used
Reason - Attach or Detach
Context - Not Used
Return Value:
STATUS_SUCCESS
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG SupportedAdapters;
LONG TotalAdapters = 0;
LONG ReturnValue;
LONG Length = 0;
PDETECT_CONFIG Tmp;
BOOLEAN f;
if (DLL_PROCESS_DETACH == Reason)
{
//
// This is the close call
//
FreeEisaAdapterInfo();
FreePciAdapterInfo();
FreeMcaAdapterInfo();
//
// Free ResourceList
//
if (NumberOfAllocatedResourceSlots > 0)
{
DetectFreeHeap(ResourceList);
}
//
// Now free config list
//
while (DetectConfigs != NULL)
{
Tmp = DetectConfigs;
DetectConfigs = DetectConfigs->Next;
DetectFreeHeap(Tmp);
}
//
// Free any temporary resources
//
DetectFreeTemporaryResources();
return(TRUE);
}
//
// Load the adapter information out of the registry.
//
if (DLL_PROCESS_ATTACH == Reason)
{
//
// This is the close call
//
f = LoadEisaAdapterInfo();
if (!f)
{
return(FALSE);
}
f = LoadPciAdapterInfo();
if (!f)
{
return(FALSE);
}
f = LoadMcaAdapterInfo();
if (!f)
{
return(FALSE);
}
}
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// Count the total number of adapters supported by this DLL by
// iterating through each module, finding the number of adapters
// each module supports.
//
SupportedAdapters = 0;
for ( ; ; SupportedAdapters++)
{
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectIdentifyHandler))(
((SupportedAdapters+10) * 100),
NULL,
Length);
if (ReturnValue == ERROR_NO_MORE_ITEMS)
{
break;
}
}
TotalAdapters += SupportedAdapters;
DetectAdapters[CurrentDriver].SupportedAdapters = SupportedAdapters;
}
if (TotalAdapters > 0xFFFF)
{
//
// We do not support more than this many adapters in this DLL
// because of the way we build the Tokens and NetcardIds.
//
return(FALSE);
}
return(TRUE);
}
LONG
NcDetectIdentify(
IN LONG Index,
OUT WCHAR *Buffer,
IN LONG BuffSize
)
/*++
Routine Description:
This routine returns information about the netcards supported by
this DLL.
Arguments:
Index - The index of the netcard being address. The first
cards information is at index 1000, the second at 1100, etc.
Buffer - Buffer to store the result into.
BuffSize - Number of bytes in pwchBuffer
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG ReturnValue;
LONG AdapterNumber = (Index / 100) - 10;
LONG CodeNumber = Index % 100;
//
// First we check the index for any of the 'special' values.
//
if (Index == 0)
{
//
// Return manufacturers identfication
//
if (BuffSize < 4)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy in the identification number
//
wsprintf(Buffer,L"0x0");
return(0);
}
if (Index == 1)
{
//
// Return the date and version
//
if (BuffSize < 12)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy it in
//
wsprintf(Buffer,L"0x10920301");
return(0);
}
if (AdapterNumber < 0)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Now we find the number of drivers this DLL is supporting.
//
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
//
// Iterate through index until we find the the adapter indicated above.
//
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// See if the one we want is in here
//
if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters)
{
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectIdentifyHandler))(
((AdapterNumber + 10) * 100) + CodeNumber,
Buffer,
BuffSize);
return(ReturnValue);
}
else
{
//
// No, move on to next driver.
//
AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters;
}
}
return(ERROR_NO_MORE_ITEMS);
}
LONG
NcDetectFirstNext(
IN LONG NetcardId,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN BOOL First,
OUT PVOID *Token,
OUT LONG *Confidence
)
/*++
Routine Description:
This routine finds the instances of a physical adapter identified
by the NetcardId.
//
Arguments:
NetcardId - The index of the netcard being address. The first
cards information is id 1000, the second id 1100, etc.
InterfaceType - Any bus type.
BusNumber - The bus number of the bus to search.
First - TRUE is we are to search for the first instance of an
adapter, FALSE if we are to continue search from a previous stopping
point.
Token - A pointer to a handle to return to identify the found
instance
Confidence - A pointer to a long for storing the confidence factor
that the card exists.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG ReturnValue;
LONG AdapterNumber = (NetcardId / 100) - 10;
PDETECT_CONFIG TmpConfig;
if (AdapterNumber < 0)
{
return(ERROR_INVALID_PARAMETER);
}
if ((NetcardId % 100) != 0)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Find non-network hardware that will cause hangs and claim those
// resources.
//
TmpConfig = DetectConfigs;
while (TmpConfig != NULL)
{
if ((TmpConfig->InterfaceType == InterfaceType) &&
(TmpConfig->BusNumber == BusNumber))
{
break;
}
TmpConfig = TmpConfig->Next;
}
if (TmpConfig == NULL)
{
//
// Record this new config
//
TmpConfig = (PDETECT_CONFIG)DetectAllocateHeap(sizeof(DETECT_CONFIG));
TmpConfig->InterfaceType = InterfaceType;
TmpConfig->BusNumber = BusNumber;
TmpConfig->Next = DetectConfigs;
DetectConfigs = TmpConfig;
//
// Now find any other hardware on this config
//
NcDetectFindOtherHardware(InterfaceType, BusNumber);
}
//
// Now we find the number of drivers this DLL is supporting.
//
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
//
// Iterate through index until we find the the adapter indicated above.
//
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// See if the one we want is in here
//
if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters)
{
//
// Yes, so call to get the right one.
//
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectFirstNextHandler))(
(AdapterNumber + 10) * 100,
InterfaceType,
BusNumber,
First,
Token,
Confidence);
if (ReturnValue == 0)
{
//
// Store information
//
*Token = (PVOID)(((ULONG)(*Token)) | (CurrentDriver << 16));
}
else
{
*Token = 0;
}
return(ReturnValue);
}
else
{
//
// No, move on to next driver.
//
AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters;
}
}
return(ERROR_INVALID_PARAMETER);
}
LONG
NcDetectOpenHandle(
IN PVOID Token,
OUT PVOID *Handle
)
/*++
Routine Description:
This routine takes a token returned by FirstNext and converts it
into a permanent handle.
Arguments:
Token - The token.
Handle - A pointer to the handle, so we can store the resulting
handle.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG ReturnValue;
LONG DriverToken = ((ULONG)Token & 0xFFFF);
LONG DriverNumber = ((ULONG)Token >> 16);
PADAPTER_HANDLE Adapter;
ReturnValue = (*(DetectAdapters[DriverNumber].NcDetectOpenHandleHandler))(
(PVOID)DriverToken,
Handle);
if (ReturnValue == 0)
{
//
// Store information
//
Adapter = DetectAllocateHeap(sizeof(ADAPTER_HANDLE));
if (Adapter == NULL)
{
//
// Error
//
(*(DetectAdapters[DriverNumber].NcDetectCloseHandleHandler))(*Handle);
return(ERROR_NOT_ENOUGH_MEMORY);
}
Adapter->Handle = *Handle;
Adapter->DriverNumber = DriverNumber;
*Handle = Adapter;
}
else
{
*Handle = NULL;
}
return(ReturnValue);
}
LONG
NcDetectCreateHandle(
IN LONG NetcardId,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
OUT PVOID *Handle
)
/*++
Routine Description:
This routine is used to force the creation of a handle for cases
where a card is not found via FirstNext, but the user says it does
exist.
Arguments:
NetcardId - The id of the card to create the handle for.
InterfaceType - Any bus type.
BusNumber - The bus number of the bus in the system.
Handle - A pointer to the handle, for storing the resulting handle.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG ReturnValue;
LONG AdapterNumber = (NetcardId / 100) - 10;
PADAPTER_HANDLE Adapter;
PDETECT_CONFIG TmpConfig;
if (AdapterNumber < 0)
{
return(ERROR_INVALID_PARAMETER);
}
if ((NetcardId % 100) != 0)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Find non-network hardware that will cause hangs and claim those
// resources.
//
TmpConfig = DetectConfigs;
while (TmpConfig != NULL)
{
if ((TmpConfig->InterfaceType == InterfaceType) &&
(TmpConfig->BusNumber == BusNumber))
{
break;
}
TmpConfig = TmpConfig->Next;
}
if (TmpConfig == NULL)
{
//
// Record this new config
//
TmpConfig = (PDETECT_CONFIG)DetectAllocateHeap(sizeof(DETECT_CONFIG));
TmpConfig->InterfaceType = InterfaceType;
TmpConfig->BusNumber = BusNumber;
TmpConfig->Next = DetectConfigs;
DetectConfigs = TmpConfig;
//
// Now find any other hardware on this config
//
NcDetectFindOtherHardware(InterfaceType, BusNumber);
}
//
// Now we find the number of drivers this DLL is supporting.
//
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
//
// Iterate through index until we find the the adapter indicated above.
//
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// See if the one we want is in here
//
if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters)
{
//
// Yes, so call to get the right one.
//
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectCreateHandleHandler))(
(AdapterNumber + 10) * 100,
InterfaceType,
BusNumber,
Handle);
if (ReturnValue == 0)
{
//
// Store information
//
Adapter = DetectAllocateHeap(sizeof(ADAPTER_HANDLE));
if (Adapter == NULL)
{
//
// Error
//
(*(DetectAdapters[CurrentDriver].NcDetectCloseHandleHandler))(
*Handle);
return(ERROR_NOT_ENOUGH_MEMORY);
}
Adapter->Handle = *Handle;
Adapter->DriverNumber = CurrentDriver;
*Handle = Adapter;
}
else
{
*Handle = NULL;
}
return(ReturnValue);
}
else
{
//
// No, move on to next driver.
//
AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters;
}
}
return(ERROR_INVALID_PARAMETER);
}
LONG
NcDetectCloseHandle(
IN PVOID Handle
)
/*++
Routine Description:
This frees any resources associated with a handle.
Arguments:
pvHandle - The handle.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
PADAPTER_HANDLE Adapter = (PADAPTER_HANDLE)(Handle);
(*(DetectAdapters[Adapter->DriverNumber].NcDetectCloseHandleHandler))(
Adapter->Handle);
DetectFreeHeap( Adapter );
return(0);
}
LONG
NcDetectQueryCfg(
IN PVOID Handle,
OUT WCHAR *Buffer,
IN LONG BuffSize
)
/*++
Routine Description:
This routine calls the appropriate driver's query config handler to
get the parameters for the adapter associated with the handle.
Arguments:
Handle - The handle.
Buffer - The resulting parameter list.
BuffSize - Length of the given buffer in WCHARs.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
PADAPTER_HANDLE Adapter = (PADAPTER_HANDLE)(Handle);
LONG ReturnValue;
ReturnValue = (*(DetectAdapters[Adapter->DriverNumber].NcDetectQueryCfgHandler))(
Adapter->Handle,
Buffer,
BuffSize);
return(ReturnValue);
}
LONG
NcDetectVerifyCfg(
IN PVOID Handle,
IN WCHAR *Buffer
)
/*++
Routine Description:
This routine verifys that a given parameter list is complete and
correct for the adapter associated with the handle.
Arguments:
Handle - The handle.
Buffer - The parameter list.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
PADAPTER_HANDLE Adapter = (PADAPTER_HANDLE)(Handle);
LONG ReturnValue;
ReturnValue = (*(DetectAdapters[Adapter->DriverNumber].NcDetectVerifyCfgHandler))(
Adapter->Handle,
Buffer);
return(ReturnValue);
}
LONG
NcDetectQueryMask(
IN LONG NetcardId,
OUT WCHAR *Buffer,
IN LONG BuffSize
)
/*++
Routine Description:
This routine returns the parameter list information for a specific
network card.
Arguments:
NetcardId - The id of the desired netcard.
Buffer - The buffer for storing the parameter information.
BuffSize - Length of Buffer in WCHARs.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG ReturnValue;
LONG AdapterNumber = (NetcardId / 100) - 10;
if (AdapterNumber < 0)
{
return(ERROR_INVALID_PARAMETER);
}
if ((NetcardId % 100) != 0)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Now we find the number of drivers this DLL is supporting.
//
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
//
// Iterate through index until we find the the adapter indicated above.
//
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// See if the one we want is in here
//
if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters)
{
//
// Yes, so call to get the right one.
//
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectQueryMaskHandler))(
((AdapterNumber + 10) * 100),
Buffer,
BuffSize);
return(ReturnValue);
}
else
{
//
// No, move on to next driver.
//
AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters;
}
}
return(ERROR_INVALID_PARAMETER);
}
LONG
NcDetectParamRange(
IN LONG NetcardId,
IN WCHAR *Param,
OUT LONG *Values,
OUT LONG *BuffSize
)
/*++
Routine Description:
This routine returns a list of valid values for a given parameter name
for a given card.
Arguments:
NetcardId - The Id of the card desired.
Param - A WCHAR string of the parameter name to query the values of.
Values - A pointer to a list of LONGs into which we store valid values
for the parameter.
BuffSize - At entry, the length of plValues in LONGs. At exit, the
number of LONGs stored in plValues.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG ReturnValue;
LONG AdapterNumber = (NetcardId / 100) - 10;
if (AdapterNumber < 0)
{
return(ERROR_INVALID_PARAMETER);
}
if ((NetcardId % 100) != 0)
{
return(ERROR_INVALID_PARAMETER);
}
//
// Now we find the number of drivers this DLL is supporting.
//
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
//
// Iterate through index until we find the the adapter indicated above.
//
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// See if the one we want is in here
//
if (AdapterNumber < DetectAdapters[CurrentDriver].SupportedAdapters)
{
//
// Yes, so call to get the right one.
//
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectParamRangeHandler))(
((AdapterNumber + 10) * 100),
Param,
Values,
BuffSize);
return(ReturnValue);
}
else
{
//
// No, move on to next driver.
//
AdapterNumber -= DetectAdapters[CurrentDriver].SupportedAdapters;
}
}
return(ERROR_INVALID_PARAMETER);
}
LONG
NcDetectQueryParameterName(
IN WCHAR *Param,
OUT WCHAR *Buffer,
IN LONG BufferSize
)
/*++
Routine Description:
Returns a localized, displayable name for a specific parameter.
Arguments:
Param - The parameter to be queried.
Buffer - The buffer to store the result into.
BufferSize - The length of Buffer in WCHARs.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
LONG SupportedDrivers;
LONG CurrentDriver;
LONG ReturnValue;
//
// Now we find the number of drivers this DLL is supporting.
//
SupportedDrivers = sizeof(DetectAdapters) / sizeof(DETECT_ADAPTER);
//
// Iterate through index until we find the the adapter indicated above.
//
CurrentDriver = 0;
for (; CurrentDriver < SupportedDrivers ; CurrentDriver++)
{
//
// No way to tell where this came from -- guess until success.
//
ReturnValue =
(*(DetectAdapters[CurrentDriver].NcDetectQueryParameterNameHandler))(
Param,
Buffer,
BufferSize);
if (ReturnValue == 0)
{
return(0);
}
}
return(ERROR_INVALID_PARAMETER);
}
LONG
NcDetectResourceClaim(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG Type,
IN ULONG Value,
IN ULONG Length,
IN ULONG Flags,
IN BOOL Claim
)
/*++
Routine Description:
Attempts to claim a resources, failing if there is a conflict.
Arguments:
InterfaceType - Any type.
BusNumber - The bus number of the bus to search.
Type - The type of resource, Irq, Memory, Port, Dma
Value - The starting value
Length - The Length of the resource from starting value to end.
Flags - If Type is IRQ, this defines if this is Latched or LevelSensitive.
Claim - TRUE if we are to permanently claim the resource, else FALSE.
Return Value:
0 if nothing went wrong, else the appropriate WINERROR.H value.
--*/
{
ULONG i;
NTSTATUS NtStatus;
return(ERROR_NOT_SUPPORTED);
//
// Check the resources we've claimed for ourselves
//
for (i = 0; i < NumberOfResources; i++)
{
if ((ResourceList[i].InterfaceType == InterfaceType) &&
(ResourceList[i].BusNumber == BusNumber) &&
(ResourceList[i].Type == Type))
{
if (Value < ResourceList[i].Value)
{
if ((Value + Length) > ResourceList[i].Value)
{
return(ERROR_SHARING_VIOLATION);
}
}
else if (Value == ResourceList[i].Value)
{
return(ERROR_SHARING_VIOLATION);
}
else if (Value < (ResourceList[i].Value + ResourceList[i].Length))
{
return(ERROR_SHARING_VIOLATION);
}
}
}
//
// Make sure resource list has space for this one.
//
if (NumberOfResources == NumberOfAllocatedResourceSlots)
{
PVOID TmpList;
//
// Get more space
//
TmpList = DetectAllocateHeap((NumberOfAllocatedResourceSlots + 32) *
sizeof(NETDTECT_RESOURCE));
//
// Copy data
//
memcpy(TmpList,
ResourceList,
(NumberOfAllocatedResourceSlots * sizeof(NETDTECT_RESOURCE)));
//
// Update counter
//
NumberOfAllocatedResourceSlots += 32;
//
// Free old space
//
DetectFreeHeap(ResourceList);
ResourceList = (PNETDTECT_RESOURCE)TmpList;
}
//
// Add it to the list
//
ResourceList[NumberOfResources].InterfaceType = InterfaceType;
ResourceList[NumberOfResources].BusNumber = BusNumber;
ResourceList[NumberOfResources].Type = Type;
ResourceList[NumberOfResources].Value = Value;
ResourceList[NumberOfResources].Length = Length;
ResourceList[NumberOfResources].Flags = Flags;
//
// Try to claim the resource
//
NtStatus = DetectClaimResource(NumberOfResources + 1, (PVOID)ResourceList);
//
// If failed, exit
//
if (NtStatus == STATUS_CONFLICTING_ADDRESSES)
{
//
// Undo the claim
//
DetectClaimResource(NumberOfResources, (PVOID)ResourceList);
return(ERROR_SHARING_VIOLATION);
}
if (!NT_SUCCESS(NtStatus))
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
if (!Claim)
{
//
// Undo the claim
//
DetectClaimResource(NumberOfResources, (PVOID)ResourceList);
}
else
{
//
// Adjust total count only if this is permanent
//
NumberOfResources++;
}
//
// no error
//
return(0);
}
//
// Support routines.
//
// These routines are common routines used within each detection module.
//
ULONG
UnicodeStrLen(
IN WCHAR *String
)
/*++
Routine Description:
This routine returns the number of Unicode characters in a NULL
terminated Unicode string.
Arguments:
String - The string.
Return Value:
The length in number of unicode characters
--*/
{
ULONG Length;
for (Length=0; ; Length++)
{
if (String[Length] == L'\0')
{
return Length;
}
}
}
WCHAR *
FindParameterString(
IN WCHAR *String1,
IN WCHAR *String2
)
/*++
Routine Description:
This routine returns a pointer to the first instance of String2
in String1. It assumes that String1 is a parameter list where
each parameter name is terminated with a NULL and the entire
string terminated by two consecutive NULLs.
Arguments:
String1 -- String to search.
String2 -- Substring to search for.
Return Value:
Pointer to place in String1 of first character of String2 if it
exists, else NULL.
--*/
{
ULONG Length1;
ULONG Length2;
WCHAR *Place = String1;
Length2 = UnicodeStrLen(String2) + 1;
Length1 = UnicodeStrLen(String1) + 1;
//
// While not the NULL only
//
while (Length1 != 1)
{
//
// Are these the same?
//
if (memcmp(Place, String2, Length2 * sizeof(WCHAR)) == 0)
{
//
// Yes.
//
return(Place);
}
Place = (WCHAR *)(Place + Length1);
Length1 = UnicodeStrLen(Place) + 1;
}
return(NULL);
}
VOID
ScanForNumber(
IN WCHAR *Place,
OUT ULONG *Value,
OUT BOOLEAN *Found
)
/*++
Routine Description:
This routine does a sscanf(Place, "%d", Value) on a unicode string.
Arguments:
Place - String to read from
Value - Pointer to place to store the result.
Found - Pointer to tell if the routine failed to find an integer.
Return Value:
None.
--*/
{
ULONG Tmp;
*Value = 0;
*Found = FALSE;
//
// Skip leading blanks
//
while (*Place == L' ')
{
Place++;
}
//
// Is this a hex number?
//
if ((Place[0] == L'0') && (Place[1] == L'x'))
{
//
// Yes, parse it as a hex number
//
*Found = TRUE;
//
// Skip leading '0x'
//
Place += 2;
//
// Convert a hex number
//
while (TRUE)
{
if ((*Place >= L'0') && (*Place <= L'9'))
{
Tmp = ((ULONG)*Place) - ((ULONG)L'0');
}
else
{
switch (*Place)
{
case L'a':
case L'A':
Tmp = 10;
break;
case L'b':
case L'B':
Tmp = 11;
break;
case L'c':
case L'C':
Tmp = 12;
break;
case L'd':
case L'D':
Tmp = 13;
break;
case L'e':
case L'E':
Tmp = 14;
break;
case L'f':
case L'F':
Tmp = 15;
break;
default:
return;
}
}
(*Value) *= 16;
(*Value) += Tmp;
Place++;
}
}
else if ((*Place >= L'0') && (*Place <= L'9'))
{
//
// Parse it as an int
//
*Found = TRUE;
//
// Convert a base 10 number
//
while (TRUE)
{
if ((*Place >= L'0') && (*Place <= L'9'))
{
Tmp = ((ULONG)*Place) - ((ULONG)L'0');
}
else
{
return;
}
(*Value) *= 10;
(*Value) += Tmp;
Place++;
}
}
}
BOOLEAN
CheckFor8390(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IoBaseAddress
)
/*++
Routine Description:
This routine checks for the existence of an 8390 NIC.
Arguments:
InterfaceType - Any bus type.
BusNumber - The bus number of the bus in the system.
IoBaseAddress - The IoBaseAddress to check.
Return Value:
None.
--*/
{
UCHAR Value;
UCHAR IMRValue;
NTSTATUS NtStatus;
UCHAR SavedOffset0;
UCHAR SavedOffset3;
UCHAR SavedOffsetF;
BOOLEAN Status = TRUE;
//
// If the IoBaseAddress is the address of the DMA register on the NE2000
// adapter, then this routine will hang the card and the machine. To avoid
// this, we first write to the Ne2000's reset port.
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&SavedOffsetF);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Fail;
}
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
0xFF);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Fail;
}
//
// Write STOP bit
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
&SavedOffset0);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore1;
}
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x21);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore1;
}
//
// Read boundary
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x3,
&Value);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore2;
}
SavedOffset3 = Value;
//
// Write a different boundary
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x3,
(UCHAR)(Value + 1));
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore2;
}
//
// Did it stick?
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x3,
&IMRValue);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore3;
}
if (IMRValue != (UCHAR)(Value + 1))
{
Status = FALSE;
goto Restore3;
}
//
// Write IMR
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
0x3F);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore3;
}
//
// switch to page 2
//
NtStatus = DetectWritePortUchar(
InterfaceType,
BusNumber,
IoBaseAddress,
0xA1);
if (NtStatus != STATUS_SUCCESS)
{
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21);
Status = FALSE;
goto Restore3;
}
//
// Read the IMR
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&IMRValue);
if (NtStatus != STATUS_SUCCESS)
{
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x21);
Status = FALSE;
goto Restore3;
}
//
// Remove bits added by NIC
//
IMRValue &= 0x3F;
//
// switch to page 0
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x21);
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore3;
}
//
// Write IMR
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
(UCHAR)(IMRValue));
if (NtStatus != STATUS_SUCCESS)
{
Status = FALSE;
goto Restore3;
}
//
// switch to page 1
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x61);
if (NtStatus != STATUS_SUCCESS)
{
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21);
Status = FALSE;
goto Restore3;
}
//
// Write ~IMR
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
(UCHAR)(~IMRValue));
if (NtStatus != STATUS_SUCCESS)
{
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x21);
Status = FALSE;
goto Restore3;
}
//
// switch to page 2
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0xA1);
if (NtStatus != STATUS_SUCCESS)
{
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x21);
Status = FALSE;
goto Restore3;
}
//
// Read IMR
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
&Value);
if (NtStatus != STATUS_SUCCESS)
{
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21);
Status = FALSE;
goto Restore3;
}
//
// Are they the same?
//
if ((UCHAR)(Value & 0x3F) != (UCHAR)(IMRValue))
{
Status = FALSE;
}
//
// Change to page 0
//
DetectWritePortUchar(InterfaceType, BusNumber, IoBaseAddress, 0x21);
Restore3:
DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x3,
SavedOffset3);
Restore2:
DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
SavedOffset0);
Restore1:
DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
SavedOffsetF);
Fail:
return(Status);
}
VOID
Send8390Packet(
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN ULONG IoBaseAddress,
IN ULONG MemoryBaseAddress,
IN COPY_ROUTINE CardCopyDownBuffer,
IN UCHAR *NetworkAddress
)
/*++
Routine Description:
This routine creates an interrupt on an 8390 chip. The only way to
do this is to actually transmit a packet. So, we put the card in
loopback mode and let 'er rip.
Arguments:
InterfaceType - Any bus type.
BusNumber - The bus number of the bus in the system.
IoBaseAddress - The IoBaseAddress to check.
MemoryBaseAddress - The MemoryBaseAddress (if applicable) to copy a p
packet to for transmission.
CardCopyDownBuffer - A routine for copying a packet onto a card.
NetworkAddress - The network address of the machine.
Return Value:
None.
--*/
{
#define TEST_LEN 60
#define MAGIC_NUM 0x92
NTSTATUS NtStatus;
UCHAR TestPacket[TEST_LEN] = {0}; // a dummy packet.
memcpy(TestPacket, NetworkAddress, 6);
memcpy(TestPacket+6, NetworkAddress, 6);
TestPacket[12] = 0x00;
TestPacket[13] = 0x00;
TestPacket[TEST_LEN-1] = MAGIC_NUM;
//
// First construct TestPacket.
//
TestPacket[TEST_LEN-1] = MAGIC_NUM;
//
// Now copy down TestPacket and start the transmission.
//
(*CardCopyDownBuffer)(InterfaceType,
BusNumber,
IoBaseAddress,
MemoryBaseAddress,
TestPacket,
TEST_LEN);
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x4,
(UCHAR)(MemoryBaseAddress >> 8));
if (NtStatus != STATUS_SUCCESS)
{
return;
}
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x6,
0x0);
if (NtStatus != STATUS_SUCCESS)
{
return;
}
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x5,
(UCHAR)(TEST_LEN));
if (NtStatus != STATUS_SUCCESS)
{
return;
}
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress,
0x26);
if (NtStatus != STATUS_SUCCESS)
{
return;
}
//
// We pause here to allow the xmit to complete so that we can ACK
// it below - leaving the card in a valid state.
//
{
UCHAR i;
UCHAR RegValue;
for (i = 0; i != 0xFF; i++)
{
//
// check for send completion
//
NtStatus = DetectReadPortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0x7,
&RegValue);
if (NtStatus != STATUS_SUCCESS)
{
return;
}
if (RegValue & 0xA)
{
break;
}
}
}
//
// Turn off any interrupts
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xF,
0x00);
if (NtStatus != STATUS_SUCCESS)
{
return;
}
//
// Acknowledge any interrupts that are floating around.
//
NtStatus = DetectWritePortUchar(InterfaceType,
BusNumber,
IoBaseAddress + 0xE,
0xFF);
if (NtStatus != STATUS_SUCCESS)
{
return;
}
return;
}
BOOLEAN
GetMcaKey(
IN ULONG BusNumber,
OUT PVOID *InfoHandle
)
/*++
Routine Description:
This routine finds the Microchannel bus with BusNumber in the
registry and returns a handle for the config information.
Arguments:
BusNumber - The bus number of the bus to search for.
InfoHandle - The resulting root in the registry.
Return Value:
TRUE if nothing went wrong, else FALSE.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_ATTRIBUTES BusObjectAttributes;
PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
PWSTR ConfigData = L"Configuration Data";
UNICODE_STRING RootName;
UNICODE_STRING BusName;
UNICODE_STRING ConfigDataName;
NTSTATUS NtStatus;
PKEY_BASIC_INFORMATION BasicInformation;
PKEY_VALUE_FULL_INFORMATION ValueInformation;
PUCHAR BufferPointer;
PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
HANDLE McaHandle, BusHandle;
ULONG BytesWritten, BytesNeeded;
ULONG Index;
*InfoHandle = NULL;
if (BusNumber > 98)
{
return FALSE;
}
RtlInitUnicodeString(&RootName, McaPath);
InitializeObjectAttributes(
&ObjectAttributes,
&RootName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL);
//
// Open the root.
//
NtStatus = NtOpenKey(&McaHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(NtStatus))
{
return FALSE;
}
Index = 0;
while (TRUE)
{
//
// Enumerate through keys, searching for the proper bus number
//
NtStatus = NtEnumerateKey(
McaHandle,
Index,
KeyBasicInformation,
NULL,
0,
&BytesNeeded);
//
// That should fail!
//
if (BytesNeeded == 0)
{
Index++;
continue;
}
BasicInformation = (PKEY_BASIC_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (BasicInformation == NULL)
{
NtClose(McaHandle);
return FALSE;
}
NtStatus = NtEnumerateKey(
McaHandle,
Index,
KeyBasicInformation,
BasicInformation,
BytesNeeded,
&BytesWritten);
if (!NT_SUCCESS(NtStatus))
{
DetectFreeHeap(BasicInformation);
NtClose(McaHandle);
return FALSE;
}
//
// Init the BusName String
//
BusName.MaximumLength = (USHORT)(BasicInformation->NameLength);
BusName.Length = (USHORT)(BasicInformation->NameLength);
BusName.Buffer = BasicInformation->Name;
//
// Now try to find Configuration Data within this Key
//
InitializeObjectAttributes(
&BusObjectAttributes,
&BusName,
OBJ_CASE_INSENSITIVE,
(HANDLE)McaHandle,
NULL);
//
// Open the MCA root + Bus Number
//
NtStatus = NtOpenKey(
&BusHandle,
KEY_READ,
&BusObjectAttributes);
DetectFreeHeap(BasicInformation);
if (!NT_SUCCESS(NtStatus))
{
Index++;
continue;
}
//
// opening the configuration data. This first call tells us how
// much memory we need to allocate
//
RtlInitUnicodeString(&ConfigDataName, ConfigData);
//
// This should fail
//
NtStatus = NtQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
NULL,
0,
&BytesNeeded);
ValueInformation = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (ValueInformation == NULL)
{
Index++;
NtClose(BusHandle);
continue;
}
NtStatus = NtQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
ValueInformation,
BytesNeeded,
&BytesWritten);
if (!NT_SUCCESS(NtStatus))
{
Index++;
DetectFreeHeap(ValueInformation);
NtClose(BusHandle);
continue;
}
//
// Search for our bus number and type
//
//
// What we got back from the registry is actually a blob of data that
// looks like this
//
// ------------------------------------------
// |FULL |PAR |PAR |MCA |MCA |MCA |
// |RES. |RES |RES |POS |POS |POS | . . .
// |DESC |LIST|DESC|DATA|DATA|DATA|
// ------------------------------------------
// slot 0 1 2 . . .
//
// Out of this mess we need to grovel a pointer to the first block
// of MCA_POS_DATA, then we can just index by slot number.
//
if (ValueInformation->DataLength == 0)
{
//
// Get next key
//
DetectFreeHeap(ValueInformation);
Index++;
NtClose(BusHandle);
continue;
}
BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
if (FullResource->InterfaceType != MicroChannel)
{
//
// Get next key
//
DetectFreeHeap(ValueInformation);
Index++;
NtClose(BusHandle);
continue;
}
if (FullResource->BusNumber != BusNumber)
{
//
// Get next key
//
DetectFreeHeap(ValueInformation);
Index++;
NtClose(BusHandle);
continue;
}
//
// Found it!!
//
*InfoHandle = ValueInformation;
NtClose(McaHandle);
return(TRUE);
}
}
BOOLEAN
GetMcaPosId(
IN PVOID BusHandle,
IN ULONG SlotNumber,
OUT PULONG PosId
)
/*++
Routine Description:
This routine returns the PosId of an adapter in SlotNumber of an MCA bus.
Arguments:
BusHandle - Handle returned by GetMcaKey().
SlotNumber - the desired slot number
PosId - the PosId.
Return Value:
TRUE if nothing went wrong, else FALSE.
--*/
{
PKEY_VALUE_FULL_INFORMATION ValueInformation = (PKEY_VALUE_FULL_INFORMATION)(BusHandle);
PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
PUCHAR BufferPointer;
PCM_PARTIAL_RESOURCE_LIST ResourceList;
ULONG i;
ULONG TotalSlots;
PCM_MCA_POS_DATA PosData;
BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
ResourceList = &FullResource->PartialResourceList;
//
// Find the device-specific information, which is where the POS data is.
//
for (i = 0; i < ResourceList->Count; i++)
{
if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific)
{
break;
}
}
if (i == ResourceList->Count)
{
//
// Couldn't find device-specific information.
//
return FALSE;
}
TotalSlots = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize;
TotalSlots = TotalSlots / sizeof(CM_MCA_POS_DATA);
if (SlotNumber <= TotalSlots)
{
PosData = (PCM_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]);
PosData += (SlotNumber - 1);
*PosId = PosData->AdapterId;
return(TRUE);
}
return(FALSE);
}
VOID
DeleteMcaKey(
IN PVOID BusHandle
)
/*++
Routine Description:
This routine frees resources associated with an MCA handle.
Arguments:
BusHandle - Handle returned by GetMcaKey().
Return Value:
None.
--*/
{
DetectFreeHeap(BusHandle);
}
BOOLEAN
GetEisaKey(
IN ULONG BusNumber,
OUT PVOID *InfoHandle
)
/*++
Routine Description:
This routine finds the Eisa bus with BusNumber in the
registry and returns a handle for the config information.
Arguments:
BusNumber - The bus number of the bus to search for.
InfoHandle - The resulting root in the registry.
Return Value:
TRUE if nothing went wrong, else FALSE.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_ATTRIBUTES BusObjectAttributes;
PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
PWSTR ConfigData = L"Configuration Data";
UNICODE_STRING RootName;
UNICODE_STRING BusName;
UNICODE_STRING ConfigDataName;
NTSTATUS NtStatus;
PKEY_BASIC_INFORMATION BasicInformation;
PKEY_VALUE_FULL_INFORMATION ValueInformation;
PUCHAR BufferPointer;
PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
HANDLE EisaHandle, BusHandle;
ULONG BytesWritten, BytesNeeded;
ULONG Index;
*InfoHandle = NULL;
if (BusNumber > 98)
{
return FALSE;
}
RtlInitUnicodeString(&RootName, EisaPath);
InitializeObjectAttributes(
&ObjectAttributes,
&RootName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL);
//
// Open the root.
//
NtStatus = NtOpenKey(&EisaHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(NtStatus))
{
return FALSE;
}
Index = 0;
while (TRUE)
{
//
// Enumerate through keys, searching for the proper bus number
//
NtStatus = NtEnumerateKey(
EisaHandle,
Index,
KeyBasicInformation,
NULL,
0,
&BytesNeeded);
//
// That should fail!
//
if (BytesNeeded == 0)
{
Index++;
continue;
}
BasicInformation = (PKEY_BASIC_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (BasicInformation == NULL)
{
NtClose(EisaHandle);
return FALSE;
}
NtStatus = NtEnumerateKey(
EisaHandle,
Index,
KeyBasicInformation,
BasicInformation,
BytesNeeded,
&BytesWritten);
if (!NT_SUCCESS(NtStatus))
{
DetectFreeHeap(BasicInformation);
NtClose(EisaHandle);
return FALSE;
}
//
// Init the BusName String
//
BusName.MaximumLength = (USHORT)(BasicInformation->NameLength);
BusName.Length = (USHORT)(BasicInformation->NameLength);
BusName.Buffer = BasicInformation->Name;
//
// Now try to find Configuration Data within this Key
//
InitializeObjectAttributes(
&BusObjectAttributes,
&BusName,
OBJ_CASE_INSENSITIVE,
(HANDLE)EisaHandle,
NULL);
//
// Open the EISA root + Bus Number
//
NtStatus = NtOpenKey(&BusHandle, KEY_READ, &BusObjectAttributes);
DetectFreeHeap(BasicInformation);
if (!NT_SUCCESS(NtStatus))
{
Index++;
continue;
}
//
// opening the configuration data. This first call tells us how
// much memory we need to allocate
//
RtlInitUnicodeString(&ConfigDataName, ConfigData);
//
// This should fail
//
NtStatus = NtQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
NULL,
0,
&BytesNeeded);
ValueInformation = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (ValueInformation == NULL)
{
Index++;
NtClose(BusHandle);
continue;
}
NtStatus = NtQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
ValueInformation,
BytesNeeded,
&BytesWritten);
if (!NT_SUCCESS(NtStatus))
{
Index++;
DetectFreeHeap(ValueInformation);
NtClose(BusHandle);
continue;
}
if (ValueInformation->DataLength == 0)
{
Index++;
NtClose(BusHandle);
continue;
}
//
// Search for our bus number and type
//
BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
if (FullResource->InterfaceType != Eisa)
{
//
// Get next key
//
DetectFreeHeap(ValueInformation);
Index++;
NtClose(BusHandle);
continue;
}
if (FullResource->BusNumber != BusNumber)
{
//
// Get next key
//
DetectFreeHeap(ValueInformation);
Index++;
NtClose(BusHandle);
continue;
}
//
// Found it!!
//
*InfoHandle = ValueInformation;
NtClose(EisaHandle);
return(TRUE);
}
}
BOOLEAN
GetEisaCompressedId(
IN PVOID BusHandle,
IN ULONG SlotNumber,
OUT PULONG CompressedId,
IN ULONG Mask
)
/*++
Routine Description:
This routine returns the PosId of an adapter in SlotNumber of an Eisa bus.
Arguments:
BusHandle - Handle returned by GetEisaKey().
SlotNumber - the desired slot number
CompressedId - EISA Id in the slot desired.
Mask - Mask to apply to the ID.
Return Value:
TRUE if nothing went wrong, else FALSE.
--*/
{
PKEY_VALUE_FULL_INFORMATION ValueInformation = (PKEY_VALUE_FULL_INFORMATION)(BusHandle);
PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
PUCHAR BufferPointer;
PCM_PARTIAL_RESOURCE_LIST ResourceList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
ULONG i;
ULONG TotalDataSize;
ULONG SlotDataSize;
PCM_EISA_SLOT_INFORMATION SlotInformation;
BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
ResourceList = &FullResource->PartialResourceList;
//
// Find the device-specific information, which is where the POS data is.
//
for (i = 0; i < ResourceList->Count; i++)
{
if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific)
{
break;
}
}
if (i == ResourceList->Count)
{
//
// Couldn't find device-specific information.
//
return FALSE;
}
//
// Bingo!
//
ResourceDescriptor = &(ResourceList->PartialDescriptors[i]);
TotalDataSize = ResourceDescriptor->u.DeviceSpecificData.DataSize;
SlotInformation = (PCM_EISA_SLOT_INFORMATION)
((PUCHAR)ResourceDescriptor +
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
while (((LONG)TotalDataSize) > 0)
{
if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT)
{
SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
}
else
{
SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
SlotInformation->NumberFunctions *
sizeof(CM_EISA_FUNCTION_INFORMATION);
}
if (SlotDataSize > TotalDataSize)
{
//
// Something is wrong again
//
return FALSE;
}
if (SlotNumber != 0)
{
SlotNumber--;
SlotInformation = (PCM_EISA_SLOT_INFORMATION)
((PUCHAR)SlotInformation + SlotDataSize);
TotalDataSize -= SlotDataSize;
continue;
}
//
// This is our slot
//
break;
}
if ((SlotNumber != 0) || (TotalDataSize == 0))
{
//
// No such slot number
//
return(FALSE);
}
//
// End loop
//
*CompressedId = SlotInformation->CompressedId & Mask;
return(TRUE);
}
VOID
DeleteEisaKey(
IN PVOID BusHandle
)
/*++
Routine Description:
This routine frees resources associated with an EISA handle.
Arguments:
BusHandle - Handle returned by GetEisaKey().
Return Value:
None.
--*/
{
DetectFreeHeap(BusHandle);
}
BOOLEAN PcmciaGetCardInfo(
OUT PHANDLE phCardInfo,
IN PWSTR pCardName
)
/*+++
Description:
This routine takes a card name and finds the information for it in
the registry.
Returns:
BOOLEAN - TRUE if phCardInfo is a valid handle to the card.
Histroy:
1/4/95 [kyleb] created.
---*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
PWSTR PcmciaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs";
UNICODE_STRING RootName;
NTSTATUS Status;
HANDLE hPcmcia;
ULONG c;
ULONG cbNeeded;
ULONG cbRead;
UNICODE_STRING CardName;
UNICODE_STRING ValueName;
PKEY_VALUE_BASIC_INFORMATION pValueInfo1;
PKEY_VALUE_FULL_INFORMATION pValueInfo2;
//
// Initialize the card information handle.
//
*phCardInfo = NULL;
//
// Turn our card name into a UNICODE_STRING.
//
RtlInitUnicodeString(&CardName, pCardName);
//
// Initialize the root name with the path to
// the pcmcia card information.
//
RtlInitUnicodeString(&RootName, PcmciaPath);
//
// Initialize the attributes for the root.
//
InitializeObjectAttributes(
&ObjectAttributes,
&RootName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL);
//
// Open the root.
//
Status = NtOpenKey(&hPcmcia, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
return(FALSE);
//
// Now enumerate the adapter type passed us.
//
for (c = 0, pValueInfo1 = NULL; ; c++)
{
//
// Determine the amount of buffer space needed.
//
Status = NtEnumerateValueKey(
hPcmcia,
c,
KeyValueBasicInformation,
NULL,
0,
&cbNeeded);
if (0 == cbNeeded)
continue;
//
// Get the name of the value.
//
pValueInfo1 = (PKEY_VALUE_BASIC_INFORMATION)DetectAllocateHeap(cbNeeded);
if (NULL == pValueInfo1)
{
//
// BUGBUG
// Return that out of memory status code (i'm lazy).
//
return(FALSE);
}
//
// Read in the basic information on the value entry;
// this includes the type of the value and the name.
//
Status = NtEnumerateValueKey(
hPcmcia,
c,
KeyValueBasicInformation,
pValueInfo1,
cbNeeded,
&cbRead);
if (!NT_SUCCESS(Status))
{
DetectFreeHeap(pValueInfo1);
break;
}
//
// Turn the value name into a UNICODE_STRING.
//
ValueName.Buffer = DetectAllocateHeap(pValueInfo1->NameLength + sizeof(WCHAR));
if (NULL == ValueName.Buffer)
{
DetectFreeHeap(pValueInfo1);
break;
}
//
// Copy the string data.
//
RtlMoveMemory(ValueName.Buffer, pValueInfo1->Name, pValueInfo1->NameLength);
//
// Save the unicode string's length.
//
ValueName.Length = ValueName.MaximumLength =
(USHORT)pValueInfo1->NameLength;
//
// Place the NULL at the end of the string.
//
ValueName.Buffer[ValueName.Length / 2] = (WCHAR)'\0';
//
// We no longer need the pValueInfo1 pointer.
//
DetectFreeHeap(pValueInfo1);
//
// Is this the value that we are looking for?
//
if (RtlEqualUnicodeString(&ValueName, &CardName, TRUE))
{
//
// We have a match!
// Get the resource information and return a pointer to it.
//
//
// First query the value to determine the amount of
// resource data.
//
NtQueryValueKey(
hPcmcia,
&ValueName,
KeyValueFullInformation,
NULL,
0,
&cbNeeded);
//
// Allocate a buffer for the information.
//
pValueInfo2 = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(cbNeeded);
if (NULL == pValueInfo2)
{
DetectFreeHeap(ValueName.Buffer);
break;
}
//
// Read in the full value information.
//
Status = NtQueryValueKey(
hPcmcia,
&ValueName,
KeyValueFullInformation,
pValueInfo2,
cbNeeded,
&cbRead);
if (!NT_SUCCESS(Status))
{
//
// Free the value information.
//
DetectFreeHeap(ValueName.Buffer);
DetectFreeHeap(pValueInfo2);
break;
}
//
// We've now got what we need!
//
*phCardInfo = (HANDLE)pValueInfo2;
//
// Free up value information.
//
DetectFreeHeap(ValueName.Buffer);
break;
}
//
// Free the value information.
//
DetectFreeHeap(ValueName.Buffer);
}
//
// Close the PCMCIA registry handle.
//
NtClose(hPcmcia);
//
// Do we have any data to return?
//
if (NULL == *phCardInfo)
{
//
// We don't have any data to return to the caller.
//
return(FALSE);
}
return(TRUE);
} //** PcmciaGetCardInfo()
VOID PcmciaFreeCardInfo(
HANDLE hCardInfo
)
/*+++
Description:
This routine will free the card information that was allocated by
PcmciaGetCardInfo().
Returns:
VOID
Histroy:
1/4/95 [kyleb] created.
---*/
{
DetectFreeHeap((PVOID)hCardInfo);
} //** PcmciaFreeCardInfo()
BOOLEAN PcmciaQueryCardResource(
OUT PVOID *ppvValue,
IN HANDLE hCardInfo,
IN ULONG ulResource
)
/*+++
Description:
This routine will find the resource for the card described by
the card information handle and return it in the location
passed in.
NOTE:
THE VALUES THAT ARE RETURNED FROM THIS STRUCTURE ARE VALID
ONLY AS LONG AS THE hCardInfo PARAMETER IS!!!!!!
ONCE PcmciaFreeCardInfo() IS CALLED ON THIS HANDLE THESE
VALUES ARE TOAST.
Returns:
BOOLEAN - TRUE if the resource was successfully returned.
Histroy:
1/4/95 [kyleb] created.
---*/
{
PCM_FULL_RESOURCE_DESCRIPTOR pFullDesc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDesc;
ULONG c;
//
// Validate the handle (somewhat).
//
if (NULL == hCardInfo)
return(FALSE);
//
// Get a pointer to the resource data.
//
pFullDesc = (PVOID)((PUCHAR)hCardInfo +
((PKEY_VALUE_FULL_INFORMATION)hCardInfo)->DataOffset);
//
// Find the resource needed.
//
for (c = 0; c < pFullDesc->PartialResourceList.Count; c++)
{
//
// Get a pointer to the current resource list entry.
//
pPartialDesc = &pFullDesc->PartialResourceList.PartialDescriptors[c];
//
// Is this the one we are looking for?
//
if (pPartialDesc->Type == (UCHAR)ulResource)
{
//
// Return a pointer to the resource descriptor.
//
*ppvValue = pPartialDesc;
return(TRUE);
}
}
return(FALSE);
} //** PcmciaQueryCardResource()
VOID
NcDetectFindOtherHardware(
INTERFACE_TYPE InterfaceType,
ULONG BusNumber
)
/*++
Routine Description:
This routine will search for non-network hardware which will cause
this DLL to hang. If it finds one, it will grab those resources
so that when a Check for resource free is done it will fail.
Arguments:
InterfaceType - Any bus type.
BusNumber - The bus number of the bus in the system.
Return Value:
None.
--*/
{
SoundBlaster(InterfaceType, BusNumber);
}
NTSTATUS
NcDetectTemporaryClaimResource(
IN PNETDTECT_RESOURCE Resource
)
{
Resource->InterfaceType = Isa;
Resource->BusNumber = 0;
#if _DBG
DbgPrint(
"NcDetectTemporaryClaimResource()\n"
" Interface: %x\n"
" BusNumber: %x\n"
" Type : %s\n"
" Value : %x\n"
" Length : %x\n"
" Flags : %x\n",
Resource->InterfaceType,
Resource->BusNumber,
(Resource->Type == 1) ? "IRQ" :
(Resource->Type == 2) ? "MEMORY" :
(Resource->Type == 3) ? "PORT" : "DMA",
Resource->Value,
Resource->Length,
Resource->Flags
);
#endif
return(DetectTemporaryClaimResource(Resource));
}
NTSTATUS
NcDetectFreeSpecificTemporaryResource(
IN PNETDTECT_RESOURCE Resource
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return(DetectFreeSpecificTemporaryResource(Resource));
}
NTSTATUS
NcDetectFreeTemporaryResource(
VOID
)
{
#if _DBG
DbgPrint("NcDetectFreeTemporaryResource()\n");
#endif
return(DetectFreeTemporaryResources());
}
BOOLEAN
QueryAdapterInformation(
IN HANDLE AdapterHandle,
OUT PCOMMON_ADAPTER_INFO Adapter
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UNICODE_STRING NetDetectKeyValue;
UINT BytesNeeded;
NTSTATUS NtStatus;
PKEY_VALUE_PARTIAL_INFORMATION pValueInfo;
PWSTR Id = L"Id";
PWSTR Mask = L"Mask";
PWSTR Token = L"token";
//
// Build a unicode string to query the eisa token.
//
RtlInitUnicodeString(&NetDetectKeyValue, Token);
//
// Determine how much memory we need to get the value.
//
BytesNeeded = 0;
NtQueryValueKey(
AdapterHandle,
&NetDetectKeyValue,
KeyValuePartialInformation,
NULL,
0,
&BytesNeeded);
if (0 == BytesNeeded)
{
#if _DBG
DbgPrint("Unable to get the size of the value information for token\n");
#endif
return(FALSE);
}
//
// Allocate space to hold the partial value information.
//
pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (NULL == pValueInfo)
{
#if _DBG
DbgPrint("Unable to allocate memory for the value information for the token\n");
#endif
return(FALSE);
}
//
// Get the value information for the id.
//
NtStatus = NtQueryValueKey(
AdapterHandle,
&NetDetectKeyValue,
KeyValuePartialInformation,
pValueInfo,
BytesNeeded,
&BytesNeeded);
if (!NT_SUCCESS(NtStatus))
{
#if _DBG
DbgPrint("Failed to query the value for key index\n");
#endif
DetectFreeHeap(pValueInfo);
return(FALSE);
}
//
// Allocate memory for the token.
//
Adapter->InfId = DetectAllocateHeap(pValueInfo->DataLength + sizeof(WCHAR));
if (NULL == Adapter->InfId)
{
DetectFreeHeap(pValueInfo);
return(FALSE);
}
RtlZeroMemory(Adapter->InfId, pValueInfo->DataLength + sizeof(WCHAR));
RtlCopyMemory(Adapter->InfId, pValueInfo->Data, pValueInfo->DataLength);
//
// Free the value information pointer.
//
DetectFreeHeap(pValueInfo);
//
// Build a unicode string to query the id.
//
RtlInitUnicodeString(&NetDetectKeyValue, Id);
//
// Determine how much memory we need to get the value.
//
BytesNeeded = 0;
NtQueryValueKey(
AdapterHandle,
&NetDetectKeyValue,
KeyValuePartialInformation,
NULL,
0,
&BytesNeeded);
if (0 == BytesNeeded)
{
#if _DBG
DbgPrint("Unable to get the size of the value information for id\n");
#endif
return(FALSE);
}
//
// Allocate space to hold the partial value information.
//
pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (NULL == pValueInfo)
{
#if _DBG
DbgPrint("Unable to allocate memory for the value information for the id\n");
#endif
return(FALSE);
}
//
// Get the value information for the id.
//
NtStatus = NtQueryValueKey(
AdapterHandle,
&NetDetectKeyValue,
KeyValuePartialInformation,
pValueInfo,
BytesNeeded,
&BytesNeeded);
if (!NT_SUCCESS(NtStatus))
{
#if _DBG
DbgPrint("Failed to query the value for key index\n");
#endif
DetectFreeHeap(pValueInfo);
return(FALSE);
}
//
// Save the value.
//
Adapter->Id = *((PULONG)(pValueInfo->Data));
//
// Free the value information pointer.
//
DetectFreeHeap(pValueInfo);
//
// Build a unicode string to query the mask.
//
RtlInitUnicodeString(&NetDetectKeyValue, Mask);
//
// Determine how much memory we need to get the value.
//
BytesNeeded = 0;
NtStatus = NtQueryValueKey(
AdapterHandle,
&NetDetectKeyValue,
KeyValuePartialInformation,
NULL,
0,
&BytesNeeded);
if (STATUS_OBJECT_NAME_NOT_FOUND == NtStatus)
{
//
// If there is no mask value then assume it's the whole id
// and get out.
//
Adapter->Mask = 0xffffffff;
return(TRUE);
}
if (0 == BytesNeeded)
{
#if _DBG
DbgPrint("Unable to get the size of the value information for mask\n");
#endif
return(FALSE);
}
//
// Allocate space to hold the partial value information.
//
pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (NULL == pValueInfo)
{
#if _DBG
DbgPrint("Unable to allocate memory for the value information for the mask\n");
#endif
return(FALSE);
}
//
// Get the value information for the mask.
//
NtStatus = NtQueryValueKey(
AdapterHandle,
&NetDetectKeyValue,
KeyValuePartialInformation,
pValueInfo,
BytesNeeded,
&BytesNeeded);
if (!NT_SUCCESS(NtStatus))
{
#if _DBG
DbgPrint("Failed to query the value for key index\n");
#endif
DetectFreeHeap(pValueInfo);
return(FALSE);
}
//
// Save the value.
//
Adapter->Mask = *((PULONG)(pValueInfo->Data));
//
// Free the value information pointer.
//
DetectFreeHeap(pValueInfo);
return(TRUE);
}
BOOLEAN
GetAdapterBasicInformation(
IN HANDLE BusHandle,
IN UINT Count,
IN PKEY_BASIC_INFORMATION *pBasicInformation
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus;
UINT BytesNeeded;
PKEY_BASIC_INFORMATION BasicInfo;
//
// Determine how big an information buffer is needed.
//
NtStatus = NtEnumerateKey(
BusHandle,
Count,
KeyBasicInformation,
NULL,
0,
&BytesNeeded);
//
// allocate a buffer
//
BasicInfo = (PKEY_BASIC_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (NULL == BasicInfo)
{
#if _DBG
DbgPrint("Failed to get basic information size for key\n");
#endif
*pBasicInformation = NULL;
return(FALSE);
}
//
// Get the basic information for the key.
//
NtStatus = NtEnumerateKey(
BusHandle,
Count,
KeyBasicInformation,
BasicInfo,
BytesNeeded,
&BytesNeeded);
if (NtStatus != STATUS_SUCCESS)
{
#if _DBG
DbgPrint("Failed to get basic information for key\n");
#endif
DetectFreeHeap(BasicInfo);
*pBasicInformation = NULL;
return(FALSE);
}
*pBasicInformation = BasicInfo;
return(TRUE);
}
BOOLEAN
GetNumberOfAdaptersSupported(
IN HANDLE BusHandle,
OUT PUINT NumberOfAdapters,
OUT PUINT MaxSubKeyLength
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PKEY_FULL_INFORMATION pFullKeyInformation;
NTSTATUS NtStatus;
UINT BytesNeeded;
//
// We need to get the number of sub-keys under the bus specific
// section. To do this we need to read in the full key information.
//
NtStatus = NtQueryKey(
BusHandle,
KeyFullInformation,
NULL,
0,
&BytesNeeded);
if (NtStatus != STATUS_BUFFER_TOO_SMALL)
{
#if _DBG
DbgPrint("Failed to get the size of the full key information for the bus\n");
#endif
return(FALSE);
}
//
// Allocate a buffer for this information.
//
pFullKeyInformation = (PKEY_FULL_INFORMATION)DetectAllocateHeap(BytesNeeded);
if (NULL == pFullKeyInformation)
{
#if _DBG
DbgPrint("Failed to query the number of subkeys under bus key\n");
#endif
return(FALSE);
}
//
// Get the actual key information.
//
NtStatus = NtQueryKey(
BusHandle,
KeyFullInformation,
pFullKeyInformation,
BytesNeeded,
&BytesNeeded);
if (NtStatus != STATUS_SUCCESS)
{
#if _DBG
DbgPrint("Failed to read the full key information for the bus\n");
#endif
return(FALSE);
}
//
// Get the number of sub-keys, this is the number of adapters for the
// bus.
//
*NumberOfAdapters = pFullKeyInformation->SubKeys;
*MaxSubKeyLength = pFullKeyInformation->MaxNameLen;
//
// We are done with the key information.
//
DetectFreeHeap(pFullKeyInformation);
return(TRUE);
}
VOID
CloseBusSpecificRegistryKey(
IN HANDLE BusHandle,
IN UNICODE_STRING *NetDetectRootName
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
if (NetDetectRootName->Buffer != NULL)
{
DetectFreeHeap(NetDetectRootName->Buffer);
}
if (BusHandle != NULL)
{
NtClose(BusHandle);
}
}
BOOLEAN
OpenBusSpecificRegistryKey(
IN PWSTR DetectPath,
IN PWSTR BusName,
OUT UNICODE_STRING *NetDetectRootName,
OUT HANDLE *BusHandle
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UNICODE_STRING TempString;
OBJECT_ATTRIBUTES ObjectAttributes;
PWSTR FullDetectPath;
NTSTATUS NtStatus;
UINT FullDetectPathLength;
//
// Determine the length of the string that we need to allocate.
//
FullDetectPathLength = (wcslen(DetectPath) * sizeof(WCHAR)) +
(wcslen(BusName) * sizeof(WCHAR)) +
sizeof(WCHAR);
//
// Allocate memory for the string buffer.
//
FullDetectPath = (PWSTR)DetectAllocateHeap(FullDetectPathLength);
if (NULL == FullDetectPath)
{
#if _DBG
DbgPrint("Failed to allocate memory for the full detection path\n");
#endif
*BusHandle = NULL;
return(FALSE);
}
//
// Initialize the unicode string.
//
RtlCopyMemory(FullDetectPath, DetectPath, (wcslen(DetectPath) * sizeof(WCHAR)));
NetDetectRootName->Buffer = FullDetectPath;
NetDetectRootName->Length = (wcslen(DetectPath) * sizeof(WCHAR));
NetDetectRootName->MaximumLength = FullDetectPathLength;
//
// Append the bus name to the end of the detection path.
//
NtStatus = RtlAppendUnicodeToString(
NetDetectRootName,
BusName);
if (NtStatus != STATUS_SUCCESS)
{
#if _DBG
DbgPrint("Unable to append the bus name to the registry path!\n");
#endif
*BusHandle = NULL;
DetectFreeHeap(FullDetectPath);
return(FALSE);
}
//
// Initialize the attributes of the registry key.
//
InitializeObjectAttributes(
&ObjectAttributes,
NetDetectRootName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL);
//
// Open the key for the eisa information.
//
NtStatus = NtOpenKey(BusHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(NtStatus))
{
#if _DBG
DbgPrint("Failed to open bus key\n");
#endif
*BusHandle = NULL;
return(FALSE);
}
return(TRUE);
}
BOOLEAN
LoadAdapterInformation(
IN PWSTR BusName,
IN UINT AdapterEntrySize,
OUT PVOID *AdapterList,
OUT UINT *CountOfAdapters
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UNICODE_STRING NetDetectKeyName;
UNICODE_STRING NetDetectRootName;
OBJECT_ATTRIBUTES ObjectAttributes;
PWSTR DetectPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NDIS\\NetDetect\\";
PWSTR CurrentKeyPath;
NTSTATUS NtStatus;
HANDLE BusHandle;
HANDLE AdapterHandle;
HANDLE CurrentAdapterHandle;
ULONG Count;
PKEY_BASIC_INFORMATION pBasicKeyInformation;
ULONG BytesNeeded;
BOOLEAN fStatus;
PWSTR AdapterName;
UINT MaxSubKeyLength;
PCOMMON_ADAPTER_INFO pAdapterList;
UINT NumberOfAdapters;
BOOLEAN fBusHandleOpened = FALSE;
BOOLEAN fAllocatedAdapterList = FALSE;
BOOLEAN fAllocatedCurrentKeyPath = FALSE;
BOOLEAN fAllocatedBasicInformation = FALSE;
BOOLEAN fOpenedSubKey = FALSE;
BOOLEAN fAllocatedAdapterName = FALSE;
do
{
//
// Open the bus specific detection information.
//
fStatus = OpenBusSpecificRegistryKey(
DetectPath,
BusName,
&NetDetectRootName,
&BusHandle);
if (!fStatus)
{
break;
}
fBusHandleOpened = TRUE;
//
// Get the number of sub-keys under the bus key.
// this is the number of adapters that we will be attempting to
// detect.
//
fStatus = GetNumberOfAdaptersSupported(
BusHandle,
&NumberOfAdapters,
&MaxSubKeyLength);
if (!fStatus)
{
break;
}
//
// Allocate memory for the adapter array.
// We also need to allocate memory for the InfId or Option name.
// This extra memory is allocated at the end of the array and the
// pointers to the name are fixed up.
//
pAdapterList = (PCOMMON_ADAPTER_INFO)DetectAllocateHeap(
NumberOfAdapters * AdapterEntrySize);
if (NULL == pAdapterList)
{
#if _DBG
DbgPrint("Unable to allocate memory for the adapter information array\n");
#endif
break;
}
fAllocatedAdapterList = TRUE;
//
// Zero out the adapter list contents.
//
RtlZeroMemory(pAdapterList, NumberOfAdapters * AdapterEntrySize);
//
// Add the terminating NULL...
//
MaxSubKeyLength += sizeof(WCHAR);
//
// Build the unicode name for the adapter.
//
AdapterName = (PWSTR)DetectAllocateHeap(MaxSubKeyLength);
if (NULL == AdapterName)
{
#if _DBG
DbgPrint("Failed to allocate memory for the adapter name\n");
#endif
continue;
}
fAllocatedAdapterName = TRUE;
//
// Read in the information for each adapter.
//
for (Count = 0, fStatus = TRUE;
(Count < NumberOfAdapters) && fStatus;
Count++)
{
//
// Initialize the adapter information entry.
//
pAdapterList[Count].Index = (Count * 100) + 1000;
//
// Get an adapters basic information.
//
fStatus = GetAdapterBasicInformation(
BusHandle,
Count,
&pBasicKeyInformation);
if (!fStatus)
{
#if _DBG
DbgPrint("Failed to get the basic information for sub-key\n");
#endif
continue;
}
fAllocatedBasicInformation = TRUE;
RtlZeroMemory(AdapterName, MaxSubKeyLength);
RtlCopyMemory(
AdapterName,
pBasicKeyInformation->Name,
pBasicKeyInformation->NameLength);
//
// Construct a unicode string from the buffer that was stored
// with the adapter list. We know this will stick around for
// a while so it's cool.
//
RtlInitUnicodeString(&NetDetectKeyName, AdapterName);
//
// Initialize the attributes for the registry sub-key.
//
InitializeObjectAttributes(
&ObjectAttributes,
&NetDetectKeyName,
OBJ_CASE_INSENSITIVE,
BusHandle,
NULL);
//
// Open the sub-key so we can query it.
//
NtStatus = NtOpenKey(
&AdapterHandle,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(NtStatus))
{
#if _DBG
DbgPrint("Failed to open the sub-key index[%u]\n", Count);
#endif
fStatus = FALSE;
continue;
}
fOpenedSubKey = TRUE;
//
// Query the adapter information.
//
fStatus = QueryAdapterInformation(AdapterHandle, &pAdapterList[Count]);
if (!fStatus)
{
#if _DBG
DbgPrint("Unable to query the id for the adapter\n");
#endif
continue;
}
NtClose(AdapterHandle);
fOpenedSubKey = FALSE;
//
// Free the buffer for the basic key information.
//
DetectFreeHeap(pBasicKeyInformation);
fAllocatedBasicInformation = FALSE;
}
} while (FALSE);
if (fOpenedSubKey)
{
NtClose(AdapterHandle);
}
if (fAllocatedAdapterName)
{
DetectFreeHeap(AdapterName);
}
if (fAllocatedCurrentKeyPath)
{
DetectFreeHeap(CurrentKeyPath);
}
if (fBusHandleOpened)
{
CloseBusSpecificRegistryKey(BusHandle, &NetDetectRootName);
}
if ((Count != NumberOfAdapters) || !fStatus)
{
if (fAllocatedBasicInformation);
{
DetectFreeHeap(pBasicKeyInformation);
}
FreeAdapterInformation(pAdapterList, Count);
return(FALSE);
}
//
// Save the pointer to the adapter list.
//
*AdapterList = pAdapterList;
*CountOfAdapters = NumberOfAdapters;
return(TRUE);
}
VOID
FreeAdapterInformation(
IN PVOID AdapterList,
IN UINT NumberOfAdapters
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PCOMMON_ADAPTER_INFO pAdapterList = AdapterList;
UINT Count;
if (NULL == pAdapterList)
{
return;
}
for (Count = 0; Count < NumberOfAdapters; Count++)
{
if (NULL != pAdapterList[Count].InfId)
{
DetectFreeHeap(pAdapterList[Count].InfId);
}
}
DetectFreeHeap(pAdapterList);
}
VOID
AcquireAllPcmciaResources(
VOID
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
PWSTR PcmciaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\PCMCIA PCCARDs";
UNICODE_STRING RootName;
NTSTATUS Status;
HANDLE hPcmcia = NULL;
ULONG c;
ULONG cResource;
ULONG cbNeeded;
ULONG cbRead;
UNICODE_STRING CardName;
UNICODE_STRING ValueName;
PKEY_FULL_INFORMATION pKeyInfo;
PKEY_VALUE_BASIC_INFORMATION pValueInfo1;
PKEY_VALUE_FULL_INFORMATION pValueInfo2;
PCM_FULL_RESOURCE_DESCRIPTOR pFullResource;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResource;
NETDTECT_RESOURCE Resource;
//
// Initialize the root name with the path to
// the pcmcia card information.
//
RtlInitUnicodeString(&RootName, PcmciaPath);
//
// Initialize the attributes for the root.
//
InitializeObjectAttributes(
&ObjectAttributes,
&RootName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL);
//
// Open the root.
//
Status = NtOpenKey(&hPcmcia, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DBGPRINT(("Failed to open the PCMCIA PCCARDs registry key\n"));
DBGPRINT(("<==AcquireAllPcmciaResources\n"));
return;
}
//
// Get the number of keys
//
NtQueryKey(hPcmcia, KeyFullInformation, NULL, 0, &cbNeeded);
pKeyInfo = (PKEY_FULL_INFORMATION)DetectAllocateHeap(cbNeeded);
if (NULL == pKeyInfo)
{
DBGPRINT(("Failed to allocate a buffer for the full key information\n"));
return;
}
Status = NtQueryKey(
hPcmcia,
KeyFullInformation,
pKeyInfo,
sizeof(KEY_FULL_INFORMATION),
&cbRead);
if (!NT_SUCCESS(Status))
{
DBGPRINT(("Failed to read the full key information. Status 0x%x\n", Status));
DetectFreeHeap(pKeyInfo);
return;
}
pValueInfo1 = NULL;
ValueName.Buffer = NULL;
//
// Now enumerate the adapter type passed us.
//
for (c = 0, pValueInfo1 = NULL; c < pKeyInfo->Values; c++)
{
//
// Determine the amount of buffer space needed.
//
NtEnumerateValueKey(
hPcmcia,
c,
KeyValueBasicInformation,
NULL,
0,
&cbNeeded);
//
// Get the name of the value.
//
pValueInfo1 = (PKEY_VALUE_BASIC_INFORMATION)DetectAllocateHeap(cbNeeded);
if (NULL == pValueInfo1)
{
DBGPRINT(("Failed to allocate space for basic value information\n"));
break;
}
//
// Read in the basic information on the value entry;
// this includes the type of the value and the name.
//
Status = NtEnumerateValueKey(
hPcmcia,
c,
KeyValueBasicInformation,
pValueInfo1,
cbNeeded,
&cbRead);
if (!NT_SUCCESS(Status))
{
DBGPRINT(("Failed to read in the basic information. Status 0x%x\n", Status));
break;
}
//
// Turn the value name into a UNICODE_STRING.
//
ValueName.Buffer = DetectAllocateHeap(pValueInfo1->NameLength + sizeof(WCHAR));
if (NULL == ValueName.Buffer)
{
DBGPRINT(("Failed to allocate buffer for the value name\n"));
break;
}
//
// Copy the string data.
//
RtlMoveMemory(ValueName.Buffer, pValueInfo1->Name, pValueInfo1->NameLength);
//
// Save the unicode string's length.
//
ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInfo1->NameLength;
//
// Place the NULL at the end of the string.
//
ValueName.Buffer[ValueName.Length / 2] = (WCHAR)'\0';
//
// We no longer need the pValueInfo1 pointer.
//
DetectFreeHeap(pValueInfo1);
pValueInfo1 = NULL;
//
// First query the value to determine the amount of resource data.
//
NtQueryValueKey(
hPcmcia,
&ValueName,
KeyValueFullInformation,
NULL,
0,
&cbNeeded);
//
// Allocate a buffer for the information.
//
pValueInfo2 = (PKEY_VALUE_FULL_INFORMATION)DetectAllocateHeap(cbNeeded);
if (NULL == pValueInfo2)
{
DBGPRINT(("Failed to allocate memory for te full value information\n"));
break;
}
//
// Read in the full value information.
//
Status = NtQueryValueKey(
hPcmcia,
&ValueName,
KeyValueFullInformation,
pValueInfo2,
cbNeeded,
&cbRead);
if (!NT_SUCCESS(Status))
{
DBGPRINT(("Failed to query the full value information. Status 0x%x\n", Status));
break;
}
//
// Go through the resources and acquire them.
// we will ignore any conflicts to acquire.
//
pFullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)
((PUCHAR)pValueInfo2 + pValueInfo2->DataOffset);
for (cResource = 0; cResource < pFullResource->PartialResourceList.Count; cResource++)
{
//
// Get a pointer to the current resource.
//
pPartialResource = &pFullResource->PartialResourceList.PartialDescriptors[cResource];
//
// Acquire the resource.
//
RtlZeroMemory(&Resource, sizeof(NETDTECT_RESOURCE));
Resource.InterfaceType = Isa;
Resource.BusNumber = 0;
Resource.Flags = 0;
switch (pPartialResource->Type)
{
case CmResourceTypePort:
Resource.Type = NETDTECT_PORT_RESOURCE;
Resource.Value = pPartialResource->u.Port.Start.LowPart;
Resource.Length = pPartialResource->u.Port.Length;
break;
case CmResourceTypeInterrupt:
Resource.Type = NETDTECT_IRQ_RESOURCE;
Resource.Value = pPartialResource->u.Interrupt.Level;
Resource.Length = 0;
break;
case CmResourceTypeMemory:
Resource.Type = NETDTECT_MEMORY_RESOURCE;
Resource.Value = pPartialResource->u.Memory.Start.LowPart;
Resource.Length = pPartialResource->u.Memory.Length;
break;
case CmResourceTypeDma:
Resource.Type = NETDTECT_DMA_RESOURCE;
Resource.Value = pPartialResource->u.Dma.Channel;
Resource.Length = 0;
break;
}
DetectTemporaryClaimResource(&Resource);
}
//
// Free up value information.
//
DetectFreeHeap(ValueName.Buffer);
ValueName.Buffer = NULL;
//
// Free the value information.
//
DetectFreeHeap(pValueInfo2);
pValueInfo2 = NULL;
}
//
// Free any allocated memory.
//
if (NULL != ValueName.Buffer)
{
DetectFreeHeap(ValueName.Buffer);
}
if (NULL != pValueInfo1)
{
DetectFreeHeap(pValueInfo1);
}
if (NULL != pValueInfo2)
{
DetectFreeHeap(pValueInfo2);
}
//
// Free the PCMCIA PCCARDs full key information.
//
if (NULL != pKeyInfo)
{
DetectFreeHeap(pKeyInfo);
}
//
// Close the PCMCIA registry handle.
//
if (hPcmcia != NULL)
{
NtClose(hPcmcia);
}
}