/*************************************************************************** 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; Adapter->RequestId = 1; #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(); // Keep the message frame around until send-completion. ReferenceMsgFrame(pMsgFrame); // send the message to the microport. RNDISMP_SEND_TO_MICROPORT(Adapter, pMsgFrame, TRUE, CompleteSendInit); 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; } // // The message frame will be deref'ed once when we receive // a reply to the query, and once below, when this thread // is done with the frame. Make sure that it doesn't go away // until this thread is done with it. // ReferenceMsgFrame(pMsgFrame); // 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; pReqContext->bInternal = TRUE; NdisInitializeEvent(&Event); pReqContext->pEvent = &Event; pMsgFrame->pVc = NULL; pMsgFrame->pReqContext = pReqContext; RequestId = pMsgFrame->RequestId; // 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 // BUILD_WIN9X if (Adapter->bRunningOnWin9x) { // // Query and cache the values of certain OIDs that NDIS queries // us for, so that when we get those queries, we can complete // them immediately (synchronously). This is to work around // a problem where NDIS (98/SE only) times out too soon on // internally generated queries. // Status = SyncQueryDevice(Adapter, OID_GEN_MAXIMUM_FRAME_SIZE, (PUCHAR)&Adapter->MaximumFrameSize, sizeof(Adapter->MaximumFrameSize)); if (Status != NDIS_STATUS_SUCCESS) { TRACE1(("Init: Adapter %x, failed to query MAXIMUM_FRAME_SIZE\n", Adapter)); Status = NDIS_STATUS_DEVICE_FAILED; break; } Status = SyncQueryDevice(Adapter, OID_GEN_MAC_OPTIONS, (PUCHAR)&Adapter->MacOptions, sizeof(Adapter->MacOptions)); if (Status != NDIS_STATUS_SUCCESS) { TRACE1(("Init: Adapter %x, failed to query MAC_OPTIONS\n", Adapter)); Status = NDIS_STATUS_DEVICE_FAILED; break; } Status = SyncQueryDevice(Adapter, OID_802_3_MAXIMUM_LIST_SIZE, (PUCHAR)&Adapter->MaxMulticastListSize, sizeof(Adapter->MaxMulticastListSize)); if (Status != NDIS_STATUS_SUCCESS) { TRACE1(("Init: Adapter %x, failed to query MAX_LIST_SIZE\n", Adapter)); Status = NDIS_STATUS_DEVICE_FAILED; break; } Status = SyncQueryDevice(Adapter, OID_802_3_CURRENT_ADDRESS, (PUCHAR)Adapter->MacAddress, ETH_LENGTH_OF_ADDRESS); if (Status != NDIS_STATUS_SUCCESS) { TRACE1(("Init: Adapter %x, failed to query CURRENT_ADDR\n", Adapter)); Status = NDIS_STATUS_DEVICE_FAILED; break; } TRACE1(("Init: Adapter %p, OID caching done!\n", Adapter)); } // 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; pKeepaliveComplete = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage); // save off status Status = pKeepaliveComplete->Status; TRACE2(("KeepAliveCompletionMessage (%d) on adapter %p\n", pKeepaliveComplete->RequestId, pAdapter)); // 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 /****************************************************************************/ /* CompleteSendInit */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Utility function to handle completion of sending of an INIT message. */ /* We simply free up the message frame. */ /* */ /* Arguments: */ /* */ /* pMsgFrame - Frame structure describing the INIT message */ /* SendStatus - outcome of sending this message. */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID CompleteSendInit(IN PRNDISMP_MESSAGE_FRAME pMsgFrame, IN NDIS_STATUS SendStatus) { PRNDISMP_ADAPTER pAdapter; pAdapter = pMsgFrame->pAdapter; TRACE1(("CompleteSendInit: Adapter %x, SendStatus %x\n", pAdapter, SendStatus)); DereferenceMsgFrame(pMsgFrame); } // CompleteSendInit /****************************************************************************/ /* 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 = RNDISMP_GET_MDL_LENGTH(pTmpMdl); pBuf = RNDISMP_GET_MDL_ADDRESS(pTmpMdl); if (pBuf != NULL) { 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