_Use_decl_annotations_ VOID FilterCancelOidRequest( NDIS_HANDLE FilterModuleContext, PVOID RequestId ) /*++ Routine Description: Cancels an OID request If your filter driver does not intercept and hold onto any OID requests, then you do not need to implement this routine. You may simply omit it. Furthermore, if the filter only holds onto OID requests so it can pass down a clone (the most common case) the filter does not need to implement this routine; NDIS will then automatically request that the lower-level filter/miniport cancel your cloned OID. Most filters do not need to implement this routine. Arguments: FilterModuleContext - our filter RequestId - identifies the request(s) to cancel --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PNDIS_OID_REQUEST Request = NULL; POTLWF_REQUEST_CONTEXT Context; PNDIS_OID_REQUEST OriginalRequest = NULL; BOOLEAN bFalse = FALSE; LogFuncEntryMsg(DRIVER_OID, "Filter: %p, RequestId: %p", FilterModuleContext, RequestId); FILTER_ACQUIRE_LOCK(&pFilter->PendingOidRequestLock, bFalse); Request = pFilter->PendingOidRequest; if (Request != NULL) { Context = (POTLWF_REQUEST_CONTEXT)(&Request->SourceReserved[0]); OriginalRequest = (*Context); } if ((OriginalRequest != NULL) && (OriginalRequest->RequestId == RequestId)) { FILTER_RELEASE_LOCK(&pFilter->PendingOidRequestLock, bFalse); NdisFCancelOidRequest(pFilter->FilterHandle, RequestId); } else { FILTER_RELEASE_LOCK(&pFilter->PendingOidRequestLock, bFalse); } LogFuncExit(DRIVER_OID); }
VOID otLwfEventProcessingIndicateAddressChange( _In_ PMS_FILTER pFilter, _In_ MIB_NOTIFICATION_TYPE NotificationType, _In_ PIN6_ADDR pAddr ) { LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", pFilter); NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE); POTLWF_ADDR_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(OTLWF_ADDR_EVENT)); if (Event == NULL) { LogWarning(DRIVER_DEFAULT, "Failed to alloc new OTLWF_ADDR_EVENT"); } else { Event->NotificationType = NotificationType; Event->Address = *pAddr; // Add the event to the queue NdisAcquireSpinLock(&pFilter->EventsLock); InsertTailList(&pFilter->AddressChangesHead, &Event->Link); NdisReleaseSpinLock(&pFilter->EventsLock); // Set the event to indicate we have a new address to process KeSetEvent(&pFilter->EventWorkerThreadProcessAddressChanges, 0, FALSE); } LogFuncExit(DRIVER_DEFAULT); }
_Use_decl_annotations_ VOID FilterDetach( NDIS_HANDLE FilterModuleContext ) /*++ Routine Description: Filter detach routine. This is a required function that will deallocate all the resources allocated during FilterAttach. NDIS calls FilterAttach to remove a filter instance from a filter stack. Arguments: FilterModuleContext - pointer to the filter context area. Return Value: None. NOTE: Called at PASSIVE_LEVEL and the filter is in paused state --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", FilterModuleContext); // Filter must be in paused state and pretty much inactive NT_ASSERT(pFilter->State == FilterPaused); NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_UNINTIALIZED); // // Detach must not fail, so do not put any code here that can possibly fail. // // Remove this Filter from the global list NdisAcquireSpinLock(&FilterListLock); RemoveEntryList(&pFilter->FilterModuleLink); NdisReleaseSpinLock(&FilterListLock); // Unregister from address change notifications CancelMibChangeNotify2(pFilter->AddressChangeHandle); pFilter->AddressChangeHandle = NULL; // Close the registry key if (pFilter->InterfaceRegKey) { ZwClose(pFilter->InterfaceRegKey); pFilter->InterfaceRegKey = NULL; } // Free the memory allocated NdisFreeMemory(pFilter, 0, 0); LogFuncExit(DRIVER_DEFAULT); }
_Use_decl_annotations_ VOID FilterStatus( NDIS_HANDLE FilterModuleContext, PNDIS_STATUS_INDICATION StatusIndication ) /*++ Routine Description: Status indication handler Arguments: FilterModuleContext - our filter context StatusIndication - the status being indicated NOTE: called at <= DISPATCH_LEVEL FILTER driver may call NdisFIndicateStatus to generate a status indication to all higher layer modules. --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p, IndicateStatus: %8x", FilterModuleContext, StatusIndication->StatusCode); if (StatusIndication->StatusCode == NDIS_STATUS_LINK_STATE) { PNDIS_LINK_STATE LinkState = (PNDIS_LINK_STATE)StatusIndication->StatusBuffer; LogInfo(DRIVER_DEFAULT, "Filter: %p, MediaConnectState: %u", FilterModuleContext, LinkState->MediaConnectState); // Cache the link state from the miniport memcpy(&pFilter->MiniportLinkState, LinkState, sizeof(NDIS_LINK_STATE)); } NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication); LogFuncExit(DRIVER_DEFAULT); }
_Use_decl_annotations_ NDIS_STATUS FilterOidRequest( NDIS_HANDLE FilterModuleContext, PNDIS_OID_REQUEST Request ) /*++ Routine Description: Request handler Handle requests from upper layers Arguments: FilterModuleContext - our filter Request - the request passed down Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_PENDING NDIS_STATUS_XXX NOTE: Called at <= DISPATCH_LEVEL (unlike a miniport's MiniportOidRequest) --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; NDIS_STATUS Status; PNDIS_OID_REQUEST ClonedRequest=NULL; BOOLEAN bSubmitted = FALSE; POTLWF_REQUEST_CONTEXT Context; BOOLEAN bFalse = FALSE; LogFuncEntryMsg(DRIVER_OID, "Request %p", Request); // // Most of the time, a filter will clone the OID request and pass down // the clone. When the clone completes, the filter completes the original // OID request. // // If your filter needs to modify a specific request, it can modify the // request before or after sending down the cloned request. Or, it can // complete the original request on its own without sending down any // clone at all. // // If your filter driver does not need to modify any OID requests, then // you may simply omit this routine entirely; NDIS will pass OID requests // down on your behalf. This is more efficient than implementing a // routine that does nothing but clone all requests, as in the sample here. // do { Status = NdisAllocateCloneOidRequest(pFilter->FilterHandle, Request, OTLWF_CLONED_OID_TAG, &ClonedRequest); if (Status != NDIS_STATUS_SUCCESS) { LogWarning(DRIVER_OID, "Failed to Clone Request, %!NDIS_STATUS!", Status); break; } Context = (POTLWF_REQUEST_CONTEXT)(&ClonedRequest->SourceReserved[0]); *Context = Request; bSubmitted = TRUE; // // Use same request ID // ClonedRequest->RequestId = Request->RequestId; pFilter->PendingOidRequest = ClonedRequest; LogVerbose(DRIVER_OID, "Sending (cloned) Oid Request %p", ClonedRequest); Status = NdisFOidRequest(pFilter->FilterHandle, ClonedRequest); if (Status != NDIS_STATUS_PENDING) { FilterOidRequestComplete(pFilter, ClonedRequest, Status); Status = NDIS_STATUS_PENDING; } } while(bFalse); if (bSubmitted == FALSE) { switch(Request->RequestType) { case NdisRequestMethod: Request->DATA.METHOD_INFORMATION.BytesRead = 0; Request->DATA.METHOD_INFORMATION.BytesNeeded = 0; Request->DATA.METHOD_INFORMATION.BytesWritten = 0; break; case NdisRequestSetInformation: Request->DATA.SET_INFORMATION.BytesRead = 0; Request->DATA.SET_INFORMATION.BytesNeeded = 0; break; case NdisRequestQueryInformation: case NdisRequestQueryStatistics: default: Request->DATA.QUERY_INFORMATION.BytesWritten = 0; Request->DATA.QUERY_INFORMATION.BytesNeeded = 0; break; } } LogFuncExitNDIS(DRIVER_OID, Status); return Status; }
_Use_decl_annotations_ VOID FilterOidRequestComplete( NDIS_HANDLE FilterModuleContext, PNDIS_OID_REQUEST Request, NDIS_STATUS Status ) /*++ Routine Description: Notification that an OID request has been completed If this filter sends a request down to a lower layer, and the request is pended, the FilterOidRequestComplete routine is invoked when the request is complete. Most requests we've sent are simply clones of requests received from a higher layer; all we need to do is complete the original higher request. However, if this filter driver sends original requests down, it must not attempt to complete a pending request to the higher layer. Arguments: FilterModuleContext - our filter context area NdisRequest - the completed request Status - completion status --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PNDIS_OID_REQUEST OriginalRequest; POTLWF_REQUEST_CONTEXT Context; BOOLEAN bFalse = FALSE; LogFuncEntryMsg(DRIVER_OID, "Filter: %p, Request %p", FilterModuleContext, Request); Context = (POTLWF_REQUEST_CONTEXT)(&Request->SourceReserved[0]); OriginalRequest = (*Context); // // This is an internal request // if (OriginalRequest == NULL) { otLwfInternalRequestComplete(pFilter, Request, Status); LogFuncExit(DRIVER_OID); return; } FILTER_ACQUIRE_LOCK(&pFilter->PendingOidRequestLock, bFalse); ASSERT(pFilter->PendingOidRequest == Request); pFilter->PendingOidRequest = NULL; FILTER_RELEASE_LOCK(&pFilter->PendingOidRequestLock, bFalse); // // Copy the information from the returned request to the original request // switch(Request->RequestType) { case NdisRequestMethod: OriginalRequest->DATA.METHOD_INFORMATION.OutputBufferLength = Request->DATA.METHOD_INFORMATION.OutputBufferLength; OriginalRequest->DATA.METHOD_INFORMATION.BytesRead = Request->DATA.METHOD_INFORMATION.BytesRead; OriginalRequest->DATA.METHOD_INFORMATION.BytesNeeded = Request->DATA.METHOD_INFORMATION.BytesNeeded; OriginalRequest->DATA.METHOD_INFORMATION.BytesWritten = Request->DATA.METHOD_INFORMATION.BytesWritten; break; case NdisRequestSetInformation: OriginalRequest->DATA.SET_INFORMATION.BytesRead = Request->DATA.SET_INFORMATION.BytesRead; OriginalRequest->DATA.SET_INFORMATION.BytesNeeded = Request->DATA.SET_INFORMATION.BytesNeeded; break; case NdisRequestQueryInformation: case NdisRequestQueryStatistics: default: OriginalRequest->DATA.QUERY_INFORMATION.BytesWritten = Request->DATA.QUERY_INFORMATION.BytesWritten; OriginalRequest->DATA.QUERY_INFORMATION.BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded; break; } (*Context) = NULL; LogVerbose(DRIVER_OID, "Freeing (cloned) Oid Request %p", Request); NdisFreeCloneOidRequest(pFilter->FilterHandle, Request); LogVerbose(DRIVER_OID, "Completing (external) Oid Request %p", OriginalRequest); NdisFOidRequestComplete(pFilter->FilterHandle, OriginalRequest, Status); LogFuncExit(DRIVER_OID); }
NTSTATUS otLwfEventProcessingStart( _In_ PMS_FILTER pFilter ) { NTSTATUS status = STATUS_SUCCESS; HANDLE threadHandle = NULL; LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p, TimeIncrement = %u", pFilter, KeQueryTimeIncrement()); pFilter->NextAlarmTickCount.QuadPart = 0; NT_ASSERT(pFilter->EventWorkerThread == NULL); if (pFilter->EventWorkerThread != NULL) { status = STATUS_ALREADY_REGISTERED; goto error; } // Make sure to reset the necessary events KeResetEvent(&pFilter->EventWorkerThreadStopEvent); KeResetEvent(&pFilter->SendNetBufferListComplete); KeResetEvent(&pFilter->EventWorkerThreadEnergyScanComplete); // Start the worker thread status = PsCreateSystemThread( &threadHandle, // ThreadHandle THREAD_ALL_ACCESS, // DesiredAccess NULL, // ObjectAttributes NULL, // ProcessHandle NULL, // ClientId otLwfEventWorkerThread, // StartRoutine pFilter // StartContext ); if (!NT_SUCCESS(status)) { LogError(DRIVER_DEFAULT, "PsCreateSystemThread failed, %!STATUS!", status); goto error; } // Grab the object reference to the worker thread status = ObReferenceObjectByHandle( threadHandle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &pFilter->EventWorkerThread, NULL ); if (!NT_VERIFYMSG("ObReferenceObjectByHandle can't fail with a valid kernel handle", NT_SUCCESS(status))) { LogError(DRIVER_DEFAULT, "ObReferenceObjectByHandle failed, %!STATUS!", status); KeSetEvent(&pFilter->EventWorkerThreadStopEvent, IO_NO_INCREMENT, FALSE); } ZwClose(threadHandle); error: if (!NT_SUCCESS(status)) { ExSetTimerResolution(0, FALSE); } LogFuncExitNT(DRIVER_DEFAULT, status); return status; }
VOID otLwfEventProcessingStop( _In_ PMS_FILTER pFilter ) { PLIST_ENTRY Link = NULL; LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", pFilter); // By this point, we have disabled the Data Path, so no more // NBLs should be queued up. // Clean up worker thread if (pFilter->EventWorkerThread) { LogInfo(DRIVER_DEFAULT, "Stopping event processing worker thread and waiting for it to complete."); // Send event to shutdown worker thread KeSetEvent(&pFilter->EventWorkerThreadStopEvent, 0, FALSE); // Wait for worker thread to finish KeWaitForSingleObject( pFilter->EventWorkerThread, Executive, KernelMode, FALSE, NULL ); // Free worker thread ObDereferenceObject(pFilter->EventWorkerThread); pFilter->EventWorkerThread = NULL; LogInfo(DRIVER_DEFAULT, "Event processing worker thread cleaned up."); } // Clean up any left over events if (pFilter->AddressChangesHead.Flink) { Link = pFilter->AddressChangesHead.Flink; while (Link != &pFilter->AddressChangesHead) { POTLWF_ADDR_EVENT Event = CONTAINING_RECORD(Link, OTLWF_ADDR_EVENT, Link); Link = Link->Flink; // Delete the event NdisFreeMemory(Event, 0, 0); } } // Clean up any left over events if (pFilter->NBLsHead.Flink) { Link = pFilter->NBLsHead.Flink; while (Link != &pFilter->NBLsHead) { POTLWF_NBL_EVENT Event = CONTAINING_RECORD(Link, OTLWF_NBL_EVENT, Link); Link = Link->Flink; otLwfCompleteNBLs(pFilter, FALSE, Event->NetBufferLists, STATUS_CANCELLED); // Delete the event NdisFreeMemory(Event, 0, 0); } } // Clean up any left over events if (pFilter->MacFramesHead.Flink) { Link = pFilter->MacFramesHead.Flink; while (Link != &pFilter->MacFramesHead) { POTLWF_MAC_FRAME_EVENT Event = CONTAINING_RECORD(Link, OTLWF_MAC_FRAME_EVENT, Link); Link = Link->Flink; // Delete the event NdisFreeMemory(Event, 0, 0); } } // Reinitialize the list head InitializeListHead(&pFilter->AddressChangesHead); InitializeListHead(&pFilter->NBLsHead); InitializeListHead(&pFilter->MacFramesHead); if (pFilter->EventIrpListHead.Flink) { FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, FALSE); // Clean up any left over IRPs Link = pFilter->EventIrpListHead.Flink; while (Link != &pFilter->EventIrpListHead) { PIRP Irp = CONTAINING_RECORD(Link, IRP, Tail.Overlay.ListEntry); Link = Link->Flink; // Before we are allowed to complete the pending IRP, we must remove the cancel routine KIRQL irql; IoAcquireCancelSpinLock(&irql); IoSetCancelRoutine(Irp, NULL); IoReleaseCancelSpinLock(irql); Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } // Reinitialize the list head InitializeListHead(&pFilter->EventIrpListHead); FILTER_RELEASE_LOCK(&pFilter->EventsLock, FALSE); } LogFuncExit(DRIVER_DEFAULT); }
_Use_decl_annotations_ NDIS_STATUS FilterPause( NDIS_HANDLE FilterModuleContext, PNDIS_FILTER_PAUSE_PARAMETERS PauseParameters ) /*++ Routine Description: Filter pause routine. Complete all the outstanding sends and queued sends, wait for all the outstanding recvs to be returned and return all the queued receives. Arguments: FilterModuleContext - pointer to the filter context stucture PauseParameters - additional information about the pause Return Value: NDIS_STATUS_SUCCESS if filter pauses successfully, NDIS_STATUS_PENDING if not. No other return value is allowed (pause must succeed, eventually). N.B.: When the filter is in Pausing state, it can still process OID requests, complete sending, and returning packets to NDIS, and also indicate status. After this function completes, the filter must not attempt to send or receive packets, but it may still process OID requests and status indications. --*/ { PMS_FILTER pFilter = (PMS_FILTER)(FilterModuleContext); NDIS_STATUS Status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(PauseParameters); LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", FilterModuleContext); // // Set the flag that the filter is going to pause // NT_ASSERT(pFilter->State == FilterRunning); NdisAcquireSpinLock(&FilterListLock); pFilter->State = FilterPausing; NdisReleaseSpinLock(&FilterListLock); // // Send final notification of interface removal // otLwfNotifyDeviceAvailabilityChange(pFilter, FALSE); LogInfo(DRIVER_DEFAULT, "Interface %!GUID! removal.", &pFilter->InterfaceGuid); // // Disable external references and wait for existing calls to complete // LogInfo(DRIVER_DEFAULT, "Disabling and waiting for external references to release"); ExWaitForRundownProtectionRelease(&pFilter->ExternalRefs); LogInfo(DRIVER_DEFAULT, "External references released."); // // Clean up based on the device mode // if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) { otLwfUninitializeThreadMode(pFilter); } else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) { otLwfTunUninitialize(pFilter); } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; // // Clean up the Spinel command processing // otLwfCmdUninitialize(pFilter); // // Set the state back to Paused now that we are done // pFilter->State = FilterPaused; LogFuncExitNDIS(DRIVER_DEFAULT, Status); return Status; }
_Use_decl_annotations_ NDIS_STATUS FilterRestart( NDIS_HANDLE FilterModuleContext, PNDIS_FILTER_RESTART_PARAMETERS RestartParameters ) /*++ Routine Description: Filter restart routine. Start the datapath - begin sending and receiving NBLs. Arguments: FilterModuleContext - pointer to the filter context stucture. RestartParameters - additional information about the restart operation. Return Value: NDIS_STATUS_SUCCESS: if filter restarts successfully NDIS_STATUS_XXX: Otherwise. --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; PVOID SpinelCapsDataBuffer = NULL; const uint8_t* SpinelCapsPtr = NULL; spinel_size_t SpinelCapsLen = 0; NL_INTERFACE_KEY key = {0}; NL_INTERFACE_RW interfaceRw; ULONG ThreadOnHost = TRUE; PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", FilterModuleContext); NT_ASSERT(pFilter->State == FilterPaused); NdisRestartAttributes = RestartParameters->RestartAttributes; // // If NdisRestartAttributes is not NULL, then the filter can modify generic // attributes and add new media specific info attributes at the end. // Otherwise, if NdisRestartAttributes is NULL, the filter should not try to // modify/add attributes. // if (NdisRestartAttributes != NULL) { ASSERT(NdisRestartAttributes->Oid == OID_GEN_MINIPORT_RESTART_ATTRIBUTES); NdisGeneralAttributes = (PNDIS_RESTART_GENERAL_ATTRIBUTES)NdisRestartAttributes->Data; // // Check to see if we need to change any attributes. For example, the // driver can change the current MAC address here. Or the driver can add // media specific info attributes. // NdisGeneralAttributes->LookaheadSize = 128; } // Initialize the Spinel command processing NdisStatus = otLwfCmdInitialize(pFilter); if (NdisStatus != NDIS_STATUS_SUCCESS) { LogError(DRIVER_DEFAULT, "otLwfCmdInitialize failed, %!NDIS_STATUS!", NdisStatus); goto exit; } // Query the device capabilities NtStatus = otLwfCmdGetProp(pFilter, SpinelCapsDataBuffer, SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, &SpinelCapsPtr, &SpinelCapsLen); if (!NT_SUCCESS(NtStatus)) { NdisStatus = NDIS_STATUS_NOT_SUPPORTED; LogError(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_CAPS, %!STATUS!", NtStatus); goto exit; } // Iterate and process returned capabilities while (SpinelCapsLen > 0) { ULONG SpinelCap = 0; spinel_ssize_t len = spinel_datatype_unpack(SpinelCapsPtr, SpinelCapsLen, SPINEL_DATATYPE_UINT_PACKED_S, &SpinelCap); if (len < 1) break; SpinelCapsLen -= (spinel_size_t)len; switch (SpinelCap) { case SPINEL_CAP_MAC_RAW: pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO; pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT; pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN; break; case SPINEL_CAP_NET_THREAD_1_0: pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_THREAD_1_0; break; default: break; } } // Set the state indicating where we should be running the Thread logic (Host or Device). if (!NT_SUCCESS(GetRegDWORDValue(pFilter, L"RunOnHost", &ThreadOnHost))) { // Default to running on the host if the key isn't present ThreadOnHost = TRUE; SetRegDWORDValue(pFilter, L"RunOnHost", ThreadOnHost); } LogInfo(DRIVER_DEFAULT, "Filter: %p initializing ThreadOnHost=%d", FilterModuleContext, ThreadOnHost); // Initialize the processing logic if (ThreadOnHost) { // Ensure the device has the capabilities to support raw radio commands if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO) == 0) { LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support raw radio commands"); NdisStatus = NDIS_STATUS_NOT_SUPPORTED; goto exit; } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_RADIO_MODE; NtStatus = otLwfInitializeThreadMode(pFilter); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "otLwfInitializeThreadMode failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; goto exit; } } else { // Ensure the device has the capabilities to support Thread commands if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_THREAD_1_0) == 0) { LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support thread commands"); NdisStatus = NDIS_STATUS_NOT_SUPPORTED; goto exit; } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_THREAD_MODE; NtStatus = otLwfTunInitialize(pFilter); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "otLwfInitializeTunnelMode failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; goto exit; } } // // Disable DAD and Neighbor advertisements // key.Luid = pFilter->InterfaceLuid; NlInitializeInterfaceRw(&interfaceRw); interfaceRw.DadTransmits = 0; interfaceRw.SendUnsolicitedNeighborAdvertisementOnDad = FALSE; NtStatus = NsiSetAllParameters( NsiActive, NsiSetDefault, &NPI_MS_IPV6_MODULEID, NlInterfaceObject, &key, sizeof(key), &interfaceRw, sizeof(interfaceRw)); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "NsiSetAllParameters (NlInterfaceObject) failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; goto exit; } // // Enable the external references to the filter // ExReInitializeRundownProtection(&pFilter->ExternalRefs); // // If everything is OK, set the filter in running state. // pFilter->State = FilterRunning; // when successful otLwfNotifyDeviceAvailabilityChange(pFilter, TRUE); LogInfo(DRIVER_DEFAULT, "Interface %!GUID! arrival, Filter=%p", &pFilter->InterfaceGuid, pFilter); exit: // // Ensure the state is Paused if restart failed. // if (NdisStatus != NDIS_STATUS_SUCCESS) { pFilter->State = FilterPaused; if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) { otLwfUninitializeThreadMode(pFilter); } else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) { otLwfTunUninitialize(pFilter); } pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; // Clean up Spinel command processing otLwfCmdUninitialize(pFilter); } // Free the buffer for the capabilities we queried if (SpinelCapsDataBuffer != NULL) { FILTER_FREE_MEM(SpinelCapsDataBuffer); } LogFuncExitNDIS(DRIVER_DEFAULT, NdisStatus); return NdisStatus; }