/* * 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) { 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; }