| /* |
| * Copyright (c) 2007-2008 Atheros Communications Inc. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include "cprecomp.h" |
| |
| void zfScanMgrInit(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| wd->sta.scanMgr.scanReqs[0] = 0; |
| wd->sta.scanMgr.scanReqs[1] = 0; |
| |
| wd->sta.scanMgr.currScanType = ZM_SCAN_MGR_SCAN_NONE; |
| wd->sta.scanMgr.scanStartDelay = 3; |
| //wd->sta.scanMgr.scanStartDelay = 0; |
| } |
| |
| u8_t zfScanMgrScanStart(zdev_t* dev, u8_t scanType) |
| { |
| u8_t i; |
| |
| zmw_get_wlan_dev(dev); |
| |
| zm_debug_msg1("scanType = ", scanType); |
| |
| zmw_declare_for_critical_section(); |
| |
| if ( scanType != ZM_SCAN_MGR_SCAN_INTERNAL && |
| scanType != ZM_SCAN_MGR_SCAN_EXTERNAL ) |
| { |
| zm_debug_msg0("unknown scanType"); |
| return 1; |
| } |
| else if (zfStaIsConnecting(dev)) |
| { |
| zm_debug_msg0("reject scan request due to connecting"); |
| return 1; |
| } |
| |
| i = scanType - 1; |
| |
| zmw_enter_critical_section(dev); |
| |
| if ( wd->sta.scanMgr.scanReqs[i] == 1 ) |
| { |
| zm_debug_msg1("scan rescheduled", scanType); |
| goto scan_done; |
| } |
| |
| wd->sta.scanMgr.scanReqs[i] = 1; |
| zm_debug_msg1("scan scheduled: ", scanType); |
| |
| // If there's no scan pending, we do the scan right away. |
| // If there's an internal scan and the new scan request is external one, |
| // we will restart the scan. |
| if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_NONE ) |
| { |
| goto schedule_scan; |
| } |
| else if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_INTERNAL && |
| scanType == ZM_SCAN_MGR_SCAN_EXTERNAL ) |
| { |
| // Stop the internal scan & schedule external scan first |
| zfTimerCancel(dev, ZM_EVENT_SCAN); |
| |
| /* Fix for WHQL sendrecv => we do not apply delay time in which the device |
| stop transmitting packet when we already connect to some AP */ |
| wd->sta.bScheduleScan = FALSE; |
| |
| zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); |
| zfTimerCancel(dev, ZM_EVENT_IN_SCAN); |
| |
| wd->sta.bChannelScan = FALSE; |
| goto schedule_scan; |
| } |
| else |
| { |
| zm_debug_msg0("Scan is busy...waiting later to start\n"); |
| } |
| |
| zmw_leave_critical_section(dev); |
| return 0; |
| |
| scan_done: |
| zmw_leave_critical_section(dev); |
| return 1; |
| |
| schedule_scan: |
| |
| wd->sta.bScheduleScan = TRUE; |
| |
| zfTimerSchedule(dev, ZM_EVENT_SCAN, wd->sta.scanMgr.scanStartDelay); |
| wd->sta.scanMgr.scanStartDelay = 3; |
| //wd->sta.scanMgr.scanStartDelay = 0; |
| wd->sta.scanMgr.currScanType = scanType; |
| zmw_leave_critical_section(dev); |
| |
| if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) |
| { |
| zfSendNullData(dev, 1); |
| } |
| return 0; |
| } |
| |
| void zfScanMgrScanStop(zdev_t* dev, u8_t scanType) |
| { |
| u8_t scanNotifyRequired = 0; |
| u8_t theOtherScan = ZM_SCAN_MGR_SCAN_NONE; |
| |
| zmw_get_wlan_dev(dev); |
| |
| zmw_declare_for_critical_section(); |
| |
| zmw_enter_critical_section(dev); |
| |
| if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_NONE ) |
| { |
| zm_assert(wd->sta.scanMgr.scanReqs[0] == 0); |
| zm_assert(wd->sta.scanMgr.scanReqs[1] == 0); |
| goto done; |
| } |
| |
| switch(scanType) |
| { |
| case ZM_SCAN_MGR_SCAN_EXTERNAL: |
| scanNotifyRequired = 1; |
| theOtherScan = ZM_SCAN_MGR_SCAN_INTERNAL; |
| break; |
| |
| case ZM_SCAN_MGR_SCAN_INTERNAL: |
| theOtherScan = ZM_SCAN_MGR_SCAN_EXTERNAL; |
| break; |
| |
| default: |
| goto done; |
| } |
| |
| if ( wd->sta.scanMgr.currScanType != scanType ) |
| { |
| goto stop_done; |
| } |
| |
| zfTimerCancel(dev, ZM_EVENT_SCAN); |
| |
| /* Fix for WHQL sendrecv => we do not apply delay time in which the device |
| stop transmitting packet when we already connect to some AP */ |
| wd->sta.bScheduleScan = FALSE; |
| |
| zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); |
| zfTimerCancel(dev, ZM_EVENT_IN_SCAN); |
| |
| wd->sta.bChannelScan = FALSE; |
| wd->sta.scanFrequency = 0; |
| |
| if ( wd->sta.scanMgr.scanReqs[theOtherScan - 1] ) |
| { |
| wd->sta.scanMgr.currScanType = theOtherScan; |
| |
| // Schedule the other scan after 1 second later |
| zfTimerSchedule(dev, ZM_EVENT_SCAN, 100); |
| } |
| else |
| { |
| wd->sta.scanMgr.currScanType = ZM_SCAN_MGR_SCAN_NONE; |
| } |
| |
| stop_done: |
| wd->sta.scanMgr.scanReqs[scanType - 1] = 0; |
| |
| zmw_leave_critical_section(dev); |
| |
| /* avoid lose receive packet when site survey */ |
| if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) |
| { |
| zfSendNullData(dev, 0); |
| } |
| |
| if ( scanNotifyRequired ) |
| { |
| zm_debug_msg0("Scan notify after reset"); |
| if (wd->zfcbScanNotify != NULL) |
| { |
| wd->zfcbScanNotify(dev, NULL); |
| } |
| } |
| |
| return; |
| |
| done: |
| zmw_leave_critical_section(dev); |
| return; |
| } |
| |
| void zfScanMgrScanAck(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| zmw_declare_for_critical_section(); |
| |
| zmw_enter_critical_section(dev); |
| |
| wd->sta.scanMgr.scanStartDelay = 3; |
| //wd->sta.scanMgr.scanStartDelay = 0; |
| |
| zmw_leave_critical_section(dev); |
| return; |
| } |
| |
| extern void zfStaReconnect(zdev_t* dev); |
| |
| static void zfScanSendProbeRequest(zdev_t* dev) |
| { |
| u8_t k; |
| u16_t dst[3] = { 0xffff, 0xffff, 0xffff }; |
| |
| zmw_get_wlan_dev(dev); |
| |
| /* Increase rxBeaconCount to prevent beacon lost */ |
| if (zfStaIsConnected(dev)) |
| { |
| wd->sta.rxBeaconCount++; |
| } |
| |
| if ( wd->sta.bPassiveScan ) |
| { |
| return; |
| } |
| /* enable 802.l11h and in DFS Band , disable sending probe request */ |
| if (wd->sta.DFSEnable) |
| { |
| if (zfHpIsDfsChannel(dev, wd->sta.scanFrequency)) |
| { |
| return; |
| } |
| } |
| |
| zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBEREQ, dst, 0, 0, 0); |
| |
| if ( wd->sta.disableProbingWithSsid ) |
| { |
| return; |
| } |
| |
| for (k=1; k<=ZM_MAX_PROBE_HIDDEN_SSID_SIZE; k++) |
| { |
| if ( wd->ws.probingSsidList[k-1].ssidLen != 0 ) |
| { |
| zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBEREQ, dst, k, 0, 0); |
| } |
| } |
| } |
| |
| static void zfScanMgrEventSetFreqCompleteCb(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| zmw_declare_for_critical_section(); |
| |
| //printk("zfScanMgrEventSetFreqCompleteCb #1\n"); |
| |
| zmw_enter_critical_section(dev); |
| zfTimerSchedule(dev, ZM_EVENT_IN_SCAN, ZM_TICK_IN_SCAN); |
| if (wd->sta.bPassiveScan) |
| { |
| zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_SCAN, wd->sta.passiveScanTickPerChannel); |
| } |
| else |
| { |
| zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_SCAN, wd->sta.activescanTickPerChannel); |
| } |
| zmw_leave_critical_section(dev); |
| |
| zfScanSendProbeRequest(dev); |
| } |
| |
| |
| static void zfScanMgrEventScanCompleteCb(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) |
| { |
| zfSendNullData(dev, 0); |
| } |
| return; |
| } |
| |
| |
| void zfScanMgrScanEventRetry(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| if ( !wd->sta.bChannelScan ) |
| { |
| return; |
| } |
| |
| if ( !wd->sta.bPassiveScan ) |
| { |
| zfScanSendProbeRequest(dev); |
| #if 0 |
| zmw_enter_critical_section(dev); |
| zfTimerSchedule(dev, ZM_EVENT_IN_SCAN, ZM_TICK_IN_SCAN); |
| zmw_leave_critical_section(dev); |
| #endif |
| } |
| } |
| |
| u8_t zfScanMgrScanEventTimeout(zdev_t* dev) |
| { |
| u16_t nextScanFrequency = 0; |
| u8_t temp; |
| |
| zmw_get_wlan_dev(dev); |
| |
| zmw_declare_for_critical_section(); |
| |
| zmw_enter_critical_section(dev); |
| if ( wd->sta.scanFrequency == 0 ) |
| { |
| zmw_leave_critical_section(dev); |
| return -1; |
| } |
| |
| nextScanFrequency = zfChGetNextChannel(dev, wd->sta.scanFrequency, |
| &wd->sta.bPassiveScan); |
| |
| if ( (nextScanFrequency == 0xffff) |
| || (wd->sta.scanFrequency == zfChGetLastChannel(dev, &temp)) ) |
| { |
| u8_t currScanType; |
| u8_t isExternalScan = 0; |
| u8_t isInternalScan = 0; |
| |
| //zm_debug_msg1("end scan = ", KeQueryInterruptTime()); |
| wd->sta.scanFrequency = 0; |
| |
| zm_debug_msg1("scan 1 type: ", wd->sta.scanMgr.currScanType); |
| zm_debug_msg1("scan channel count = ", wd->regulationTable.allowChannelCnt); |
| |
| //zfBssInfoRefresh(dev); |
| zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); |
| |
| if ( wd->sta.bChannelScan == FALSE ) |
| { |
| zm_debug_msg0("WOW!! scan is cancelled\n"); |
| zmw_leave_critical_section(dev); |
| goto report_scan_result; |
| } |
| |
| |
| currScanType = wd->sta.scanMgr.currScanType; |
| switch(currScanType) |
| { |
| case ZM_SCAN_MGR_SCAN_EXTERNAL: |
| isExternalScan = 1; |
| |
| if ( wd->sta.scanMgr.scanReqs[ZM_SCAN_MGR_SCAN_INTERNAL - 1] ) |
| { |
| wd->sta.scanMgr.scanReqs[ZM_SCAN_MGR_SCAN_INTERNAL - 1] = 0; |
| isInternalScan = 1; |
| } |
| |
| break; |
| |
| case ZM_SCAN_MGR_SCAN_INTERNAL: |
| isInternalScan = 1; |
| |
| if ( wd->sta.scanMgr.scanReqs[ZM_SCAN_MGR_SCAN_EXTERNAL - 1] ) |
| { |
| // Because the external scan should pre-empts internal scan. |
| // So this shall not be happened!! |
| zm_assert(0); |
| } |
| |
| break; |
| |
| default: |
| zm_assert(0); |
| break; |
| } |
| |
| wd->sta.scanMgr.scanReqs[currScanType - 1] = 0; |
| wd->sta.scanMgr.scanStartDelay = 100; |
| wd->sta.scanMgr.currScanType = ZM_SCAN_MGR_SCAN_NONE; |
| zmw_leave_critical_section(dev); |
| |
| //Set channel according to AP's configuration |
| zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, |
| wd->ExtOffset, zfScanMgrEventScanCompleteCb); |
| |
| wd->sta.bChannelScan = FALSE; |
| |
| #if 1 |
| if (zfStaIsConnected(dev)) |
| { // Finish site survey, reset the variable to detect using wrong frequency ! |
| zfHpFinishSiteSurvey(dev, 1); |
| zmw_enter_critical_section(dev); |
| wd->sta.ibssSiteSurveyStatus = 2; |
| wd->tickIbssReceiveBeacon = 0; |
| wd->sta.ibssReceiveBeaconCount = 0; |
| zmw_leave_critical_section(dev); |
| |
| /* #5 Re-enable RIFS function after the site survey ! */ |
| /* This is because switch band will reset the BB register to initial value */ |
| if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) |
| { |
| zfHpEnableRifs(dev, ((wd->sta.currentFrequency<3000)?1:0), wd->sta.EnableHT, wd->sta.HT2040); |
| } |
| } |
| else |
| { |
| zfHpFinishSiteSurvey(dev, 0); |
| zmw_enter_critical_section(dev); |
| wd->sta.ibssSiteSurveyStatus = 0; |
| zmw_leave_critical_section(dev); |
| } |
| #endif |
| |
| report_scan_result: |
| /* avoid lose receive packet when site survey */ |
| //if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) |
| //{ |
| // zfSendNullData(dev, 0); |
| //} |
| |
| if ( isExternalScan )//Quickly reboot |
| { |
| if (wd->zfcbScanNotify != NULL) |
| { |
| wd->zfcbScanNotify(dev, NULL); |
| } |
| } |
| |
| if ( isInternalScan ) |
| { |
| //wd->sta.InternalScanReq = 0; |
| zfStaReconnect(dev); |
| } |
| |
| return 0; |
| } |
| else |
| { |
| wd->sta.scanFrequency = nextScanFrequency; |
| |
| //zmw_enter_critical_section(dev); |
| zfTimerCancel(dev, ZM_EVENT_IN_SCAN); |
| zmw_leave_critical_section(dev); |
| |
| zm_debug_msg0("scan 2"); |
| zfCoreSetFrequencyV2(dev, wd->sta.scanFrequency, zfScanMgrEventSetFreqCompleteCb); |
| |
| return 1; |
| } |
| } |
| |
| void zfScanMgrScanEventStart(zdev_t* dev) |
| { |
| zmw_get_wlan_dev(dev); |
| |
| zmw_declare_for_critical_section(); |
| |
| if ( wd->sta.bChannelScan ) |
| { |
| return; |
| } |
| |
| zfPowerSavingMgrWakeup(dev); |
| |
| zmw_enter_critical_section(dev); |
| |
| if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_NONE ) |
| { |
| goto no_scan; |
| } |
| |
| //zfBssInfoRefresh(dev); |
| zfBssInfoRefresh(dev, 0); |
| wd->sta.bChannelScan = TRUE; |
| wd->sta.bScheduleScan = FALSE; |
| zfTimerCancel(dev, ZM_EVENT_IN_SCAN); |
| zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); |
| |
| //zm_debug_msg1("start scan = ", KeQueryInterruptTime()); |
| wd->sta.scanFrequency = zfChGetFirstChannel(dev, &wd->sta.bPassiveScan); |
| zmw_leave_critical_section(dev); |
| |
| /* avoid lose receive packet when site survey */ |
| //if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) |
| //{ |
| // zfSendNullData(dev, 1); |
| //} |
| // zm_debug_msg0("scan 0"); |
| // zfCoreSetFrequencyV2(dev, wd->sta.scanFrequency, zfScanMgrEventSetFreqCompleteCb); |
| |
| #if 1 |
| if (zfStaIsConnected(dev)) |
| {// If doing site survey ! |
| zfHpBeginSiteSurvey(dev, 1); |
| zmw_enter_critical_section(dev); |
| wd->sta.ibssSiteSurveyStatus = 1; |
| zmw_leave_critical_section(dev); |
| } |
| else |
| { |
| zfHpBeginSiteSurvey(dev, 0); |
| zmw_enter_critical_section(dev); |
| wd->sta.ibssSiteSurveyStatus = 0; |
| zmw_leave_critical_section(dev); |
| } |
| #endif |
| |
| zm_debug_msg0("scan 0"); |
| zfCoreSetFrequencyV2(dev, wd->sta.scanFrequency, zfScanMgrEventSetFreqCompleteCb); |
| |
| return; |
| |
| no_scan: |
| zmw_leave_critical_section(dev); |
| return; |
| } |