windows-nt/Source/XPSP1/NT/net/rndis/rndismp/rndismp.c

2670 lines
108 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/***************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name:
RNDISMP.C
Abstract:
Remote NDIS Miniport driver. Sits on top of Remote NDIS bus specific
layers.
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/6/99 : created
Author:
Tom Green
****************************************************************************/
#include "precomp.h"
//
// miniport driver block list (miniport layer may support several microports)
//
DRIVER_BLOCK RndismpMiniportBlockListHead = {0};
UINT RndismpNumMicroports = 0;
NDIS_SPIN_LOCK RndismpGlobalLock;
ULONG RndisForceReset = FALSE;
#ifdef TESTING
UCHAR OffloadBuffer[sizeof(NDIS_TASK_OFFLOAD_HEADER) +
sizeof(NDIS_TASK_OFFLOAD) +
sizeof(NDIS_TASK_TCP_IP_CHECKSUM)];
PUCHAR pOffloadBuffer = OffloadBuffer;
ULONG OffloadSize = sizeof(OffloadBuffer);
#endif
#ifdef RAW_ENCAP
ULONG gRawEncap = TRUE;
#else
ULONG gRawEncap = FALSE;
#endif
//
// A list of NDIS versions we cycle through, trying to register the
// highest version we can with NDIS. This is so that we can run on
// earlier platforms.
//
// To support a newer version, add an entry at the TOP of the list.
//
struct _RNDISMP_NDIS_VERSION_TABLE
{
UCHAR MajorVersion;
UCHAR MinorVersion;
ULONG CharsSize;
} RndismpNdisVersionTable[] =
{
#ifdef NDIS51_MINIPORT
{5, 1, sizeof(NDIS51_MINIPORT_CHARACTERISTICS)},
#endif
{5, 0, sizeof(NDIS50_MINIPORT_CHARACTERISTICS)}
};
ULONG RndismpNdisVersions = sizeof(RndismpNdisVersionTable) /
sizeof(struct _RNDISMP_NDIS_VERSION_TABLE);
/****************************************************************************/
/* DriverEntry */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Driver entry routine. Never called, Microport driver entry is used */
/* */
/****************************************************************************/
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
// this is never called. Driver entry in Microport is entry.
TRACE1(("DriverEntry\n"));
return NDIS_STATUS_SUCCESS;
} // DriverEntry
/****************************************************************************/
/* RndisMInitializeWrapper */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* RndisMInitializeWrapper is called from the microport to init driver */
/* */
/* Arguments: */
/* */
/* pNdisWrapperHandle - Pass NDIS wrapper handle back to microport */
/* MicroportContext - Microport "Global" context */
/* DriverObject - Driver object */
/* RegistryPath - Registry path */
/* pCharacteristics - Characteristics of RNDIS microport */
/* */
/* Return Value: */
/* */
/* NDIS_STATUS_SUCCESS */
/* NDIS_STATUS_PENDING */
/* */
/****************************************************************************/
NDIS_STATUS
RndisMInitializeWrapper(OUT PNDIS_HANDLE pNdisWrapperHandle,
IN PVOID MicroportContext,
IN PVOID DriverObject,
IN PVOID RegistryPath,
IN PRNDIS_MICROPORT_CHARACTERISTICS pCharacteristics)
{
// Receives the status of the NdisMRegisterMiniport operation.
NDIS_STATUS Status;
// Characteristics table for this driver
NDIS_MINIPORT_CHARACTERISTICS RndismpChar;
// Pointer to the global information for this driver
PDRIVER_BLOCK NewDriver;
// Handle for referring to the wrapper about this driver.
NDIS_HANDLE NdisWrapperHandle;
ULONG i;
TRACE3(("RndisMInitializeWrapper\n"));
// allocate the driver block object, exit if error occurs
Status = MemAlloc(&NewDriver, sizeof(DRIVER_BLOCK));
if(Status != NDIS_STATUS_SUCCESS)
{
TRACE2(("Block Allocate Memory failed (%08X)\n", Status));
return Status;
}
// Initialize the wrapper.
NdisMInitializeWrapper(&NdisWrapperHandle,
(PDRIVER_OBJECT)DriverObject,
RegistryPath,
NULL);
// Save the global information about this driver.
NewDriver->NdisWrapperHandle = NdisWrapperHandle;
NewDriver->AdapterList = (PRNDISMP_ADAPTER) NULL;
NewDriver->DriverObject = DriverObject;
NewDriver->Signature = BLOCK_SIGNATURE;
// get handlers passed in from microport
NewDriver->RmInitializeHandler = pCharacteristics->RmInitializeHandler;
NewDriver->RmInitCompleteNotifyHandler = pCharacteristics->RmInitCompleteNotifyHandler;
NewDriver->RmHaltHandler = pCharacteristics->RmHaltHandler;
NewDriver->RmShutdownHandler = pCharacteristics->RmShutdownHandler;
NewDriver->RmUnloadHandler = pCharacteristics->RmUnloadHandler;
NewDriver->RmSendMessageHandler = pCharacteristics->RmSendMessageHandler;
NewDriver->RmReturnMessageHandler = pCharacteristics->RmReturnMessageHandler;
// save microport "Global" context
NewDriver->MicroportContext = MicroportContext;
// pass the microport the wrapper handle
*pNdisWrapperHandle = (NDIS_HANDLE) NdisWrapperHandle;
// initialize the Miniport characteristics for the call to NdisMRegisterMiniport.
NdisZeroMemory(&RndismpChar, sizeof(RndismpChar));
RndismpChar.HaltHandler = RndismpHalt;
RndismpChar.InitializeHandler = RndismpInitialize;
RndismpChar.QueryInformationHandler = RndismpQueryInformation;
RndismpChar.ReconfigureHandler = RndismpReconfigure;
RndismpChar.ResetHandler = RndismpReset;
RndismpChar.SendPacketsHandler = RndismpMultipleSend;
RndismpChar.SetInformationHandler = RndismpSetInformation;
RndismpChar.ReturnPacketHandler = RndismpReturnPacket;
RndismpChar.CheckForHangHandler = RndismpCheckForHang;
RndismpChar.DisableInterruptHandler = NULL;
RndismpChar.EnableInterruptHandler = NULL;
RndismpChar.HandleInterruptHandler = NULL;
RndismpChar.ISRHandler = NULL;
RndismpChar.SendHandler = NULL;
RndismpChar.TransferDataHandler = NULL;
#if CO_RNDIS
RndismpChar.CoSendPacketsHandler = RndismpCoSendPackets;
RndismpChar.CoCreateVcHandler = RndismpCoCreateVc;
RndismpChar.CoDeleteVcHandler = RndismpCoDeleteVc;
RndismpChar.CoActivateVcHandler = RndismpCoActivateVc;
RndismpChar.CoDeactivateVcHandler = RndismpCoDeactivateVc;
RndismpChar.CoRequestHandler = RndismpCoRequest;
#endif // CO_RNDIS
#ifdef NDIS51_MINIPORT
RndismpChar.PnPEventNotifyHandler = RndismpPnPEventNotify;
RndismpChar.AdapterShutdownHandler = RndismpShutdownHandler;
#endif
for (i = 0; i < RndismpNdisVersions; i++)
{
RndismpChar.MajorNdisVersion = RndismpNdisVersionTable[i].MajorVersion;
RndismpChar.MinorNdisVersion = RndismpNdisVersionTable[i].MinorVersion;
Status = NdisMRegisterMiniport(NdisWrapperHandle,
&RndismpChar,
RndismpNdisVersionTable[i].CharsSize);
if (Status == NDIS_STATUS_SUCCESS)
{
TRACE1(("InitializeWrapper: successfully registered as a %d.%d miniport\n",
RndismpNdisVersionTable[i].MajorVersion,
RndismpNdisVersionTable[i].MinorVersion));
NewDriver->MajorNdisVersion = RndismpNdisVersionTable[i].MajorVersion;
NewDriver->MinorNdisVersion = RndismpNdisVersionTable[i].MinorVersion;
break;
}
}
if(Status != NDIS_STATUS_SUCCESS)
{
Status = STATUS_UNSUCCESSFUL;
// free up memory allocated for block
MemFree(NewDriver, sizeof(DRIVER_BLOCK));
}
else
{
// everything went fine, so add the driver block to the list
AddDriverBlock(&RndismpMiniportBlockListHead, NewDriver);
#ifndef BUILD_WIN9X
// if we are running on a platform < NDIS 5.1, attempt to support
// surprise removal.
HookPnpDispatchRoutine(NewDriver);
#endif
#ifndef BUILD_WIN9X
// Not supported on Win98 Gold:
NdisMRegisterUnloadHandler(NdisWrapperHandle, RndismpUnload);
#endif
}
return (NDIS_STATUS) Status;
} // RndisMInitializeWrapper
/****************************************************************************/
/* RndismpUnload */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Called by NDIS when this driver is unloaded. */
/* */
/* Arguments: */
/* */
/* pDriverObject - Pointer to driver object. */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpUnload(IN PDRIVER_OBJECT pDriverObject)
{
PDRIVER_BLOCK DriverBlock;
// Find our Driver block for this driver object.
DriverBlock = DriverObjectToDriverBlock(&RndismpMiniportBlockListHead, pDriverObject);
TRACE1(("RndismpUnload: DriverObj %x, DriverBlock %x\n", pDriverObject, DriverBlock));
if (DriverBlock)
{
if (DriverBlock->RmUnloadHandler)
{
(DriverBlock->RmUnloadHandler)(DriverBlock->MicroportContext);
}
RemoveDriverBlock(&RndismpMiniportBlockListHead, DriverBlock);
MemFree(DriverBlock, sizeof(*DriverBlock));
}
TRACE1(("RndismpUnload: Done\n"));
}
#ifndef BUILD_WIN9X
/****************************************************************************/
/* DllInitialize */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Called by the system when this driver is loaded. */
/* */
/* Arguments: */
/* */
/* pRegistryPath - Pointer to registry path for this service. */
/* */
/* Return: */
/* */
/* NTSTATUS - success always */
/* */
/****************************************************************************/
NTSTATUS
DllInitialize(IN PUNICODE_STRING pRegistryPath)
{
#if DBG
DbgPrint("RNDISMP: RndismpDebugFlags set to %x, &RndismpDebugFlags is %p\n",
RndismpDebugFlags, &RndismpDebugFlags);
#endif
TRACE1(("DllInitialize\n"));
#ifdef TESTING
{
PNDIS_TASK_OFFLOAD_HEADER pOffloadHdr = (PNDIS_TASK_OFFLOAD_HEADER)pOffloadBuffer;
PNDIS_TASK_OFFLOAD pTask;
PNDIS_TASK_TCP_IP_CHECKSUM pChksum;
pOffloadHdr->Version = NDIS_TASK_OFFLOAD_VERSION;
pOffloadHdr->Size = sizeof(NDIS_TASK_OFFLOAD_HEADER);
pOffloadHdr->EncapsulationFormat.Encapsulation = IEEE_802_3_Encapsulation;
pOffloadHdr->EncapsulationFormat.EncapsulationHeaderSize = 0; // ?
pOffloadHdr->EncapsulationFormat.Flags.FixedHeaderSize = 0;
pOffloadHdr->OffsetFirstTask = sizeof(NDIS_TASK_OFFLOAD_HEADER);
pTask = (PNDIS_TASK_OFFLOAD)(pOffloadHdr + 1);
pTask->Version = NDIS_TASK_OFFLOAD_VERSION;
pTask->Size = sizeof(NDIS_TASK_OFFLOAD);
pTask->Task = TcpIpChecksumNdisTask;
pTask->OffsetNextTask = 0;
pTask->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
pChksum = (PNDIS_TASK_TCP_IP_CHECKSUM)&pTask->TaskBuffer[0];
*(PULONG)pChksum = 0;
pChksum->V4Transmit.TcpChecksum = 1;
pChksum->V4Transmit.UdpChecksum = 1;
}
#endif
return STATUS_SUCCESS;
}
#endif // !BUILD_WIN9X
/****************************************************************************/
/* DllUnload */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Called by the system when this driver is unloaded. */
/* */
/* Arguments: */
/* */
/* None */
/* */
/* Return: */
/* */
/* NTSTATUS - success always */
/* */
/****************************************************************************/
NTSTATUS
DllUnload(VOID)
{
#if DBG
DbgPrint("RNDISMP: DllUnload called!\n");
#endif
return STATUS_SUCCESS;
}
/****************************************************************************/
/* RndismpHalt */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Stop the adapter and release resources */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpHalt(IN NDIS_HANDLE MiniportAdapterContext)
{
#ifdef BUILD_WIN9X
//
// On Win98/SE, we would have intercepted the config mgr handler.
// Put it back the way it was.
//
UnHookNtKernCMHandler((PRNDISMP_ADAPTER)MiniportAdapterContext);
#endif
RndismpInternalHalt(MiniportAdapterContext, TRUE);
}
/****************************************************************************/
/* RndismpInternalHalt */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Internal Halt routine. This is usually called from the MiniportHalt */
/* entry point, but it may also be called when we are notified of surprise */
/* removal by NDIS. Do all work atmost once. */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* bCalledFromHalt - Is this called from the MiniportHalt entry point? */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpInternalHalt(IN NDIS_HANDLE MiniportAdapterContext,
IN BOOLEAN bCalledFromHalt)
{
PRNDISMP_ADAPTER Adapter;
PDRIVER_BLOCK DriverBlock;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
BOOLEAN bWokenUp;
UINT Count, LoopCount;
// get adapter context
Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(Adapter);
TRACE1(("RndismpInternalHalt: Adapter %x, Halting %d, CalledFromHalt %d\n", Adapter, Adapter->Halting, bCalledFromHalt));
FlushPendingMessages(Adapter);
if (!Adapter->Halting)
{
pMsgFrame = BuildRndisMessageCommon(Adapter,
NULL,
REMOTE_NDIS_HALT_MSG,
0,
NULL,
0);
if(pMsgFrame)
{
RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
Adapter->Halting = TRUE;
NdisInitializeEvent(&Adapter->HaltWaitEvent);
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
// send the message to the microport
RNDISMP_SEND_TO_MICROPORT(Adapter, pMsgFrame, FALSE, CompleteSendHalt);
// wait for the -Send- to complete
bWokenUp = NdisWaitEvent(&Adapter->HaltWaitEvent, MINIPORT_HALT_TIMEOUT);
}
else
{
ASSERT(FALSE);
// Consider allocating the Halt message during Init time.
}
//
// Wait for any outstanding receives to finish before halting
// the microport.
//
LoopCount = 0;
while ((Count = NdisPacketPoolUsage(Adapter->ReceivePacketPool)) != 0)
{
TRACE1(("RndismpInternalHalt: Adapter %p, Pkt pool %x has "
"%d outstanding\n",
Adapter, Adapter->ReceivePacketPool, Count));
NdisMSleep(200);
if (LoopCount++ > 30)
{
TRACE1(("RndismpInternalHalt: Adapter %p, cant reclaim packet pool %x\n",
Adapter, Adapter->ReceivePacketPool));
break;
}
}
//
// Wait for send-messages pending at the microport to finish.
// Since we have set Halting to TRUE, no -new- messages will
// be sent down, however there may be running threads that
// have gone past the check for Halting - allow those
// threads to finish now.
//
LoopCount = 0;
while (Adapter->CurPendedMessages)
{
TRACE1(("RndismpInternalHalt: Adapter %p, %d msgs at microport\n",
Adapter, Adapter->CurPendedMessages));
NdisMSleep(200);
if (LoopCount++ > 30)
{
TRACE1(("RndismpInternalHalt: Adapter %p, %d messages not send-completed!\n",
Adapter, Adapter->CurPendedMessages));
break;
}
}
// cancel our keep alive timer
NdisCancelTimer(&Adapter->KeepAliveTimer, &Adapter->TimerCancelled);
// call the microport halt handler
Adapter->RmHaltHandler(Adapter->MicroportAdapterContext);
}
if (bCalledFromHalt)
{
// free lists associated with OID support
FreeOIDLists(Adapter);
// free the adapter spinlock
NdisFreeSpinLock(&Adapter->Lock);
// save driver block pointer
DriverBlock = Adapter->DriverBlock;
// remove adapter from list
RemoveAdapter(Adapter);
// Free the Adapter and associated memory resources
FreeAdapter(Adapter);
}
} // RndismpInternalHalt
/****************************************************************************/
/* RndismpReconfigure */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* NDIS calls this when the device is pulled. Note: only on WinMe! */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
NDIS_STATUS
RndismpReconfigure(OUT PNDIS_STATUS pStatus,
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE ConfigContext)
{
PRNDISMP_ADAPTER pAdapter;
// get adapter context
pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(pAdapter);
TRACE1(("Reconfig: Adapter %x\n", pAdapter));
RndismpInternalHalt(pAdapter, FALSE);
*pStatus = NDIS_STATUS_SUCCESS;
return (NDIS_STATUS_SUCCESS);
}
/****************************************************************************/
/* RndismpReset */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* The RndismpReset request instructs the Miniport to issue a hardware */
/* reset to the network adapter. The driver also resets its software */
/* state. See the description of NdisMReset for a detailed description */
/* of this request. */
/* */
/* Arguments: */
/* */
/* AddressingReset - Does the adapter need the addressing information */
/* reloaded. */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* NDIS_STATUS */
/* */
/****************************************************************************/
NDIS_STATUS
RndismpReset(OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext)
{
PRNDISMP_ADAPTER Adapter;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
NDIS_STATUS Status;
// get adapter context
Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(Adapter);
ASSERT(Adapter->ResetPending == FALSE);
TRACE1(("RndismpReset: Adapter %x\n", Adapter));
Adapter->ResetPending = TRUE;
FlushPendingMessages(Adapter);
pMsgFrame = BuildRndisMessageCommon(Adapter,
NULL,
REMOTE_NDIS_RESET_MSG,
0,
NULL,
0);
if (pMsgFrame)
{
RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
Adapter->NeedReset = FALSE;
//
// Fix water mark so that the reset gets sent down.
//
Adapter->HiWatPendedMessages = RNDISMP_PENDED_SEND_HIWAT + 1;
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
// send the message to the microport
RNDISMP_SEND_TO_MICROPORT(Adapter, pMsgFrame, FALSE, CompleteSendReset);
Status = NDIS_STATUS_PENDING;
RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
Adapter->HiWatPendedMessages--;
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
}
else
{
CompleteMiniportReset(Adapter, NDIS_STATUS_RESOURCES, FALSE);
Status = NDIS_STATUS_PENDING;
}
return Status;
} // RndismpReset
/****************************************************************************/
/* RndismpCheckForHang */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Check and see if device is "hung" */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* BOOLEAN */
/* */
/****************************************************************************/
BOOLEAN
RndismpCheckForHang(IN NDIS_HANDLE MiniportAdapterContext)
{
PRNDISMP_ADAPTER Adapter;
BOOLEAN bReturnHung;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
PLIST_ENTRY pEnt;
Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
TRACE2(("RndismpCheckForHang: Adapter %x\n", Adapter));
CHECK_VALID_ADAPTER(Adapter);
RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
bReturnHung = (Adapter->NeedReset && !Adapter->ResetPending);
#if THROTTLE_MESSAGES
// Try to grow the pending send window, if we can.
//
if (!Adapter->SendInProgress)
{
if (Adapter->CurPendedMessages == 0)
{
Adapter->HiWatPendedMessages = RNDISMP_PENDED_SEND_HIWAT;
Adapter->LoWatPendedMessages = RNDISMP_PENDED_SEND_LOWAT;
}
}
if (!bReturnHung && !Adapter->ResetPending)
{
//
// Check if the microport isn't completing messages.
//
if (!IsListEmpty(&Adapter->PendingAtMicroportList))
{
pEnt = Adapter->PendingAtMicroportList.Flink;
pMsgFrame = CONTAINING_RECORD(pEnt, RNDISMP_MESSAGE_FRAME, PendLink);
if (pMsgFrame->TicksOnQueue > 4)
{
TRACE1(("CheckForHang: Adapter %x, Msg %x has timed out!\n",
Adapter, pMsgFrame));
bReturnHung = TRUE;
}
else
{
pMsgFrame->TicksOnQueue++;
}
}
}
#endif // THROTTLE_MESSAGES
if (RndisForceReset)
{
RndisForceReset = FALSE;
Adapter->NeedReset = TRUE;
Adapter->ResetPending = FALSE;
bReturnHung = TRUE;
}
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
return (bReturnHung);
} // RndismpCheckForHang
/****************************************************************************/
/* RndismpInitialize */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* RndismpInitialize starts an adapter and registers resources with the */
/* wrapper. */
/* */
/* Arguments: */
/* */
/* OpenErrorStatus - Extra status bytes for opening token ring adapters. */
/* SelectedMediumIndex - Index of the media type chosen by the driver. */
/* MediumArray - Array of media types for the driver to chose from. */
/* MediumArraySize - Number of entries in the array. */
/* MiniportAdapterHandle - Handle for passing to the wrapper when */
/* referring to this adapter. */
/* ConfigurationHandle - A handle to pass to NdisOpenConfiguration. */
/* */
/* Return Value: */
/* */
/* NDIS_STATUS_SUCCESS */
/* NDIS_STATUS_PENDING */
/* */
/****************************************************************************/
NDIS_STATUS
RndismpInitialize(OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE ConfigurationHandle)
{
ULONG Index;
NDIS_STATUS Status;
PRNDISMP_ADAPTER Adapter;
NDIS_INTERFACE_TYPE IfType;
PDEVICE_OBJECT Pdo, Fdo, Ndo;
PDRIVER_BLOCK DriverBlock;
PRNDIS_INITIALIZE_COMPLETE pInitCompleteMessage;
PRNDISMP_MESSAGE_FRAME pMsgFrame = NULL;
PRNDISMP_MESSAGE_FRAME pPendingMsgFrame;
PRNDISMP_REQUEST_CONTEXT pReqContext = NULL;
RNDIS_REQUEST_ID RequestId;
ULONG PacketAlignmentFactor;
NDIS_EVENT Event;
BOOLEAN bWokenUp;
BOOLEAN bLinkedAdapter;
BOOLEAN bMicroportInitialized;
TRACE2(("RndismpInitialize\n"));
Adapter = NULL;
Status = NDIS_STATUS_SUCCESS;
bLinkedAdapter = FALSE;
bMicroportInitialized = FALSE;
do
{
// allocate the adapter object, exit if error occurs
Status = MemAlloc(&Adapter, sizeof(RNDISMP_ADAPTER));
if (Status != NDIS_STATUS_SUCCESS)
{
TRACE2(("Adapter Allocate Memory failed (%08X)\n", Status));
break;
}
// allocate space for list of driver-supported OIDs
Status = MemAlloc(&Adapter->DriverOIDList,
RndismpSupportedOidsNum*sizeof(NDIS_OID));
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
RNDISMP_MOVE_MEM(Adapter->DriverOIDList, RndismpSupportedOids, RndismpSupportedOidsNum*sizeof(NDIS_OID));
Adapter->NumDriverOIDs = RndismpSupportedOidsNum;
Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
InitializeListHead(&Adapter->PendingFrameList);
Adapter->Initing = TRUE;
Adapter->MacOptions = RNDIS_DRIVER_MAC_OPTIONS;
#if THROTTLE_MESSAGES
Adapter->HiWatPendedMessages = RNDISMP_PENDED_SEND_HIWAT;
Adapter->LoWatPendedMessages = RNDISMP_PENDED_SEND_LOWAT;
Adapter->CurPendedMessages = 0;
Adapter->SendInProgress = FALSE;
InitializeListHead(&Adapter->WaitingMessageList);
#endif
InitializeListHead(&Adapter->PendingAtMicroportList);
Adapter->IndicatingReceives = FALSE;
InitializeListHead(&Adapter->PendingRcvMessageList);
NdisInitializeTimer(&Adapter->IndicateTimer, IndicateTimeout, (PVOID)Adapter);
Adapter->SendProcessInProgress = FALSE;
InitializeListHead(&Adapter->PendingSendProcessList);
NdisInitializeTimer(&Adapter->SendProcessTimer, SendProcessTimeout, (PVOID)Adapter);
TRACE2(("Adapter structure pointer is (%08X)\n", Adapter));
NdisAllocateSpinLock(&Adapter->Lock);
// get PDO to pass to microport
NdisMGetDeviceProperty(MiniportAdapterHandle,
&Pdo,
&Fdo,
&Ndo,
NULL,
NULL);
#if NEW_NDIS_API_IN_MILLENNIUM
{
NDIS_STRING UnicodeString;
Status = NdisMQueryAdapterInstanceName(&UnicodeString,
Adapter->MiniportAdapterHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
TRACE1(("Init: NDIS returned len %d [%ws]\n",
UnicodeString.Length, UnicodeString.Buffer));
NdisFreeString(UnicodeString);
}
}
#endif
Adapter->pDeviceObject = Fdo;
Adapter->pPhysDeviceObject = Pdo;
Status = GetDeviceFriendlyName(Pdo,
&Adapter->FriendlyNameAnsi,
&Adapter->FriendlyNameUnicode);
if (Status == NDIS_STATUS_SUCCESS)
{
TRACE1(("Init: Pdo %x, Ndo %x: Adapter %x: [%s]\n",
Pdo, Ndo, Adapter, Adapter->FriendlyNameAnsi.Buffer));
}
else
{
Status = NDIS_STATUS_SUCCESS;
}
// Determine the platform we are running on. Ideally we would
// like to do this from DriverEntry, but the NDIS API isn't
// available until MiniportInit time.
{
NDIS_STATUS NdisStatus;
PNDIS_CONFIGURATION_PARAMETER pParameter;
NDIS_STRING VersionKey = NDIS_STRING_CONST("Environment");
NdisReadConfiguration(
&NdisStatus,
&pParameter,
ConfigurationHandle,
&VersionKey,
NdisParameterInteger);
if ((NdisStatus == NDIS_STATUS_SUCCESS) &&
((pParameter->ParameterType == NdisParameterInteger) ||
(pParameter->ParameterType == NdisParameterHexInteger)))
{
Adapter->bRunningOnWin9x =
(pParameter->ParameterData.IntegerData == NdisEnvironmentWindows);
TRACE1(("Init: Adapter %p, running on %s\n",
Adapter,
((Adapter->bRunningOnWin9x)? "Win9X": "NT")));
}
else
{
TRACE1(("Init: ReadConfig: NdisStatus %x\n", NdisStatus));
#if DBG
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
TRACE1(("Init: ReadConfig: parametertype %x\n",
pParameter->ParameterType));
}
#endif // DBG
Adapter->bRunningOnWin9x = TRUE;
}
}
// find the driver block associated with this adapter
DriverBlock = DeviceObjectToDriverBlock(&RndismpMiniportBlockListHead, Fdo);
if (DriverBlock == NULL)
{
TRACE1(("Init: Can't find driver block for FDO %x!\n", Fdo));
Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
break;
}
// save the associated driver block in the adapter
Adapter->DriverBlock = DriverBlock;
Adapter->Signature = ADAPTER_SIGNATURE;
// get handlers passed in from microport
Adapter->RmInitializeHandler = DriverBlock->RmInitializeHandler;
Adapter->RmInitCompleteNotifyHandler = DriverBlock->RmInitCompleteNotifyHandler;
Adapter->RmHaltHandler = DriverBlock->RmHaltHandler;
Adapter->RmShutdownHandler = DriverBlock->RmShutdownHandler;
Adapter->RmSendMessageHandler = DriverBlock->RmSendMessageHandler;
Adapter->RmReturnMessageHandler = DriverBlock->RmReturnMessageHandler;
// call microport initialize handler
//
// Microport returns context
// Pass in Miniport context
// Pass in NDIS adapter handle
// Pass in NDIS configuration handle
// Pass in PDO for this adapter
Status = Adapter->RmInitializeHandler(&Adapter->MicroportAdapterContext,
&Adapter->MaxReceiveSize,
(NDIS_HANDLE) Adapter,
(NDIS_HANDLE) MiniportAdapterHandle,
(NDIS_HANDLE) ConfigurationHandle,
Ndo);
if (Status != NDIS_STATUS_SUCCESS)
{
TRACE2(("Microport initialize handler failed (%08X)\n", Status));
break;
}
bMicroportInitialized = TRUE;
// everything looks good, so finish up
Status = AllocateTransportResources(Adapter);
if (Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
// allocate space to receive a copy of the Initialize complete message in
Status = MemAlloc(&Adapter->pInitCompleteMessage, sizeof(RNDIS_INITIALIZE_COMPLETE));
if (Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
// now we send down a RNDIS initialize message to the device
pMsgFrame = BuildRndisMessageCommon(Adapter,
NULL,
REMOTE_NDIS_INITIALIZE_MSG,
0,
(PVOID) NULL,
0);
if (pMsgFrame == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
RequestId = pMsgFrame->RequestId;
pReqContext = AllocateRequestContext(Adapter);
if (pReqContext == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
pReqContext->pNdisRequest = NULL;
NdisInitializeEvent(&Event);
pReqContext->pEvent = &Event;
pMsgFrame->pVc = NULL;
pMsgFrame->pReqContext = pReqContext;
RNDISMP_ASSERT_AT_PASSIVE();
// send the message to the microport.
RNDISMP_SEND_TO_MICROPORT(Adapter, pMsgFrame, TRUE, NULL);
RNDISMP_ASSERT_AT_PASSIVE();
// wait for message to complete
bWokenUp = NdisWaitEvent(&Event, MINIPORT_INIT_TIMEOUT);
// remove the message from the pending queue - it may or may not be there.
RNDISMP_LOOKUP_PENDING_MESSAGE(pPendingMsgFrame, Adapter, RequestId);
DereferenceMsgFrame(pMsgFrame);
if (!bWokenUp)
{
// Failed to receive an Init complete within a reasonable time.
TRACE1(("Init: Adapter %x, failed to receive Init complete\n", Adapter));
Status = NDIS_STATUS_DEVICE_FAILED;
break;
}
//
// the init complete message from the device is now
// copied over to our local structure
//
pInitCompleteMessage = Adapter->pInitCompleteMessage;
if (pInitCompleteMessage->Status != NDIS_STATUS_SUCCESS)
{
Status = pInitCompleteMessage->Status;
break;
}
// make sure this is a supported device.
if (!(pInitCompleteMessage->DeviceFlags & (RNDIS_DF_CONNECTIONLESS | RNDIS_DF_RAW_DATA)) ||
(pInitCompleteMessage->Medium != RNdisMedium802_3))
{
TRACE1(("Init: Complete: unknown DeviceFlags %x or Medium %d\n",
pInitCompleteMessage->DeviceFlags,
pInitCompleteMessage->Medium));
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
if ((pInitCompleteMessage->DeviceFlags & RNDIS_DF_RAW_DATA)
|| (gRawEncap))
{
Adapter->MultipleSendFunc = DoMultipleSendRaw;
} else
{
Adapter->MultipleSendFunc = DoMultipleSend;
}
Adapter->Medium = RNDIS_TO_NDIS_MEDIUM(pInitCompleteMessage->Medium);
// get device parameters.
Adapter->MaxPacketsPerMessage = pInitCompleteMessage->MaxPacketsPerMessage;
if (Adapter->MaxPacketsPerMessage == 0)
{
Adapter->MaxPacketsPerMessage = 1;
}
#if HACK
if (Adapter->MaxPacketsPerMessage > 1)
{
Adapter->MaxPacketsPerMessage = 2;
}
#endif // HACK
Adapter->bMultiPacketSupported = (Adapter->MaxPacketsPerMessage > 1);
Adapter->MaxTransferSize = pInitCompleteMessage->MaxTransferSize;
PacketAlignmentFactor = pInitCompleteMessage->PacketAlignmentFactor;
if (PacketAlignmentFactor > 7)
{
PacketAlignmentFactor = 7;
}
Adapter->AlignmentIncr = (1 << PacketAlignmentFactor);
Adapter->AlignmentMask = ~((1 << PacketAlignmentFactor) - 1);
#if DBG
DbgPrint("RNDISMP: InitComp: Adapter %x, Version %d.%d, MaxPkt %d, AlignIncr %d, AlignMask %x, MaxXferSize %d\n",
Adapter,
pInitCompleteMessage->MajorVersion,
pInitCompleteMessage->MinorVersion,
Adapter->MaxPacketsPerMessage,
Adapter->AlignmentIncr,
Adapter->AlignmentMask,
Adapter->MaxTransferSize);
#endif // DBG
// Get the medium type.
for (Index = 0; Index < MediumArraySize; Index++)
{
if (MediumArray[Index] == Adapter->Medium)
{
break;
}
}
if (Index == MediumArraySize)
{
TRACE1(("InitComp: Adapter %x, device returned unsupported medium %d\n",
Adapter, pInitCompleteMessage->Medium));
Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
break;
}
*SelectedMediumIndex = Index;
Adapter->DeviceFlags = pInitCompleteMessage->DeviceFlags;
// call NdisMSetAttributesEx in order to let NDIS know
// what kind of driver and features we support
// interface type
IfType = NdisInterfaceInternal;
if (Adapter->bRunningOnWin9x)
{
//
// NOTE! The 0x80000000 bit is set to let NDIS know
// (Millennium only!) that our reconfig handler should
// be called when the device is surprise-removed.
//
NdisMSetAttributesEx(Adapter->MiniportAdapterHandle,
(NDIS_HANDLE) Adapter,
4,
(ULONG) NDIS_ATTRIBUTE_DESERIALIZE | 0x80000000,
IfType);
}
else
{
ULONG AttrFlags;
AttrFlags = NDIS_ATTRIBUTE_DESERIALIZE |
NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK;
if (Adapter->DeviceFlags & RNDIS_DF_CONNECTIONLESS)
{
AttrFlags |= NDIS_ATTRIBUTE_NOT_CO_NDIS;
}
NdisMSetAttributesEx(Adapter->MiniportAdapterHandle,
(NDIS_HANDLE) Adapter,
4,
AttrFlags,
IfType);
}
// Tell the microport that the device completed Init
// successfully:
if (Adapter->RmInitCompleteNotifyHandler)
{
Status = Adapter->RmInitCompleteNotifyHandler(
Adapter->MicroportAdapterContext,
Adapter->DeviceFlags,
&Adapter->MaxTransferSize);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
}
// get the list of supported OIDs from the device
pMsgFrame = BuildRndisMessageCommon(Adapter,
NULL,
REMOTE_NDIS_QUERY_MSG,
OID_GEN_SUPPORTED_LIST,
(PVOID) NULL,
0);
if (pMsgFrame == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
// link us on to the list of adapters for this driver block
AddAdapter(Adapter);
bLinkedAdapter = TRUE;
pReqContext->pNdisRequest = NULL;
pReqContext->Oid = OID_GEN_SUPPORTED_LIST;
pReqContext->CompletionStatus = NDIS_STATUS_SUCCESS;
NdisInitializeEvent(&Event);
pReqContext->pEvent = &Event;
pMsgFrame->pVc = NULL;
pMsgFrame->pReqContext = pReqContext;
// send the message to the microport.
RNDISMP_SEND_TO_MICROPORT(Adapter, pMsgFrame, TRUE, NULL);
RNDISMP_ASSERT_AT_PASSIVE();
bWokenUp = NdisWaitEvent(&Event, MINIPORT_INIT_TIMEOUT);
// remove the message from the pending queue - it may or may not be there.
RNDISMP_LOOKUP_PENDING_MESSAGE(pPendingMsgFrame, Adapter, RequestId);
DereferenceMsgFrame(pMsgFrame);
if (!bWokenUp || (Adapter->DriverOIDList == NULL))
{
// Failed to receive a response within a reasonable time,
// or the device failed this query.
//
TRACE1(("Init: Adapter %x, failed to receive response to OID_GEN_SUPPORTED_LIST\n", Adapter));
Status = NDIS_STATUS_DEVICE_FAILED;
ASSERT(FALSE);
break;
}
// Successfully queried the supported OID list.
#ifdef BUILD_WIN9X
//
// Attempt to support surprise removal of this device (Win98/SE)
// by intercepting config mgr messages forwarded by NDIS.
//
HookNtKernCMHandler(Adapter);
#endif
// send any registry parameters down to the device, if it supports them.
if (GetOIDSupport(Adapter, OID_GEN_RNDIS_CONFIG_PARAMETER) == DEVICE_SUPPORTED_OID)
{
Status = ReadAndSetRegistryParameters(Adapter, ConfigurationHandle);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
}
// register a shutdown handler
NdisMRegisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle,
(PVOID) Adapter,
RndismpShutdownHandler);
Adapter->TimerCancelled = FALSE;
Adapter->Initing = FALSE;
// initialize "KeepAlive" timer
NdisInitializeTimer(&Adapter->KeepAliveTimer,
KeepAliveTimerHandler,
(PVOID) Adapter);
NdisSetTimer(&Adapter->KeepAliveTimer, KEEP_ALIVE_TIMER / 2);
Status = NDIS_STATUS_SUCCESS;
}
while (FALSE);
if (Adapter)
{
if (Adapter->pInitCompleteMessage)
{
MemFree(Adapter->pInitCompleteMessage, sizeof(*Adapter->pInitCompleteMessage));
}
}
if (Status != NDIS_STATUS_SUCCESS)
{
TRACE1(("Failed to init adapter %x, status %x\n", Adapter, Status));
if (bMicroportInitialized)
{
ASSERT(Adapter);
Adapter->RmHaltHandler(Adapter->MicroportAdapterContext);
}
if (Adapter)
{
if (bLinkedAdapter)
{
RemoveAdapter(Adapter);
}
FreeAdapter(Adapter);
}
}
return Status;
} // RndismpInitialize
/****************************************************************************/
/* RndisMSendComplete */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Called by microport to indicate a message miniport sent is completed */
/* by microport */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* RndisMessageHandle - context used by miniport */
/* SendStatus - indicate status of send message */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndisMSendComplete(IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE RndisMessageHandle,
IN NDIS_STATUS SendStatus)
{
PRNDISMP_ADAPTER Adapter;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
// get adapter context
Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(Adapter);
pMsgFrame = MESSAGE_FRAME_FROM_HANDLE(RndisMessageHandle);
CHECK_VALID_FRAME(pMsgFrame);
ASSERT(pMsgFrame->pAdapter == Adapter);
TRACE2(("RndisMSendComplete: Adapter %x, MsgFrame %x, MDL %x\n", Adapter, pMsgFrame, pMsgFrame->pMessageMdl));
if ((SendStatus != NDIS_STATUS_SUCCESS) &&
(SendStatus != NDIS_STATUS_RESOURCES))
{
RNDISMP_INCR_STAT(Adapter, MicroportSendError);
TRACE0(("RndisMSendComplete: Adapter %x, MsgFrame %x, MDL %x, ERROR %x\n",
Adapter,
pMsgFrame,
pMsgFrame->pMessageMdl,
SendStatus));
}
#if THROTTLE_MESSAGES
RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
Adapter->CurPendedMessages--;
RemoveEntryList(&pMsgFrame->PendLink);
if (SendStatus == NDIS_STATUS_RESOURCES)
{
RNDISMP_INCR_STAT(Adapter, SendMsgLowRes);
}
if ((SendStatus != NDIS_STATUS_RESOURCES) ||
(Adapter->CurPendedMessages < 2))
{
if (Adapter->CurPendedMessages == Adapter->LoWatPendedMessages)
{
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
QueueMessageToMicroport(Adapter, NULL, FALSE);
}
else
{
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
}
if (SendStatus == NDIS_STATUS_RESOURCES)
{
TRACE1(("RndisMSendComplete: Adapter %x, got resources\n", Adapter));
SendStatus = NDIS_STATUS_SUCCESS;
}
if (pMsgFrame->pCallback)
{
(*pMsgFrame->pCallback)(pMsgFrame, SendStatus);
}
else
{
//
// Do nothing. The sender will take care of freeing
// this.
//
}
}
else
{
//
// The microport is out of send resources. Requeue this
// and adjust water marks.
//
InsertHeadList(&Adapter->WaitingMessageList, &pMsgFrame->PendLink);
Adapter->HiWatPendedMessages = Adapter->CurPendedMessages;
Adapter->LoWatPendedMessages = Adapter->CurPendedMessages / 2;
TRACE1(("RndisMSendComplete: Adapter %x, new Hiwat %d, Lowat %d\n",
Adapter, Adapter->HiWatPendedMessages, Adapter->LoWatPendedMessages));
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter);
}
#else
if (pMsgFrame->pCallback)
{
(*pMsgFrame->pCallback)(pMsgFrame, SendStatus);
}
else
{
//
// Do nothing. The sender will take care of freeing
// this.
//
}
#endif // THROTTLE_MESSAGES
} // RndisMSendComplete
/****************************************************************************/
/* InitCompletionMessage */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Completion message from microport in response to init message miniport */
/* sent. The init message was sent from the adapter init routine which is */
/* waiting for this event to unblock */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to our adapter structure */
/* pMessage - Pointer to RNDIS message */
/* pMdl - Pointer to MDL received from microport */
/* TotalLength - length of complete message */
/* MicroportMessageContext - context for message from micorport */
/* ReceiveStatus - used by microport to indicate it is low on resource */
/* bMessageCopied - is this a copy of the original message? */
/* */
/* Return: */
/* */
/* BOOLEAN - should the message be returned to the microport? */
/* */
/****************************************************************************/
BOOLEAN
InitCompletionMessage(IN PRNDISMP_ADAPTER pAdapter,
IN PRNDIS_MESSAGE pMessage,
IN PMDL pMdl,
IN ULONG TotalLength,
IN NDIS_HANDLE MicroportMessageContext,
IN NDIS_STATUS ReceiveStatus,
IN BOOLEAN bMessageCopied)
{
PRNDIS_INITIALIZE_COMPLETE pInitCompleteMessage;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
PRNDISMP_REQUEST_CONTEXT pReqContext;
BOOLEAN bDiscardMsg = TRUE;
TRACE2(("InitCompletionMessage\n"));
do
{
if (pMessage->MessageLength < RNDISMP_MIN_MESSAGE_LENGTH(InitializeComplete))
{
TRACE1(("InitCompletion: Message length (%d) too short, expect at least (%d)\n",
pMessage->MessageLength,
RNDISMP_MIN_MESSAGE_LENGTH(InitializeComplete)));
break;
}
if (pAdapter->pInitCompleteMessage == NULL)
{
TRACE1(("InitCompletion: multiple InitComplete from device, ignored\n"));
break;
}
pInitCompleteMessage = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
// get request frame from request ID in message
RNDISMP_LOOKUP_PENDING_MESSAGE(pMsgFrame, pAdapter, pInitCompleteMessage->RequestId);
if (pMsgFrame == NULL)
{
// invalid request ID or aborted request.
TRACE1(("Invalid request ID %d in Init Complete\n",
pInitCompleteMessage->RequestId));
break;
}
pReqContext = pMsgFrame->pReqContext;
RNDISMP_MOVE_MEM(pAdapter->pInitCompleteMessage,
pInitCompleteMessage,
sizeof(*pInitCompleteMessage));
// signal the adapter init routine we are done
NdisSetEvent(pReqContext->pEvent);
}
while (FALSE);
return (bDiscardMsg);
} // InitCompletionMessage
/****************************************************************************/
/* HaltMessage */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Process a HALT message from the device. */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to our Adapter structure */
/* pMessage - pointer to RNDIS message */
/* pMdl - Pointer to MDL from microport */
/* TotalLength - length of complete message */
/* MicroportMessageContext - context for message from microport */
/* ReceiveStatus - used by microport to indicate it is low on resource */
/* bMessageCopied - is this a copy of the original message? */
/* */
/* Return: */
/* */
/* BOOLEAN - should the message be returned to the microport? */
/* */
/****************************************************************************/
BOOLEAN
HaltMessage(IN PRNDISMP_ADAPTER pAdapter,
IN PRNDIS_MESSAGE pMessage,
IN PMDL pMdl,
IN ULONG TotalLength,
IN NDIS_HANDLE MicroportMessageContext,
IN NDIS_STATUS ReceiveStatus,
IN BOOLEAN bMessageCopied)
{
TRACE1(("HaltMessage: Adapter %x\n", pAdapter));
#ifndef BUILD_WIN9X
// Not supported on Win98 Gold:
NdisMRemoveMiniport(pAdapter->MiniportAdapterHandle);
#endif
return TRUE;
} // HaltMessage
/****************************************************************************/
/* ResetCompletionMessage */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Completion message from microport in response to reset message miniport */
/* sent. Indicate this completion message to the upper layers since */
/* the miniport reset routine indicated STATUS_PENDING to the upper layers */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to our Adapter structure */
/* pMessage - pointer to RNDIS message */
/* pMdl - Pointer to MDL from microport */
/* TotalLength - length of complete message */
/* MicroportMessageContext - context for message from microport */
/* ReceiveStatus - used by microport to indicate it is low on resource */
/* bMessageCopied - is this a copy of the original message? */
/* */
/* Return: */
/* */
/* BOOLEAN - should the message be returned to the microport? */
/* */
/****************************************************************************/
BOOLEAN
ResetCompletionMessage(IN PRNDISMP_ADAPTER pAdapter,
IN PRNDIS_MESSAGE pMessage,
IN PMDL pMdl,
IN ULONG TotalLength,
IN NDIS_HANDLE MicroportMessageContext,
IN NDIS_STATUS ReceiveStatus,
IN BOOLEAN bMessageCopied)
{
PRNDIS_RESET_COMPLETE pResetMessage;
BOOLEAN AddressingReset;
NDIS_STATUS Status;
TRACE2(("ResetCompletionMessage\n"));
pResetMessage = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
// save these parameters to call to upper layers
Status = pResetMessage->Status;
AddressingReset = (BOOLEAN)pResetMessage->AddressingReset;
CompleteMiniportReset(pAdapter, Status, AddressingReset);
return TRUE;
} // ResetCompletionMessage
/****************************************************************************/
/* KeepAliveCompletionMessage */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Completion message for a keep alive request send down by miniport */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to our Adapter structure */
/* pMessage - pointer to RNDIS message */
/* pMdl - Pointer to MDL from microport */
/* TotalLength - length of complete message */
/* MicroportMessageContext - context for message from microport */
/* ReceiveStatus - used by microport to indicate it is low on resource */
/* bMessageCopied - is this a copy of the original message? */
/* */
/* Return: */
/* */
/* BOOLEAN - should the message be returned to the microport? */
/* */
/****************************************************************************/
BOOLEAN
KeepAliveCompletionMessage(IN PRNDISMP_ADAPTER pAdapter,
IN PRNDIS_MESSAGE pMessage,
IN PMDL pMdl,
IN ULONG TotalLength,
IN NDIS_HANDLE MicroportMessageContext,
IN NDIS_STATUS ReceiveStatus,
IN BOOLEAN bMessageCopied)
{
PRNDIS_KEEPALIVE_COMPLETE pKeepaliveComplete;
NDIS_STATUS Status;
TRACE2(("KeepAliveCompletionMessage\n"));
pKeepaliveComplete = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
// save off status
Status = pKeepaliveComplete->Status;
// grab the spinlock
NdisAcquireSpinLock(&pAdapter->Lock);
if (pKeepaliveComplete->RequestId != pAdapter->KeepAliveMessagePendingId)
{
TRACE0(("KeepAliveCompletion: Adapter %x, expected ID %x, got %x\n",
pAdapter,
pAdapter->KeepAliveMessagePendingId,
pKeepaliveComplete->RequestId));
//
// TBD - should we set NeedReset?
}
pAdapter->KeepAliveMessagePending = FALSE;
// if there are problems, tell the check for hang handler we need a reset
if (Status != NDIS_STATUS_SUCCESS)
{
TRACE0(("KeepAliveCompletion: Adapter %x, err status %x from device\n",
pAdapter, Status));
// indicate later from check for hang handler
pAdapter->NeedReset = TRUE;
}
// release spinlock
NdisReleaseSpinLock(&pAdapter->Lock);
return TRUE;
} // KeepAliveCompletionMessage
/****************************************************************************/
/* KeepAliveMessage */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Process a keepalive message sent by the device. Send back a completion. */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to our Adapter structure */
/* pMessage - pointer to RNDIS message */
/* pMdl - Pointer to MDL from microport */
/* TotalLength - length of complete message */
/* MicroportMessageContext - context for message from microport */
/* ReceiveStatus - used by microport to indicate it is low on resource */
/* bMessageCopied - is this a copy of the original message? */
/* */
/* Return: */
/* */
/* BOOLEAN - should the message be returned to the microport? */
/* */
/****************************************************************************/
BOOLEAN
KeepAliveMessage(IN PRNDISMP_ADAPTER pAdapter,
IN PRNDIS_MESSAGE pMessage,
IN PMDL pMdl,
IN ULONG TotalLength,
IN NDIS_HANDLE MicroportMessageContext,
IN NDIS_STATUS ReceiveStatus,
IN BOOLEAN bMessageCopied)
{
PRNDIS_KEEPALIVE_REQUEST pKeepalive;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
TRACE2(("KeepAliveMessage\n"));
pKeepalive = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
//
// Send a response if we can.
//
pMsgFrame = BuildRndisMessageCommon(pAdapter,
NULL,
REMOTE_NDIS_KEEPALIVE_CMPLT,
0,
&pKeepalive->RequestId,
sizeof(pKeepalive->RequestId));
if (pMsgFrame != NULL)
{
// send the message to the microport.
RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, FALSE, NULL);
}
else
{
TRACE1(("KeepAlive: Adapter %x: failed to alloc response!\n", pAdapter));
}
return TRUE;
} // KeepAliveMessage
/****************************************************************************/
/* RndismpShutdownHandler */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Removes an adapter instance that was previously initialized. Since the */
/* system is shutting down there is no need to release resources, just */
/* shutdown receive. */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpShutdownHandler(IN NDIS_HANDLE MiniportAdapterContext)
{
PRNDISMP_ADAPTER Adapter;
// get adapter context
Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
TRACE1(("RndismpShutdownHandler\n"));
} // RndismpShutdownHandler
//
// Interrupt routines, stubbed up for now, we don't need them
//
/****************************************************************************/
/* RndismpDisableInterrupt */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpDisableInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
{
// NOP
} // RndismpDisableInterrupt
/****************************************************************************/
/* RndismpEnableInterrupt */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpEnableInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
{
// NOP
} // RndismpEnableInterrupt
/****************************************************************************/
/* RndismpHandleInterrupt */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* */
/* Arguments: */
/* */
/* MiniportAdapterContext - a context version of our Adapter pointer */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpHandleInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
{
// NOP
} // RndismpHandleInterrupt
/****************************************************************************/
/* RndismpIsr */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* This is the interrupt handler which is registered with the operating */
/* system. If several are pending (i.e. transmit complete and receive), */
/* handle them all. Block new interrupts until all pending interrupts */
/* are handled. */
/* */
/* Arguments: */
/* */
/* InterruptRecognized - Boolean value which returns TRUE if the */
/* ISR recognizes the interrupt as coming from this adapter. */
/* */
/* QueueDpc - TRUE if a DPC should be queued. */
/* */
/* Context - pointer to the adapter object */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
RndismpIsr(OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueDpc,
IN PVOID Context)
{
ASSERT(FALSE); // don't expect to be called here.
} // RndismpIsr
/****************************************************************************/
/* CompleteSendHalt */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Utility function to handle completion of sending of a HALT message. */
/* We simply wake up the thread waiting for this. */
/* */
/* Arguments: */
/* */
/* pMsgFrame - Frame structure describing the HALT message */
/* SendStatus - outcome of sending this message. */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
CompleteSendHalt(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
IN NDIS_STATUS SendStatus)
{
PRNDISMP_ADAPTER pAdapter;
pAdapter = pMsgFrame->pAdapter;
TRACE1(("CompleteSendHalt: Adapter %x, SendStatus %x\n", pAdapter, SendStatus));
ASSERT(pAdapter->Halting);
DereferenceMsgFrame(pMsgFrame);
NdisSetEvent(&pAdapter->HaltWaitEvent);
} // CompleteSendHalt
/****************************************************************************/
/* CompleteSendReset */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Callback routine to handle send-completion of a reset message by the */
/* microport. */
/* */
/* Arguments: */
/* */
/* pMsgFrame - Pointer to message frame for the Reset. */
/* SendStatus - Status of send */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
CompleteSendReset(IN PRNDISMP_MESSAGE_FRAME pMsgFrame,
IN NDIS_STATUS SendStatus)
{
PRNDISMP_ADAPTER pAdapter;
pAdapter = pMsgFrame->pAdapter;
TRACE1(("CompleteSendReset: Adapter %x, SendStatus %x\n",
pAdapter, SendStatus));
DereferenceMsgFrame(pMsgFrame);
if (SendStatus != NDIS_STATUS_SUCCESS)
{
CompleteMiniportReset(pAdapter, SendStatus, FALSE);
}
}
/****************************************************************************/
/* CompleteMiniportReset */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Utility function to complete a pending NDIS Reset. We complete any */
/* pending requests/sets before indicating reset complete to NDIS. */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to our adapter structure */
/* ResetStatus - to be used for completing reset */
/* AddressingReset - Do we need filters to be resent to us? */
/* */
/* Return: */
/* */
/* VOID */
/* */
/****************************************************************************/
VOID
CompleteMiniportReset(IN PRNDISMP_ADAPTER pAdapter,
IN NDIS_STATUS ResetStatus,
IN BOOLEAN AddressingReset)
{
LIST_ENTRY PendingRequests;
PLIST_ENTRY pEntry, pNext;
PRNDISMP_MESSAGE_FRAME pMsgFrame;
do
{
if (!pAdapter->ResetPending)
{
break;
}
pAdapter->ResetPending = FALSE;
//
// Take out all pending requests/sets queued on the adapter.
//
InitializeListHead(&PendingRequests);
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
for (pEntry = pAdapter->PendingFrameList.Flink;
pEntry != &pAdapter->PendingFrameList;
pEntry = pNext)
{
pNext = pEntry->Flink;
pMsgFrame = CONTAINING_RECORD(pEntry, RNDISMP_MESSAGE_FRAME, Link);
if (pMsgFrame->NdisMessageType == REMOTE_NDIS_QUERY_MSG ||
pMsgFrame->NdisMessageType == REMOTE_NDIS_SET_MSG)
{
RemoveEntryList(pEntry);
InsertTailList(&PendingRequests, pEntry);
TRACE0(("RNDISMP: ResetComplete: taking out MsgFrame %x, msg type %x\n",
pMsgFrame, pMsgFrame->NdisMessageType));
}
}
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
//
// Complete all these requests.
//
for (pEntry = PendingRequests.Flink;
pEntry != &PendingRequests;
pEntry = pNext)
{
pNext = pEntry->Flink;
pMsgFrame = CONTAINING_RECORD(pEntry, RNDISMP_MESSAGE_FRAME, Link);
TRACE0(("RNDISMP: ResetComplete: completing MsgFrame %x, msg type %x\n",
pMsgFrame, pMsgFrame->NdisMessageType));
ASSERT(pMsgFrame->pReqContext != NULL);
if (pMsgFrame->pReqContext->pNdisRequest != NULL)
{
//
// This request came down thru our MiniportCoRequest handler.
//
NdisMCoRequestComplete(NDIS_STATUS_REQUEST_ABORTED,
pAdapter->MiniportAdapterHandle,
pMsgFrame->pReqContext->pNdisRequest);
}
else
{
//
// This request came thru our connectionless query/set handler.
//
if (pMsgFrame->NdisMessageType == REMOTE_NDIS_QUERY_MSG)
{
NdisMQueryInformationComplete(pAdapter->MiniportAdapterHandle,
NDIS_STATUS_REQUEST_ABORTED);
}
else
{
ASSERT(pMsgFrame->NdisMessageType == REMOTE_NDIS_SET_MSG);
NdisMSetInformationComplete(pAdapter->MiniportAdapterHandle,
NDIS_STATUS_REQUEST_ABORTED);
}
}
FreeRequestContext(pAdapter, pMsgFrame->pReqContext);
pMsgFrame->pReqContext = (PRNDISMP_REQUEST_CONTEXT)UlongToPtr(0xabababab);
DereferenceMsgFrame(pMsgFrame);
}
TRACE0(("Completing reset on Adapter %x, Status %x, AddressingReset %d\n",
pAdapter, ResetStatus, AddressingReset));
RNDISMP_INCR_STAT(pAdapter, Resets);
//
// Complete the reset now.
//
NdisMResetComplete(pAdapter->MiniportAdapterHandle,
ResetStatus,
AddressingReset);
}
while (FALSE);
}
/****************************************************************************/
/* ReadAndSetRegistryParameters */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* This is called when initializing a device, to read and send any */
/* registry parameters applicable to this device. */
/* */
/* We go through the entire list of configurable parameters by walking */
/* subkeys under the "ndi\Params" key. Each subkey represents one */
/* parameter. Using information about this parameter (specifically, its */
/* name and type), we query its value, and send a SetRequest to the */
/* device. */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to adapter structure for the device */
/* ConfigurationContext - NDIS handle to access registry for this device */
/* */
/* Return: */
/* */
/* NDIS_STATUS */
/* */
/****************************************************************************/
NDIS_STATUS
ReadAndSetRegistryParameters(IN PRNDISMP_ADAPTER pAdapter,
IN NDIS_HANDLE ConfigurationContext)
{
NDIS_STATUS Status;
NDIS_HANDLE ConfigHandle;
NDIS_STRING NdiKeyName = NDIS_STRING_CONST("Ndi");
NDIS_HANDLE NdiKeyHandle = NULL;
Status = NDIS_STATUS_SUCCESS;
ConfigHandle = NULL;
do
{
NdisOpenConfiguration(&Status,
&ConfigHandle,
ConfigurationContext);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
NdisOpenConfigurationKeyByName(
&Status,
ConfigHandle,
&NdiKeyName,
&NdiKeyHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
NDIS_STRING ParamsKeyName = NDIS_STRING_CONST("Params");
NDIS_HANDLE ParamsKeyHandle = NULL;
NdisOpenConfigurationKeyByName(
&Status,
NdiKeyHandle,
&ParamsKeyName,
&ParamsKeyHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
ULONG i;
BOOLEAN bDone = FALSE;
//
// Iterate through all subkeys under ndi\Params:
//
for (i = 0; !bDone; i++)
{
NDIS_STRING ParamSubKeyName;
NDIS_HANDLE ParamSubKeyHandle;
NDIS_STRING ParamTypeName = NDIS_STRING_CONST("type");
PNDIS_CONFIGURATION_PARAMETER pConfigParameter;
ParamSubKeyName.Length =
ParamSubKeyName.MaximumLength = 0;
ParamSubKeyName.Buffer = NULL;
NdisOpenConfigurationKeyByIndex(
&Status,
ParamsKeyHandle,
i,
&ParamSubKeyName,
&ParamSubKeyHandle);
if (Status != NDIS_STATUS_SUCCESS)
{
//
// Done with parameters. Cook return value.
//
Status = NDIS_STATUS_SUCCESS;
break;
}
//
// Got the handle to a subkey under ndi\Params,
// now read the type information for this parameter.
//
#ifndef BUILD_WIN9X
TRACE3(("ReadAndSetRegParams: subkey %d under ndi\\params: %ws\n",
i, ParamSubKeyName.Buffer));
#else
//
// Handle Win98Gold behavior.
//
if (ParamSubKeyName.Buffer == NULL)
{
PNDIS_STRING pNdisString;
pNdisString = *(PNDIS_STRING *)&ParamSubKeyName;
ParamSubKeyName = *pNdisString;
}
TRACE2(("ReadAndSetRegParams: subkey %d under ndi\\params: %ws\n",
i, ParamSubKeyName.Buffer));
#endif
//
// We have a parameter name now, in ParamSubKeyName.
// Get its type information.
//
NdisReadConfiguration(
&Status,
&pConfigParameter,
ParamSubKeyHandle,
&ParamTypeName,
NdisParameterString);
if (Status == NDIS_STATUS_SUCCESS)
{
TRACE2(("ReadAndSetRegParams: Adapter %p, type is %ws\n",
pAdapter,
pConfigParameter->ParameterData.StringData.Buffer));
//
// Send off a Set Request for this
// parameter to the device.
//
Status = SendConfiguredParameter(
pAdapter,
ConfigHandle,
&ParamSubKeyName,
&pConfigParameter->ParameterData.StringData);
if (Status != NDIS_STATUS_SUCCESS)
{
TRACE0(("ReadAndSetRegParams: Adapter %p, failed %x\n",
pAdapter, Status));
bDone = TRUE;
}
else
{
NDIS_STRING NetworkAddressName =
NDIS_STRING_CONST("NetworkAddress");
//
// Special case for the "NetworkAddress"
// parameter - if we just set this successfully,
// make note of the fact.
//
if (NdisEqualString(&ParamSubKeyName,
&NetworkAddressName,
TRUE))
{
TRACE1(("ReadAndSetRegParams: Adapter %p,"
" supports MAC address overwrite\n",
pAdapter));
pAdapter->MacOptions |=
NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE;
}
}
}
//
// Done with this subkey under ndi\Params.
//
NdisCloseConfiguration(ParamSubKeyHandle);
} // for each subkey under ndi\Params
//
// Done with "ndi\Params"
//
NdisCloseConfiguration(ParamsKeyHandle);
}
//
// Done with "ndi"
//
NdisCloseConfiguration(NdiKeyHandle);
}
//
// Done with configuration section for this device.
//
NdisCloseConfiguration(ConfigHandle);
}
while (FALSE);
return (Status);
}
/****************************************************************************/
/* SendConfiguredParameter */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Read the value of the specified config parameter, format a SetRequest, */
/* send it to the device, and wait for a response. */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to adapter structure for the device */
/* ConfigHandle - handle to configuration section for this device */
/* pParameterName - parameter key name */
/* pParameterType - parameter type */
/* */
/* Return: */
/* */
/* NDIS_STATUS */
/* */
/****************************************************************************/
NDIS_STATUS
SendConfiguredParameter(IN PRNDISMP_ADAPTER pAdapter,
IN NDIS_HANDLE ConfigHandle,
IN PNDIS_STRING pParameterName,
IN PNDIS_STRING pParameterType)
{
PRNDISMP_MESSAGE_FRAME pMsgFrame = NULL;
PRNDISMP_MESSAGE_FRAME pPendingMsgFrame = NULL;
PRNDISMP_REQUEST_CONTEXT pReqContext = NULL;
NDIS_PARAMETER_TYPE NdisParameterType;
PNDIS_CONFIGURATION_PARAMETER pConfigParameter;
ULONG ParameterValueLength;
PUCHAR pParameterValue;
UINT32 ParameterType;
NDIS_EVENT Event;
UINT BytesRead;
BOOLEAN bWokenUp;
RNDIS_REQUEST_ID RequestId;
PRNDIS_CONFIG_PARAMETER_INFO pRndisConfigInfo = NULL;
ULONG RndisConfigInfoLength;
PUCHAR pConfigInfoBuf;
NDIS_STATUS Status;
struct {
NDIS_STRING TypeName;
NDIS_PARAMETER_TYPE NdisType;
} StringToNdisType[] =
{
{NDIS_STRING_CONST("int"), NdisParameterInteger},
{NDIS_STRING_CONST("long"), NdisParameterInteger},
{NDIS_STRING_CONST("word"), NdisParameterInteger},
{NDIS_STRING_CONST("dword"), NdisParameterInteger},
{NDIS_STRING_CONST("edit"), NdisParameterString},
{NDIS_STRING_CONST("enum"), NdisParameterString}
};
ULONG NumTypes = sizeof(StringToNdisType);
ULONG i;
do
{
//
// Determine the parameter type.
//
for (i = 0; i < NumTypes; i++)
{
if (NdisEqualString(&StringToNdisType[i].TypeName,
pParameterType,
TRUE))
{
NdisParameterType = StringToNdisType[i].NdisType;
break;
}
}
if (i == NumTypes)
{
TRACE1(("SendConfiguredParam: Adapter %p, Param %ws, invalid type %ws\n",
pAdapter,
pParameterName->Buffer,
pParameterType->Buffer));
Status = NDIS_STATUS_INVALID_DATA;
break;
}
NdisReadConfiguration(
&Status,
&pConfigParameter,
ConfigHandle,
pParameterName,
NdisParameterType
);
if (Status != NDIS_STATUS_SUCCESS)
{
//
// It is okay for a parameter to not be configured.
//
Status = NDIS_STATUS_SUCCESS;
break;
}
if (NdisParameterType == NdisParameterInteger)
{
ParameterValueLength = sizeof(UINT32);
pParameterValue = (PUCHAR)&pConfigParameter->ParameterData.IntegerData;
ParameterType = RNDIS_CONFIG_PARAM_TYPE_INTEGER;
}
else
{
ASSERT(NdisParameterType == NdisParameterString);
ParameterValueLength = pConfigParameter->ParameterData.StringData.Length;
pParameterValue = (PUCHAR)pConfigParameter->ParameterData.StringData.Buffer;
ParameterType = RNDIS_CONFIG_PARAM_TYPE_STRING;
}
RndisConfigInfoLength = sizeof(RNDIS_CONFIG_PARAMETER_INFO) +
pParameterName->Length +
ParameterValueLength;
Status = MemAlloc(&pRndisConfigInfo, RndisConfigInfoLength);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
pRndisConfigInfo->ParameterNameOffset = sizeof(RNDIS_CONFIG_PARAMETER_INFO);
pRndisConfigInfo->ParameterNameLength = pParameterName->Length;
pRndisConfigInfo->ParameterType = ParameterType;
pRndisConfigInfo->ParameterValueOffset =
pRndisConfigInfo->ParameterNameOffset +
pRndisConfigInfo->ParameterNameLength;
pRndisConfigInfo->ParameterValueLength = ParameterValueLength;
//
// Copy in the parameter name.
//
pConfigInfoBuf = (PUCHAR)pRndisConfigInfo +
pRndisConfigInfo->ParameterNameOffset;
RNDISMP_MOVE_MEM(pConfigInfoBuf, pParameterName->Buffer, pParameterName->Length);
//
// Copy in the parameter value.
//
pConfigInfoBuf = (PUCHAR)pRndisConfigInfo +
pRndisConfigInfo->ParameterValueOffset;
RNDISMP_MOVE_MEM(pConfigInfoBuf, pParameterValue, ParameterValueLength);
//
// Build a Set Request
//
pMsgFrame = BuildRndisMessageCommon(pAdapter,
NULL,
REMOTE_NDIS_SET_MSG,
OID_GEN_RNDIS_CONFIG_PARAMETER,
pRndisConfigInfo,
RndisConfigInfoLength);
if (pMsgFrame == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
#if DBG
{
PMDL pTmpMdl = pMsgFrame->pMessageMdl;
ULONG Length;
PUCHAR pBuf;
ULONG OldDebugFlags = RndismpDebugFlags;
Length = MmGetMdlByteCount(pTmpMdl);
pBuf = MmGetSystemAddressForMdl(pTmpMdl);
RndismpDebugFlags |= DBG_DUMP;
TRACEDUMP(("SetRequest (OID_GEN_RNDIS_CONFIG_PARAMETER):"
" Adapter %p, Param %ws\n", pAdapter, pParameterName->Buffer), pBuf, Length);
RndismpDebugFlags = OldDebugFlags;
}
#endif
pReqContext = AllocateRequestContext(pAdapter);
if (pReqContext == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
// Fill up the request context.
pReqContext->pNdisRequest = NULL;
pReqContext->Oid = OID_GEN_RNDIS_CONFIG_PARAMETER;
NdisInitializeEvent(&Event);
pReqContext->pEvent = &Event;
pReqContext->bInternal = TRUE;
pReqContext->pBytesRead = &BytesRead;
pReqContext->InformationBufferLength = RndisConfigInfoLength;
pMsgFrame->pVc = NULL;
pMsgFrame->pReqContext = pReqContext;
// save off the request Id.
RequestId = pMsgFrame->RequestId;
// send the message to the microport.
RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, TRUE, NULL);
RNDISMP_ASSERT_AT_PASSIVE();
bWokenUp = NdisWaitEvent(&Event, MINIPORT_INIT_TIMEOUT);
// remove the message from the pending queue - it may or may not be there.
RNDISMP_LOOKUP_PENDING_MESSAGE(pPendingMsgFrame, pAdapter, RequestId);
if (!bWokenUp)
{
TRACE1(("No response to set parameter, Adapter %x\n", pAdapter));
Status = NDIS_STATUS_DEVICE_FAILED;
}
else
{
Status = pReqContext->CompletionStatus;
TRACE1(("Got response to set config param, Status %x, %d bytes read\n",
Status, BytesRead));
}
}
while (FALSE);
if (pRndisConfigInfo)
{
MemFree(pRndisConfigInfo, RndisConfigInfoLength);
}
if (pMsgFrame)
{
DereferenceMsgFrame(pMsgFrame);
}
if (pReqContext)
{
FreeRequestContext(pAdapter, pReqContext);
}
return (Status);
}
#ifdef NDIS51_MINIPORT
/****************************************************************************/
/* RndismpPnPEventNotify */
/****************************************************************************/
/* */
/* Routine Description: */
/* */
/* Entry point called by NDIS to notify us of PnP events affecting our */
/* device. The main event of importance to us is surprise removal. */
/* */
/* Arguments: */
/* */
/* pAdapter - Pointer to adapter structure */
/* */
/* Return: */
/* */
/* NDIS_STATUS */
/* */
/****************************************************************************/
VOID
RndismpPnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_DEVICE_PNP_EVENT EventCode,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength)
{
PRNDISMP_ADAPTER pAdapter;
// get adapter context
pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(pAdapter);
TRACE3(("PnPEventNotify: Adapter %x\n", pAdapter));
switch (EventCode)
{
case NdisDevicePnPEventSurpriseRemoved:
TRACE1(("PnPEventNotify: Adapter %p, surprise remove\n", pAdapter));
RndismpInternalHalt(pAdapter, FALSE);
break;
default:
break;
}
} // RndismpPnPEventNotify
#endif // NDIS51_MINIPORT