blob: b32835c87590cf99aaea62c2f19ade03ad5425a3 [file] [log] [blame]
/*
* 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;
}