473 lines
17 KiB
C
473 lines
17 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
net.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Process NetCards section of WINBOM.INI
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Donald McNamara (donaldm) 5/11/2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
#include "factoryp.h"
|
||
|
|
||
|
// UpdateDriverForPlugAndPlayDevices constants
|
||
|
#include <newdev.h>
|
||
|
|
||
|
|
||
|
|
||
|
// for run-time loading of newdev.dll
|
||
|
typedef BOOL (WINAPI *ExternalUpdateDriverForPlugAndPlayDevicesW)
|
||
|
(
|
||
|
HWND hwndParent,
|
||
|
LPCWSTR HardwareId,
|
||
|
LPCWSTR FullInfPath,
|
||
|
DWORD InstallFlags,
|
||
|
PBOOL bRebootRequired OPTIONAL
|
||
|
);
|
||
|
|
||
|
extern CONFIGRET CMP_WaitServicesAvailable(IN HMACHINE hMachine);
|
||
|
|
||
|
//
|
||
|
// function prototypes
|
||
|
//
|
||
|
BOOL
|
||
|
SetupRegistryForRemoteBoot(
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
InstallNetworkCard(
|
||
|
LPTSTR lpszWinBOMPath,
|
||
|
BOOL bForceIDScan
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function installs all network card found in the system.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns TRUE if there are no fatal errors.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
HINSTANCE hInstNewDev;
|
||
|
ExternalUpdateDriverForPlugAndPlayDevicesW pUpdateDriverForPlugAndPlayDevicesW = NULL;
|
||
|
|
||
|
// We need the "UpdateDriverForPlugAndPlayDevices" function from newdev.dll.
|
||
|
//
|
||
|
if ( NULL == (hInstNewDev = LoadLibrary(L"newdev.dll")) )
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, L"Failed to load newdev.dll. Error = %d", GetLastError());
|
||
|
return bRet;
|
||
|
}
|
||
|
pUpdateDriverForPlugAndPlayDevicesW =
|
||
|
(ExternalUpdateDriverForPlugAndPlayDevicesW) GetProcAddress(hInstNewDev, "UpdateDriverForPlugAndPlayDevicesW");
|
||
|
if ( NULL == pUpdateDriverForPlugAndPlayDevicesW )
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, L"Failed to get UpdateDriverForPlugAndPlayDevicesW. Error = %d", GetLastError());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BOOL bRebootFlag = FALSE;
|
||
|
|
||
|
// Need to ensure that pnp services are available.
|
||
|
//
|
||
|
CMP_WaitServicesAvailable(NULL);
|
||
|
|
||
|
if ( !bForceIDScan )
|
||
|
{
|
||
|
LPTSTR lpszHardwareId;
|
||
|
|
||
|
// Now check to see if there are any PNP ids in the [NetCards] section of the winbom.
|
||
|
//
|
||
|
LPTSTR lpszNetCards = IniGetString(lpszWinBOMPath, WBOM_NETCARD_SECTION, NULL, NULLSTR);
|
||
|
|
||
|
// Check to make sure that we have a valid string
|
||
|
//
|
||
|
if ( lpszNetCards )
|
||
|
{
|
||
|
for ( lpszHardwareId = lpszNetCards; *lpszHardwareId; lpszHardwareId += (lstrlen(lpszHardwareId) + 1) )
|
||
|
{
|
||
|
// Get the INF name
|
||
|
//
|
||
|
LPTSTR lpszInfFileName = IniGetExpand(lpszWinBOMPath, WBOM_NETCARD_SECTION, lpszHardwareId, NULLSTR);
|
||
|
|
||
|
// At this point lpHardwareId is the PNP id for a network card that we want to install and
|
||
|
// lpszInfFileName is the name of the Inf to use to install this card.
|
||
|
//
|
||
|
if ( lpszInfFileName && *lpszInfFileName && *lpszHardwareId )
|
||
|
{
|
||
|
if ( pUpdateDriverForPlugAndPlayDevicesW(NULL,
|
||
|
lpszHardwareId,
|
||
|
lpszInfFileName,
|
||
|
INSTALLFLAG_READONLY,
|
||
|
&bRebootFlag) )
|
||
|
{
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, L"Failed to install network driver listed in the NetCards section. Hardware ID: %s, InfName: %s, Error = %d.", lpszHardwareId, lpszInfFileName, GetLastError());
|
||
|
|
||
|
//
|
||
|
// Not setting bRet to FALSE here since it is FALSE by default, and
|
||
|
// if we succesfully install at least one network card we want to return TRUE.
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
FREE(lpszInfFileName);
|
||
|
}
|
||
|
}
|
||
|
FREE(lpszNetCards);
|
||
|
}
|
||
|
else // if ( bForceIDScan )
|
||
|
{
|
||
|
HDEVINFO DeviceInfoSet = NULL;
|
||
|
|
||
|
// Get the list of all present devices.
|
||
|
//
|
||
|
DeviceInfoSet = SetupDiGetClassDevs(NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
DIGCF_ALLCLASSES);
|
||
|
|
||
|
if ( INVALID_HANDLE_VALUE == DeviceInfoSet )
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, L"Failed SetupDiGetClassDevsEx(). Error = %d", GetLastError());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dwDevice;
|
||
|
SP_DEVINFO_DATA DeviceInfoData;
|
||
|
|
||
|
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||
|
|
||
|
// Loop through all the devices.
|
||
|
//
|
||
|
for ( dwDevice = 0; SetupDiEnumDeviceInfo(DeviceInfoSet, dwDevice, &DeviceInfoData); dwDevice++ )
|
||
|
{
|
||
|
SP_DEVINSTALL_PARAMS DeviceInstallParams = {0};
|
||
|
SP_DRVINFO_DATA DriverInfoData = {0};
|
||
|
ULONG ulStatus = 0,
|
||
|
ulProblemNumber = 0;
|
||
|
|
||
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
||
|
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
||
|
|
||
|
// If we can get the dev node status and the devnode does have a problem, then
|
||
|
// build a list of possible drivers for this device and select the best one.
|
||
|
// Otherwise just skip this this device.
|
||
|
//
|
||
|
if ( ( CR_SUCCESS == CM_Get_DevNode_Status(&ulStatus, &ulProblemNumber, DeviceInfoData.DevInst, 0) ) &&
|
||
|
( ( IsRemoteBoot() &&
|
||
|
IsEqualGUID(&DeviceInfoData.ClassGuid, (LPGUID)&GUID_DEVCLASS_NET) ) ||
|
||
|
( ulStatus & (DN_HAS_PROBLEM | DN_PRIVATE_PROBLEM) ) ) &&
|
||
|
SetupDiBuildDriverInfoList(DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER) )
|
||
|
{
|
||
|
if ( ( SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV, DeviceInfoSet, &DeviceInfoData) ) &&
|
||
|
( SetupDiGetSelectedDriver(DeviceInfoSet, &DeviceInfoData, &DriverInfoData) ) )
|
||
|
{
|
||
|
//
|
||
|
// DriverInfoData contains details about the best driver, we can now see if this is a NET driver
|
||
|
// as at this point the class will have been modified to NET if best driver is a NET driver.
|
||
|
// Compare DeviceInfoData.ClassGuid against NET class GUID. If no match, skip.
|
||
|
// Otherwise get DRVINFO_DETAIL_DATA into a resizable buffer to get HardwareID.
|
||
|
// Use The HardwareID and InfFileName entries in DRVINFO_DETAIL_DATA
|
||
|
// to pass into UpdateDriverForPlugAndPlayDevices.
|
||
|
// DO NOT pass FORCE flag into UpdateDriverForPlugAndPlayDevices.
|
||
|
//
|
||
|
if ( IsEqualGUID(&DeviceInfoData.ClassGuid, (LPGUID)&GUID_DEVCLASS_NET) )
|
||
|
{
|
||
|
DWORD cbBytesNeeded = 0;
|
||
|
PSP_DRVINFO_DETAIL_DATA pDriverInfoDetailData = NULL;
|
||
|
|
||
|
if ( ( ( SetupDiGetDriverInfoDetail(DeviceInfoSet,
|
||
|
&DeviceInfoData,
|
||
|
&DriverInfoData,
|
||
|
NULL,
|
||
|
0,
|
||
|
&cbBytesNeeded) ) ||
|
||
|
( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) ) &&
|
||
|
|
||
|
( cbBytesNeeded ) &&
|
||
|
|
||
|
( pDriverInfoDetailData = MALLOC( cbBytesNeeded) ) &&
|
||
|
|
||
|
( 0 != (pDriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA)) ) &&
|
||
|
|
||
|
( SetupDiGetDriverInfoDetail(DeviceInfoSet,
|
||
|
&DeviceInfoData,
|
||
|
&DriverInfoData,
|
||
|
pDriverInfoDetailData,
|
||
|
cbBytesNeeded,
|
||
|
NULL) ) )
|
||
|
{
|
||
|
if ( pUpdateDriverForPlugAndPlayDevicesW(NULL,
|
||
|
pDriverInfoDetailData->HardwareID,
|
||
|
pDriverInfoDetailData->InfFileName,
|
||
|
INSTALLFLAG_READONLY,
|
||
|
&bRebootFlag) )
|
||
|
{
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FacLogFileStr(3 | LOG_ERR, L"Failed to install network driver. Error = %d", GetLastError());
|
||
|
|
||
|
//
|
||
|
// Not setting bRet to FALSE here since it is FALSE by default, and
|
||
|
// if we succesfully install at least one network card we want to return TRUE.
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
// Free this if allocated. Macro checks for NULL.
|
||
|
//
|
||
|
FREE ( pDriverInfoDetailData );
|
||
|
}
|
||
|
}
|
||
|
SetupDiDestroyDriverInfoList(DeviceInfoSet, &DeviceInfoData, SPDIT_COMPATDRIVER);
|
||
|
}
|
||
|
}
|
||
|
// Make sure we clean up the list.
|
||
|
//
|
||
|
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If remote boot then do the necessary registry processing
|
||
|
// so that upper level protocol drivers can bind & work
|
||
|
// correctly with already created device objects
|
||
|
//
|
||
|
if (bRet && IsRemoteBoot())
|
||
|
{
|
||
|
bRet = SetupRegistryForRemoteBoot();
|
||
|
}
|
||
|
|
||
|
FreeLibrary(hInstNewDev);
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL SetupNetwork(LPSTATEDATA lpStateData)
|
||
|
{
|
||
|
LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath;
|
||
|
BOOL bRet = TRUE;
|
||
|
TCHAR szScratch[MAX_PATH] = NULLSTR;
|
||
|
|
||
|
if ( GetPrivateProfileString(WBOM_FACTORY_SECTION, WBOM_FACTORY_FORCEIDSCAN, NULLSTR, szScratch, AS(szScratch), lpszWinBOMPath) )
|
||
|
{
|
||
|
if ( LSTRCMPI(szScratch, _T("NO")) == 0 )
|
||
|
FacLogFile(1, IDS_LOG_NONET);
|
||
|
else
|
||
|
{
|
||
|
// Attempt to install the Net card using the [NetCards] section of the WINBOM
|
||
|
//
|
||
|
if ( !InstallNetworkCard(lpszWinBOMPath, FALSE) )
|
||
|
{
|
||
|
FacLogFile(1, IDS_LOG_FORCEDNETSCAN);
|
||
|
|
||
|
// Attempt a forced scan of all network capable devices
|
||
|
//
|
||
|
if ( !InstallNetworkCard(lpszWinBOMPath, TRUE) )
|
||
|
{
|
||
|
FacLogFile(0 | LOG_ERR, IDS_ERR_FAILEDNETDRIVER);
|
||
|
bRet = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// constant strings for remote boot
|
||
|
//
|
||
|
#define NET_CLASS_DEVICE_INSTANCE_PATH TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000")
|
||
|
#define NETCFG_INSTANCEID_VALUE_NAME TEXT("NetCfgInstanceId")
|
||
|
|
||
|
#define NETBOOTCARD_ROOT_DEVICE_NAME TEXT("\\Device\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E}")
|
||
|
#define NETBOOTCARD_NETBT_DEVICE_NAME TEXT("\\Device\\NetBT_Tcpip_{54C7D140-09EF-11D1-B25A-F5FE627ED95E}")
|
||
|
|
||
|
#define ROOT_DEVICE_NAME_PREFIX TEXT("\\Device\\")
|
||
|
#define NETBT_DEVICE_NAME_PREFIX TEXT("\\Device\\NetBT_Tcpip_")
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
CreateSymbolicLink(
|
||
|
IN PWSTR LinkObjectName,
|
||
|
IN PWSTR ExistingObjectName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Creates a premanent symbolic link object linking it to the
|
||
|
specified destination object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LinkObjectName - The name of the link object that needs
|
||
|
to be created.
|
||
|
|
||
|
ExistingObjectName - The object which the link object needs
|
||
|
to resolve to (i.e. points to).
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Appropriate NTSTATUS code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
||
|
|
||
|
if (LinkObjectName && ExistingObjectName) {
|
||
|
OBJECT_ATTRIBUTES Attrs;
|
||
|
UNICODE_STRING LinkName, LinkTarget;
|
||
|
HANDLE LinkHandle;
|
||
|
|
||
|
RtlInitUnicodeString(&LinkName, LinkObjectName);
|
||
|
RtlInitUnicodeString(&LinkTarget, ExistingObjectName);
|
||
|
|
||
|
InitializeObjectAttributes(&Attrs,
|
||
|
&LinkName,
|
||
|
(OBJ_CASE_INSENSITIVE | OBJ_PERMANENT),
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
Status = NtCreateSymbolicLinkObject(&LinkHandle,
|
||
|
SYMBOLIC_LINK_ALL_ACCESS,
|
||
|
&Attrs,
|
||
|
&LinkTarget);
|
||
|
|
||
|
if (NT_SUCCESS(Status)) {
|
||
|
NtClose(LinkHandle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SetupRegistryForRemoteBoot(
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Munges the registry and sets up the required entries for
|
||
|
upper layer protocol drivers to see that a valid NIC is
|
||
|
installed.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if successful, otherwise FALSE.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL Result = FALSE;
|
||
|
HKEY InstanceKey;
|
||
|
DWORD ErrorCode;
|
||
|
|
||
|
//
|
||
|
// Open the remote boot network card instance
|
||
|
//
|
||
|
ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
|
NET_CLASS_DEVICE_INSTANCE_PATH,
|
||
|
0,
|
||
|
KEY_READ,
|
||
|
&InstanceKey);
|
||
|
|
||
|
if (ERROR_SUCCESS == ErrorCode) {
|
||
|
TCHAR NetCfgInstanceId[MAX_PATH] = {0};
|
||
|
LONG BufferSize = sizeof(NetCfgInstanceId);
|
||
|
|
||
|
//
|
||
|
// get the instance id
|
||
|
//
|
||
|
ErrorCode = RegQueryValueEx(InstanceKey,
|
||
|
NETCFG_INSTANCEID_VALUE_NAME,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
(LPBYTE)NetCfgInstanceId,
|
||
|
&BufferSize);
|
||
|
|
||
|
if (ERROR_SUCCESS == ErrorCode) {
|
||
|
WCHAR LinkName[MAX_PATH*2] = {0};
|
||
|
NTSTATUS Status;
|
||
|
BOOLEAN OldState;
|
||
|
|
||
|
Result = TRUE;
|
||
|
|
||
|
//
|
||
|
// get the privilege for creating permanent
|
||
|
// links
|
||
|
//
|
||
|
RtlAdjustPrivilege(SE_CREATE_PERMANENT_PRIVILEGE,
|
||
|
TRUE,
|
||
|
FALSE,
|
||
|
&OldState);
|
||
|
|
||
|
//
|
||
|
// create the root device link
|
||
|
//
|
||
|
lstrcpyn ( LinkName, ROOT_DEVICE_NAME_PREFIX, AS ( LinkName ) );
|
||
|
if ( FAILED ( StringCchCat ( LinkName, AS ( LinkName ) , NetCfgInstanceId) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), LinkName, NetCfgInstanceId ) ;
|
||
|
}
|
||
|
|
||
|
Status = CreateSymbolicLink(LinkName,
|
||
|
NETBOOTCARD_ROOT_DEVICE_NAME);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
Result = FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// create the NetBT device link
|
||
|
//
|
||
|
lstrcpyn ( LinkName, NETBT_DEVICE_NAME_PREFIX, AS ( LinkName ) );
|
||
|
if ( FAILED ( StringCchCat ( LinkName, AS ( LinkName ) , NetCfgInstanceId) ) )
|
||
|
{
|
||
|
FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), LinkName, NetCfgInstanceId ) ;
|
||
|
}
|
||
|
|
||
|
Status = CreateSymbolicLink(LinkName,
|
||
|
NETBOOTCARD_NETBT_DEVICE_NAME);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
Result = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|