NDIS_STATUS HelperPortReceiveEventHandler( __in PMP_PORT Port, __in PMP_RX_MSDU PacketList, __in ULONG ReceiveFlags ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PDOT11_MAC_HEADER packetHeader; PMP_RX_MPDU rxFragment; USHORT fragmentSize; PMP_RX_MSDU currentPacket = PacketList; UNREFERENCED_PARAMETER(ReceiveFlags); // Process each of the packets internally while (currentPacket != NULL) { // We only accept 1 fragment rxFragment = MP_RX_MSDU_MPDU_AT(currentPacket, 0); packetHeader = MP_RX_MPDU_DATA(rxFragment); fragmentSize = (USHORT)MP_RX_MPDU_LENGTH(rxFragment); switch(packetHeader->FrameControl.Type) { case DOT11_FRAME_TYPE_MANAGEMENT: // // Process management packet // ndisStatus = HelperPortReceiveMgmtPacket( MP_GET_HELPPORT(Port), rxFragment, fragmentSize ); break; default: break; } // // Set the status. This determines if this packet should // be forwarded up or not // MP_RX_MSDU_STATUS(currentPacket) = ndisStatus; // Next packet currentPacket = MP_RX_MSDU_NEXT_MSDU(currentPacket); } return NDIS_STATUS_SUCCESS;
NDIS_STATUS HelperPortScanCompleteCallback( _In_ PMP_PORT Port, _In_ PVOID Data ) { PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); NDIS_STATUS completionStatus = *((PNDIS_STATUS)Data); PMP_SCAN_PARAMETERS scanParameters = helperPort->ScanContext.ActiveScanParameters; // Complete the partial scan HelperPortCompletePartialScan(helperPort, scanParameters, &completionStatus); return NDIS_STATUS_SUCCESS; }
PMP_BSS_LIST HelperPortQueryAndRefBSSList( __in PMP_PORT Port, __in PMP_PORT RequestingPort, __in PMP_RW_LOCK_STATE LockState ) { PMP_HELPER_PORT HelperPort = MP_GET_HELPPORT(Port); UNREFERENCED_PARAMETER(RequestingPort); // Acquire read lock on the BSS list MP_ACQUIRE_READ_LOCK(&(HelperPort->BSSList.ListLock), LockState); return &(HelperPort->BSSList);
NDIS_STATUS HelperPortScanExAccessCallback( _In_ PMP_PORT Port, _In_ PVOID Ctx ) { PMP_SCAN_PARAMETERS scanParameters = (PMP_SCAN_PARAMETERS)Ctx; PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); BOOLEAN performScan = TRUE; // The cancellation here is handled specially. Since we cannot abort // a request for exclusive access, its possible that our exclusive // access request gets honored after we have cancelled a scan HelperPortExclusiveAccessGranted(helperPort); MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); if ((scanParameters->State != SCAN_EXCLUSIVE_ACCESS_QUEUED) || (scanParameters->CancelScan)) { // The request has been cancelled and would get completed MpTrace(COMP_SCAN, DBG_NORMAL, ("Ignored exclusive access for cancelled/old scan request %p\n", scanParameters)); performScan = FALSE; } else { // Move forward with the scan scanParameters->State = SCAN_EXCLUSIVE_ACCESS_ACQUIRED; } MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); if (performScan) { HelperPortStartPartialScan(helperPort, scanParameters); } else { // Release exclusive access back to the HW HelperPortReleaseExclusiveAccess(helperPort); // Free the scan request HelperPortScanParametersReleaseRef(helperPort, scanParameters); } return NDIS_STATUS_SUCCESS; }
VOID HelperPortNotify( _In_ PMP_PORT Port, PVOID Notif ) { PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); PNOTIFICATION_DATA_HEADER notifyHeader = (PNOTIFICATION_DATA_HEADER)Notif; switch (notifyHeader->Type) { case NotificationOpLinkState: { POP_LINK_STATE_NOTIFICATION pMediaNotif = (POP_LINK_STATE_NOTIFICATION)Notif; MP_ACQUIRE_PORT_LOCK(Port, FALSE); if (pMediaNotif->MediaConnected) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Incrementing connect count for CONNECT. current = %d\n", helperPort->ScanContext.MediaConnectedCount)); MPASSERT(helperPort->ScanContext.MediaConnectedCount < MP_MAX_NUMBER_OF_PORT); helperPort->ScanContext.MediaConnectedCount++; } else { MpTrace(COMP_SCAN, DBG_NORMAL, ("Decrementing connect count for DISCONNECT. current = %d\n", helperPort->ScanContext.MediaConnectedCount)); MPASSERT(helperPort->ScanContext.MediaConnectedCount > 0); helperPort->ScanContext.MediaConnectedCount--; } MP_RELEASE_PORT_LOCK(Port, FALSE); break; } default: break; } }
NDIS_STATUS HelperPortFlushBSSList( __in PMP_PORT Port ) { MP_RW_LOCK_STATE LockState; PLIST_ENTRY pListEntry; PMP_BSS_ENTRY pBSSEntry = NULL; LONG APRefCount; LIST_ENTRY TempList; PMP_HELPER_PORT HelperPort = MP_GET_HELPPORT(Port); PMP_BSS_LIST pDiscoveredBSSList = &(HelperPort->BSSList); // // Entries that are currently in use (eg for connection) // we cannot flush and instead would put in the temporary queue // InitializeListHead(&TempList); MP_ACQUIRE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState); while (!IsListEmpty(&(pDiscoveredBSSList->List))) { pListEntry = RemoveHeadList(&(pDiscoveredBSSList->List)); pBSSEntry = CONTAINING_RECORD(pListEntry, MP_BSS_ENTRY, Link); APRefCount = NdisInterlockedDecrement(&(pBSSEntry->RefCount)); if (APRefCount == 0) { NdisAcquireSpinLock(&(pBSSEntry->Lock)); MPASSERT(pBSSEntry->pAssocRequest == NULL); MPASSERT(pBSSEntry->pAssocResponse == NULL); if (pBSSEntry->pDot11BeaconFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11BeaconFrame); pBSSEntry->pDot11BeaconFrame = NULL; pBSSEntry->BeaconFrameSize = 0; pBSSEntry->MaxBeaconFrameSize= 0; } if (pBSSEntry->pDot11ProbeFrame != NULL) { MP_FREE_MEMORY(pBSSEntry->pDot11ProbeFrame); pBSSEntry->pDot11ProbeFrame = NULL; pBSSEntry->ProbeFrameSize = 0; pBSSEntry->MaxProbeFrameSize= 0; } pBSSEntry->pDot11InfoElemBlob = NULL; pBSSEntry->InfoElemBlobSize = 0; NdisReleaseSpinLock(&(pBSSEntry->Lock)); MP_FREE_MEMORY(pBSSEntry); } else { // Restore refcount and save for adding back to list NdisInterlockedIncrement(&(pBSSEntry->RefCount)); InsertTailList(&TempList, pListEntry); } } pDiscoveredBSSList->NumOfBSSEntries = 0; // // Restore entries that are in use // while (!IsListEmpty(&TempList)) { pListEntry = RemoveHeadList(&TempList); InsertTailList(&(pDiscoveredBSSList->List), pListEntry); pDiscoveredBSSList->NumOfBSSEntries++; } // Since our scan list is flushed, also clear the last scan time HelperPort->ScanContext.LastScanTime = 0; MP_RELEASE_WRITE_LOCK(&(HelperPort->BSSList.ListLock), &LockState); return NDIS_STATUS_SUCCESS;
VOID HelperPortCancelScan( _In_ PMP_PORT Port, _In_ PMP_PORT RequestingPort ) { ULONG i; PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); PMP_SCAN_PARAMETERS scanParameters = NULL; MP_SCAN_STATE preCancelState = SCAN_EMPTY_REQUEST; NDIS_STATUS ndisStatus; BOOLEAN timerCancelled = FALSE; // Add this scan request to the list MP_ACQUIRE_PORT_LOCK(Port, FALSE); // Search for the scan request in our list for (i = 0; i < MP_MAX_NUMBER_OF_PORT; i++) { if ((helperPort->ScanContext.ScanParameters[i].State != SCAN_EMPTY_REQUEST) && (helperPort->ScanContext.ScanParameters[i].State != SCAN_COMPLETED) && (helperPort->ScanContext.ScanParameters[i].RequestingPort == RequestingPort)) { // The scan request from this port is in the queue scanParameters = &helperPort->ScanContext.ScanParameters[i]; scanParameters->CancelScan = TRUE; // Add a refcount to ensure that the structure does not get deleted on us MP_INCREMENT_SCAN_PARAMETER_REF(scanParameters); preCancelState = scanParameters->State; // Save the previous state (for tracking) scanParameters->TrackingPreCancelState = preCancelState; if (preCancelState == SCAN_QUEUED_FOR_PROCESSING) { // This request is not yet activated for processing. // Remove the request from the pending scan list. This is done right now // with the lock held so that the request does not get requeued scanParameters->State = SCAN_REQUEST_IN_USE; MpTrace(COMP_SCAN, DBG_NORMAL, ("Canceling unprocessed scan request\n")); } else if (preCancelState == SCAN_EXCLUSIVE_ACCESS_QUEUED) { // We are unsure if the exclusive access request would // be granted or not. It would be granted if the cancel was part of // a pause or something. It would not be granted if this was // a halt MpTrace(COMP_SCAN, DBG_NORMAL, ("Canceling scan request waiting for exclusive access\n")); } break; } } MP_RELEASE_PORT_LOCK(Port, FALSE); if (scanParameters == NULL) { // No scan to cancel. return; } if (preCancelState != SCAN_QUEUED_FOR_PROCESSING) { // NOTE: Since we added the ref, we know that the ScanParameters buffer is available // If we have the timer running, force fire the timer timerCancelled = NdisCancelTimerObject(helperPort->ScanContext.Timer_Scan); if (timerCancelled == TRUE) { // We cancelled the timer, so we would need to invoke the complete ourselves MpTrace(COMP_SCAN, DBG_NORMAL, ("Canceling scan request waiting for scan timer\n")); HelperPortScanTimerCallback(helperPort); } else { // We could be waiting for exclusive access if (preCancelState == SCAN_EXCLUSIVE_ACCESS_QUEUED) { // We would complete the scan here. Because of the cancel flag, the // exclusive access routine would not proceed with the scan // if it got called ndisStatus = NDIS_STATUS_REQUEST_ABORTED; MP_ACQUIRE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); // Clear the active pointer helperPort->ScanContext.ActiveScanParameters = NULL; scanParameters->State = SCAN_COMPLETED; MP_RELEASE_PORT_LOCK(HELPPORT_GET_MP_PORT(helperPort), FALSE); // Now perform the indication HelperPortIndicateScanCompletion(helperPort, scanParameters, &ndisStatus); // We dont remove the reference here. We wait for the ex or the scan // to do it } // Ask the HW to cancel the scan (if it has it) VNic11CancelScan(HELPPORT_GET_VNIC(helperPort)); } // Now wait for the scan complete to get indicated while (scanParameters->State != SCAN_COMPLETED) { MpTrace(COMP_SCAN, DBG_NORMAL, ("Waiting for scan operation to complete\n")); NdisMSleep(20 * 1000); } // This lock is acquired to ensure that the free here does not conflict with an // in progress scan completion MP_ACQUIRE_PORT_LOCK(Port, FALSE); HelperPortScanParametersReleaseRef(helperPort, scanParameters); MP_RELEASE_PORT_LOCK(Port, FALSE); // If there is a different second scan pending, process it HelperPortProcessPendingScans(helperPort); } else { // This scan was never started, we need to complete the scan request & we are done ndisStatus = NDIS_STATUS_REQUEST_ABORTED; HelperPortIndicateScanCompletion(helperPort, scanParameters, &ndisStatus); MP_ACQUIRE_PORT_LOCK(Port, FALSE); scanParameters->State = SCAN_COMPLETED; HelperPortScanParametersReleaseRef(helperPort, scanParameters); MP_RELEASE_PORT_LOCK(Port, FALSE); } }
NDIS_STATUS HelperPortHandleScan( _In_ PMP_PORT Port, _In_ PMP_PORT RequestingPort, _In_ PMP_SCAN_REQUEST ScanRequest, _In_ PORT11_GENERIC_CALLBACK_FUNC CompletionHandler ) { PMP_SCAN_PARAMETERS scanParameters = NULL; // If we cannot find an empty slot, we return media in use NDIS_STATUS ndisStatus = NDIS_STATUS_DOT11_MEDIA_IN_USE; PMP_HELPER_PORT helperPort = MP_GET_HELPPORT(Port); ULONG i; do { // Add this scan request to the pending scan list MP_ACQUIRE_PORT_LOCK(Port, FALSE); // Find a structure we can use for (i = 0; i < MP_MAX_NUMBER_OF_PORT; i++) { if (helperPort->ScanContext.ScanParameters[i].State == SCAN_EMPTY_REQUEST) { scanParameters = &helperPort->ScanContext.ScanParameters[i]; helperPort->ScanContext.ParametersCount++; MP_INCREMENT_SCAN_PARAMETER_REF(scanParameters); // Save the passed in information scanParameters->RequestingPort = RequestingPort; scanParameters->PortScanRequest = ScanRequest; scanParameters->CompletionHandler = CompletionHandler; // Scan would start at the first channel of the first phy scanParameters->NextChannelIndex = 0; scanParameters->CurrentPhyIndex = 0; // Queue it for processing scanParameters->CancelScan = 0; scanParameters->State = SCAN_QUEUED_FOR_PROCESSING; ndisStatus = NDIS_STATUS_SUCCESS; break; } } MP_RELEASE_PORT_LOCK(Port, FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_SCAN, DBG_SERIOUS, ("Unable to save scan parameters\n")); break; } // Let the scan request proceed HelperPortProcessPendingScans(helperPort); }while (FALSE); if (ndisStatus != NDIS_STATUS_SUCCESS) { // Free stuff that we may have allocated if (scanParameters != NULL) { // This cannot be left in our list HelperPortScanParametersReleaseRef(helperPort, scanParameters); } } return ndisStatus; }