windows-nt/Source/XPSP1/NT/net/rndis/rndismp/wdmutil.c
2020-09-26 16:20:57 +08:00

475 lines
20 KiB
C

/***************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name:
WDMUTIL.C
Abstract:
Stuff that does not fit well with NDIS header files
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
Revision History:
5/17/99 : created
Author:
Tom Green
****************************************************************************/
#include "precomp.h"
/****************************************************************************/
/* DeviceObjectToDriverObject */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Get driver object associated with device object. NDIS has no notion */
/* of the shape of a device object, so we put this here for ease of */
/* building *
/* */
/* Arguments: */
/* */
/* DeviceObject - device object we to get associated driver object for */
/* */
/* Return: */
/* */
/* PDRIVER_OBJECT */
/* */
/****************************************************************************/
PDRIVER_OBJECT
DeviceObjectToDriverObject(IN PDEVICE_OBJECT DeviceObject)
{
return DeviceObject->DriverObject;
} // DeviceObjectToDriverObject
/****************************************************************************/
/* GetDeviceFriendlyName */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Return the friendly name associated with the given device object. */
/* */
/* Arguments: */
/* */
/* pDeviceObject - device object we to get associated driver object for */
/* ppName - Place to return a pointer to an ANSI string containing name */
/* pNameLength - Place to return length of above string */
/* */
/* Return: */
/* */
/* NTSTATUS */
/* */
/****************************************************************************/
NTSTATUS
GetDeviceFriendlyName(IN PDEVICE_OBJECT pDeviceObject,
OUT PANSI_STRING pAnsiName,
OUT PUNICODE_STRING pUnicodeName)
{
NTSTATUS NtStatus;
NDIS_STATUS Status;
ULONG ResultLength;
DEVICE_REGISTRY_PROPERTY Property;
UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString;
USHORT AnsiMaxLength;
PWCHAR pValueInfo;
ULONG i;
pValueInfo = NULL;
AnsiString.Buffer = NULL;
do
{
Property = DevicePropertyFriendlyName;
for (i = 0; i < 2; i++)
{
NtStatus = IoGetDeviceProperty(pDeviceObject,
Property,
0,
NULL,
&ResultLength);
if (NtStatus != STATUS_BUFFER_TOO_SMALL)
{
ASSERT(!NT_SUCCESS(NtStatus));
Property = DevicePropertyDeviceDescription;
}
}
Status = MemAlloc(&pValueInfo, ResultLength);
if (Status != NDIS_STATUS_SUCCESS)
{
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
NtStatus = IoGetDeviceProperty(pDeviceObject,
Property,
ResultLength,
pValueInfo,
&ResultLength);
if (NtStatus != STATUS_SUCCESS)
{
TRACE1(("IoGetDeviceProperty returned %x\n", NtStatus));
break;
}
RtlInitUnicodeString(&UnicodeString, pValueInfo);
//
// Allocate space for ANSI version.
//
AnsiMaxLength = UnicodeString.MaximumLength / sizeof(WCHAR);
Status = MemAlloc(&AnsiString.Buffer, AnsiMaxLength);
if (Status != NDIS_STATUS_SUCCESS)
{
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlFillMemory(AnsiString.Buffer, AnsiMaxLength, 0);
AnsiString.MaximumLength = AnsiMaxLength;
AnsiString.Length = 0;
NtStatus = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
if (!NT_SUCCESS(NtStatus))
{
ASSERT(FALSE);
break;
}
*pAnsiName = AnsiString;
*pUnicodeName = UnicodeString;
break;
}
while (FALSE);
if (!NT_SUCCESS(NtStatus))
{
if (pValueInfo)
{
MemFree(pValueInfo, -1);
}
if (AnsiString.Buffer)
{
MemFree(AnsiString.Buffer, AnsiString.MaximumLength);
}
}
return (NtStatus);
}
/****************************************************************************/
/* HookPnpDispatchRoutine */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Set up the driver object for the specified microport driver to */
/* intercept the IRP_MJ_PNP dispatch routine before it gets to NDIS. */
/* This is in order to support surprise removal on platforms where we */
/* don't have NDIS 5.1 support. If we are running on >= NDIS 5.1, don't */
/* do anything. */
/* */
/* Arguments: */
/* */
/* DriverBlock - pointer to driver block structure for this microport. */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
HookPnpDispatchRoutine(IN PDRIVER_BLOCK DriverBlock)
{
if ((DriverBlock->MajorNdisVersion <= 5) ||
((DriverBlock->MajorNdisVersion == 5) && (DriverBlock->MinorNdisVersion < 1)))
{
DriverBlock->SavedPnPDispatch =
DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP];
DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP] = PnPDispatch;
}
}
/****************************************************************************/
/* PnPDispatch */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Dispatch routine for IRP_MJ_PNP that is called by the I/O system. */
/* We process surprise removal and query capabilities. */
/* In all cases, we pass on the IRP to NDIS for further processing. */
/* */
/* Arguments: */
/* */
/* pDeviceObject - pointer to Device Object */
/* pIrp - pointer to IRP */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
NTSTATUS
PnPDispatch(IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp)
{
PIO_STACK_LOCATION pIrpSp;
NTSTATUS Status;
PDRIVER_BLOCK DriverBlock;
PRNDISMP_ADAPTER pAdapter;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
DeviceObjectToAdapterAndDriverBlock(pDeviceObject, &pAdapter, &DriverBlock);
TRACE3(("PnPDispatch: Adapter %x, MinorFunction %x\n",
pAdapter, pIrpSp->MinorFunction));
switch (pIrpSp->MinorFunction)
{
case IRP_MN_QUERY_CAPABILITIES:
pIrpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = 1;
break;
case IRP_MN_SURPRISE_REMOVAL:
TRACE1(("PnPDispatch: PDO %p, Adapter %p, surprise removal!\n",
pDeviceObject, pAdapter));
if (pAdapter)
{
RndismpInternalHalt((NDIS_HANDLE)pAdapter, FALSE);
}
break;
default:
break;
}
Status = (DriverBlock->SavedPnPDispatch)(
pDeviceObject,
pIrp);
return (Status);
}
#ifdef BUILD_WIN9X
/****************************************************************************/
/* HookNtKernCMHandler */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Swap the CM handler routine within NDIS' data structures such that */
/* we get called when NDIS forwards a CM message. This can only work on */
/* Win98 and Win98SE. */
/* */
/* Arguments: */
/* */
/* Adapter - pointer to our adapter block */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
HookNtKernCMHandler(IN PRNDISMP_ADAPTER pAdapter)
{
PVOID pNdisWrapperAdapterBlock;
PVOID pDetect;
ULONG WrapContextOffset;
pDetect = (PVOID)((ULONG_PTR)pAdapter->MiniportAdapterHandle + 0x29c);
if (*(PVOID *)pDetect == (PVOID)pAdapter->pPhysDeviceObject)
{
// Win98Gold
WrapContextOffset = 0xf8;
pAdapter->bRunningOnWin98Gold = TRUE;
}
else
{
// Win98SE
WrapContextOffset = 0x60;
pAdapter->bRunningOnWin98Gold = FALSE;
}
pAdapter->WrapContextOffset = WrapContextOffset;
pNdisWrapperAdapterBlock = *(PVOID *)((ULONG_PTR)pAdapter->MiniportAdapterHandle + WrapContextOffset);
// Save away the old handler:
pAdapter->NdisCmConfigHandler = (MY_CMCONFIGHANDLER)
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x78));
// Insert our routine:
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x78)) =
(PVOID)RndisCMHandler;
// Save the devnode to use on lookups based on devnode:
pAdapter->DevNode = (MY_DEVNODE)
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x38));
TRACE1(("HookNtKernCMHandler: Adapter %p, NdisHandler %p, DevNode %x\n",
pAdapter, pAdapter->NdisCmConfigHandler, pAdapter->DevNode));
}
/****************************************************************************/
/* UnHookNtKernCMHandler */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Put back the swapped Config Mgr handler in NDIS' data structures */
/* */
/* Arguments: */
/* */
/* Adapter - pointer to our adapter block */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
UnHookNtKernCMHandler(IN PRNDISMP_ADAPTER pAdapter)
{
PVOID pNdisWrapperAdapterBlock;
if (pAdapter->NdisCmConfigHandler)
{
pNdisWrapperAdapterBlock = *(PVOID *)((ULONG_PTR)pAdapter->MiniportAdapterHandle + pAdapter->WrapContextOffset);
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x78)) =
(PVOID)pAdapter->NdisCmConfigHandler;
}
TRACE1(("UnhookNtKernCMHandler: Adapter %p, NdisHandler %p, DevNode %x\n",
pAdapter, pAdapter->NdisCmConfigHandler, pAdapter->DevNode));
}
/****************************************************************************/
/* RndisCMHandler */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Handler to intercept Config Mgr messages forwarded by NDIS. The only */
/* message of interest is a CONFIG_PREREMOVE, which is our only indication */
/* on Win98 and Win98SE that the device is being removed. */
/* */
/* Arguments: */
/* */
/* Various - documented in Win9x CFmgr header. */
/* */
/* Return: */
/* */
/* MY_CONFIGRET */
/* */
/****************************************************************************/
MY_CONFIGRET __cdecl
RndisCMHandler(IN MY_CONFIGFUNC cfFuncName,
IN MY_SUBCONFIGFUNC cfSubFuncName,
IN MY_DEVNODE cfDevNode,
IN ULONG dwRefData,
IN ULONG ulFlags)
{
PRNDISMP_ADAPTER pAdapter, pTmpAdapter;
PDRIVER_BLOCK pDriverBlock;
MY_CONFIGRET crRetCode;
do
{
//
// Find the adapter to which this is addressed.
//
pAdapter = NULL;
NdisAcquireSpinLock(&RndismpGlobalLock);
for (pDriverBlock = RndismpMiniportBlockListHead.NextDriverBlock;
(pDriverBlock != NULL) && (pAdapter == NULL);
pDriverBlock = pDriverBlock->NextDriverBlock)
{
for (pTmpAdapter = pDriverBlock->AdapterList;
pTmpAdapter != NULL;
pTmpAdapter = pTmpAdapter->NextAdapter)
{
if (pTmpAdapter->DevNode == cfDevNode)
{
pAdapter = pTmpAdapter;
break;
}
}
}
NdisReleaseSpinLock(&RndismpGlobalLock);
ASSERT(pAdapter != NULL);
TRACE1(("CMHandler: Adapter %p, CfFuncName %x\n",
pAdapter, cfFuncName));
//
// Forward this on before acting on it.
//
if (pAdapter &&
(pAdapter->NdisCmConfigHandler != NULL))
{
crRetCode = pAdapter->NdisCmConfigHandler(
cfFuncName,
cfSubFuncName,
cfDevNode,
dwRefData,
ulFlags);
if ((cfFuncName == MY_CONFIG_PREREMOVE) ||
((cfFuncName == MY_CONFIG_PRESHUTDOWN) &&
(pAdapter->bRunningOnWin98Gold)))
{
RndismpInternalHalt((NDIS_HANDLE)pAdapter, FALSE);
}
}
else
{
crRetCode = MY_CR_SUCCESS;
}
}
while (FALSE);
return (crRetCode);
}
#endif // BUILD_WIN9X