/* * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * File: wcmd.c * * Purpose: Handles the management command interface functions * * Author: Lyndon Chen * * Date: May 8, 2003 * * Functions: * s_vProbeChannel - Active scan channel * s_MgrMakeProbeRequest - Make ProbeRequest packet * CommandTimer - Timer function to handle command * s_bCommandComplete - Command Complete function * bScheduleCommand - Push Command and wait Command Scheduler to do * vCommandTimer- Command call back functions * vCommandTimerWait- Call back timer * bClearBSSID_SCAN- Clear BSSID_SCAN cmd in CMD Queue * * Revision History: * */ #include "ttype.h" #include "tmacro.h" #include "device.h" #include "mac.h" #include "card.h" #include "80211hdr.h" #include "wcmd.h" #include "wmgr.h" #include "power.h" #include "wctl.h" #include "baseband.h" #include "rxtx.h" #include "rf.h" #include "iowpa.h" #include "channel.h" /*--------------------- Static Definitions -------------------------*/ /*--------------------- Static Classes ----------------------------*/ /*--------------------- Static Variables --------------------------*/ static int msglevel = MSG_LEVEL_INFO; //static int msglevel =MSG_LEVEL_DEBUG; /*--------------------- Static Functions --------------------------*/ static void s_vProbeChannel( PSDevice pDevice ); static PSTxMgmtPacket s_MgrMakeProbeRequest( PSDevice pDevice, PSMgmtObject pMgmt, unsigned char *pScanBSSID, PWLAN_IE_SSID pSSID, PWLAN_IE_SUPP_RATES pCurrRates, PWLAN_IE_SUPP_RATES pCurrExtSuppRates ); static bool s_bCommandComplete( PSDevice pDevice ); /*--------------------- Export Variables --------------------------*/ /*--------------------- Export Functions --------------------------*/ /* * Description: * Stop AdHoc beacon during scan process * * Parameters: * In: * pDevice - Pointer to the adapter * Out: * none * * Return Value: none * */ static void vAdHocBeaconStop(PSDevice pDevice) { PSMgmtObject pMgmt = &(pDevice->sMgmtObj); bool bStop; /* * temporarily stop Beacon packet for AdHoc Server * if all of the following conditions are met: * (1) STA is in AdHoc mode * (2) VT3253 is programmed as automatic Beacon Transmitting * (3) One of the following conditions is met * (3.1) AdHoc channel is in B/G band and the * current scan channel is in A band * or * (3.2) AdHoc channel is in A mode */ bStop = false; if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState >= WMAC_STATE_STARTED)) { if ((pMgmt->uIBSSChannel <= CB_MAX_CHANNEL_24G) && (pMgmt->uScanChannel > CB_MAX_CHANNEL_24G)) { bStop = true; } if (pMgmt->uIBSSChannel > CB_MAX_CHANNEL_24G) { bStop = true; } } if (bStop) { MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); } } /* vAdHocBeaconStop */ /* * Description: * Restart AdHoc beacon after scan process complete * * Parameters: * In: * pDevice - Pointer to the adapter * Out: * none * * Return Value: none * */ static void vAdHocBeaconRestart(PSDevice pDevice) { PSMgmtObject pMgmt = &(pDevice->sMgmtObj); /* * Restart Beacon packet for AdHoc Server * if all of the following coditions are met: * (1) STA is in AdHoc mode * (2) VT3253 is programmed as automatic Beacon Transmitting */ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState >= WMAC_STATE_STARTED)) { MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); } } /*+ * * Routine Description: * Prepare and send probe request management frames. * * * Return Value: * none. * -*/ static void s_vProbeChannel( PSDevice pDevice ) { //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C}; unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60}; //6M, 9M, 12M, 48M unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C}; unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16}; unsigned char *pbyRate; PSTxMgmtPacket pTxPacket; PSMgmtObject pMgmt = pDevice->pMgmt; unsigned int ii; if (pDevice->eCurrentPHYType == PHY_TYPE_11A) { pbyRate = &abyCurrSuppRatesA[0]; } else if (pDevice->eCurrentPHYType == PHY_TYPE_11B) { pbyRate = &abyCurrSuppRatesB[0]; } else { pbyRate = &abyCurrSuppRatesG[0]; } // build an assocreq frame and send it pTxPacket = s_MgrMakeProbeRequest ( pDevice, pMgmt, pMgmt->abyScanBSSID, (PWLAN_IE_SSID)pMgmt->abyScanSSID, (PWLAN_IE_SUPP_RATES)pbyRate, (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRatesG ); if (pTxPacket != NULL) { for (ii = 0; ii < 2; ii++) { if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request sending fail.. \n"); } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request is sending.. \n"); } } } } /*+ * * Routine Description: * Constructs an probe request frame * * * Return Value: * A ptr to Tx frame or NULL on allocation failue * -*/ PSTxMgmtPacket s_MgrMakeProbeRequest( PSDevice pDevice, PSMgmtObject pMgmt, unsigned char *pScanBSSID, PWLAN_IE_SSID pSSID, PWLAN_IE_SUPP_RATES pCurrRates, PWLAN_IE_SUPP_RATES pCurrExtSuppRates ) { PSTxMgmtPacket pTxPacket = NULL; WLAN_FR_PROBEREQ sFrame; pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool; memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBEREQ_FR_MAXLEN); pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket)); sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header; sFrame.len = WLAN_PROBEREQ_FR_MAXLEN; vMgrEncodeProbeRequest(&sFrame); sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16( ( WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) | WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBEREQ) )); memcpy(sFrame.pHdr->sA3.abyAddr1, pScanBSSID, WLAN_ADDR_LEN); memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); memcpy(sFrame.pHdr->sA3.abyAddr3, pScanBSSID, WLAN_BSSID_LEN); // Copy the SSID, pSSID->len=0 indicate broadcast SSID sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len); sFrame.len += pSSID->len + WLAN_IEHDR_LEN; memcpy(sFrame.pSSID, pSSID, pSSID->len + WLAN_IEHDR_LEN); sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN; memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN); // Copy the extension rate set if (pDevice->eCurrentPHYType == PHY_TYPE_11G) { sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len); sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN; memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN); } pTxPacket->cbMPDULen = sFrame.len; pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN; return pTxPacket; } void vCommandTimerWait( void *hDeviceContext, unsigned int MSecond ) { PSDevice pDevice = (PSDevice)hDeviceContext; init_timer(&pDevice->sTimerCommand); pDevice->sTimerCommand.data = (unsigned long) pDevice; pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer; // RUN_AT :1 msec ~= (HZ/1024) pDevice->sTimerCommand.expires = (unsigned int)RUN_AT((MSecond * HZ) >> 10); add_timer(&pDevice->sTimerCommand); return; } void vCommandTimer( void *hDeviceContext ) { PSDevice pDevice = (PSDevice)hDeviceContext; PSMgmtObject pMgmt = pDevice->pMgmt; PWLAN_IE_SSID pItemSSID; PWLAN_IE_SSID pItemSSIDCurr; CMD_STATUS Status; unsigned int ii; unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}; struct sk_buff *skb; if (pDevice->dwDiagRefCount != 0) return; if (pDevice->bCmdRunning != true) return; spin_lock_irq(&pDevice->lock); switch (pDevice->eCommandState) { case WLAN_CMD_SCAN_START: pDevice->byReAssocCount = 0; if (pDevice->bRadioOff == true) { s_bCommandComplete(pDevice); spin_unlock_irq(&pDevice->lock); return; } if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { s_bCommandComplete(pDevice); CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP); spin_unlock_irq(&pDevice->lock); return; } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState= WLAN_CMD_SCAN_START\n"); pItemSSID = (PWLAN_IE_SSID)pMgmt->abyScanSSID; // wait all Data TD complete if (pDevice->iTDUsed[TYPE_AC0DMA] != 0) { spin_unlock_irq(&pDevice->lock); vCommandTimerWait((void *)pDevice, 10); return; } if (pMgmt->uScanChannel == 0) { pMgmt->uScanChannel = pDevice->byMinChannel; // Set Baseband to be more sensitive. } if (pMgmt->uScanChannel > pDevice->byMaxChannel) { pMgmt->eScanState = WMAC_NO_SCANNING; // Set Baseband's sensitivity back. // Set channel back set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel); if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC); } else { CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE); } vAdHocBeaconRestart(pDevice); s_bCommandComplete(pDevice); } else { //2008-8-4 by chester if (!is_channel_valid(pMgmt->uScanChannel)) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d \n", pMgmt->uScanChannel); s_bCommandComplete(pDevice); spin_unlock_irq(&pDevice->lock); return; } if (pMgmt->uScanChannel == pDevice->byMinChannel) { //pMgmt->eScanType = WMAC_SCAN_ACTIVE; pMgmt->abyScanBSSID[0] = 0xFF; pMgmt->abyScanBSSID[1] = 0xFF; pMgmt->abyScanBSSID[2] = 0xFF; pMgmt->abyScanBSSID[3] = 0xFF; pMgmt->abyScanBSSID[4] = 0xFF; pMgmt->abyScanBSSID[5] = 0xFF; pItemSSID->byElementID = WLAN_EID_SSID; // clear bssid list // BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass); pMgmt->eScanState = WMAC_IS_SCANNING; } vAdHocBeaconStop(pDevice); if (set_channel(pMgmt->pAdapter, pMgmt->uScanChannel) == true) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SCAN Channel: %d\n", pMgmt->uScanChannel); } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SET SCAN Channel Fail: %d\n", pMgmt->uScanChannel); } CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_UNKNOWN); pMgmt->uScanChannel++; //2008-8-4 by chester if (!is_channel_valid(pMgmt->uScanChannel) && pMgmt->uScanChannel <= pDevice->byMaxChannel) { pMgmt->uScanChannel = pDevice->byMaxChannel + 1; pMgmt->eCommandState = WLAN_CMD_SCAN_END; } if ((pMgmt->b11hEnable == false) || (pMgmt->uScanChannel < CB_MAX_CHANNEL_24G)) { s_vProbeChannel(pDevice); spin_unlock_irq(&pDevice->lock); vCommandTimerWait((void *)pDevice, WCMD_ACTIVE_SCAN_TIME); return; } else { spin_unlock_irq(&pDevice->lock); vCommandTimerWait((void *)pDevice, WCMD_PASSIVE_SCAN_TIME); return; } } break; case WLAN_CMD_SCAN_END: // Set Baseband's sensitivity back. // Set channel back set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel); if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC); } else { CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE); } pMgmt->eScanState = WMAC_NO_SCANNING; vAdHocBeaconRestart(pDevice); //2008-0409-07, by Einsn Liu #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT if (pMgmt->eScanType == WMAC_SCAN_PASSIVE) {//send scan event to wpa_Supplicant union iwreq_data wrqu; memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL); } #endif s_bCommandComplete(pDevice); break; case WLAN_CMD_DISASSOCIATE_START: pDevice->byReAssocCount = 0; if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState != WMAC_STATE_ASSOC)) { s_bCommandComplete(pDevice); spin_unlock_irq(&pDevice->lock); return; } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Disassociation Packet..\n"); // reason = 8 : disassoc because sta has left vMgrDisassocBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (8), &Status); pDevice->bLinkPass = false; // unlock command busy pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; pItemSSID->len = 0; memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN); pMgmt->eCurrState = WMAC_STATE_IDLE; pMgmt->sNodeDBTable[0].bActive = false; // pDevice->bBeaconBufReady = false; } netif_stop_queue(pDevice->dev); pDevice->eCommandState = WLAN_DISASSOCIATE_WAIT; // wait all Control TD complete if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) { vCommandTimerWait((void *)pDevice, 10); spin_unlock_irq(&pDevice->lock); return; } DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " CARDbRadioPowerOff\n"); //2008-09-02 by chester // CARDbRadioPowerOff(pDevice); s_bCommandComplete(pDevice); break; case WLAN_DISASSOCIATE_WAIT: // wait all Control TD complete if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) { vCommandTimerWait((void *)pDevice, 10); spin_unlock_irq(&pDevice->lock); return; } //2008-09-02 by chester // CARDbRadioPowerOff(pDevice); s_bCommandComplete(pDevice); break; case WLAN_CMD_SSID_START: pDevice->byReAssocCount = 0; if (pDevice->bRadioOff == true) { s_bCommandComplete(pDevice); spin_unlock_irq(&pDevice->lock); return; } printk("chester-abyDesireSSID=%s\n", ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID); //memcpy(pMgmt->abyAdHocSSID,pMgmt->abyDesireSSID, //((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN); pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; pItemSSIDCurr = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " cmd: desire ssid = %s\n", pItemSSID->abySSID); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " cmd: curr ssid = %s\n", pItemSSIDCurr->abySSID); if (pMgmt->eCurrState == WMAC_STATE_ASSOC) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Cmd pMgmt->eCurrState == WMAC_STATE_ASSOC\n"); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " pItemSSID->len =%d\n", pItemSSID->len); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " pItemSSIDCurr->len = %d\n", pItemSSIDCurr->len); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " desire ssid = %s\n", pItemSSID->abySSID); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " curr ssid = %s\n", pItemSSIDCurr->abySSID); } if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) || ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) { if (pItemSSID->len == pItemSSIDCurr->len) { if (memcmp(pItemSSID->abySSID, pItemSSIDCurr->abySSID, pItemSSID->len) == 0) { s_bCommandComplete(pDevice); spin_unlock_irq(&pDevice->lock); return; } } netif_stop_queue(pDevice->dev); pDevice->bLinkPass = false; } // set initial state pMgmt->eCurrState = WMAC_STATE_IDLE; pMgmt->eCurrMode = WMAC_MODE_STANDBY; PSvDisablePowerSaving((void *)pDevice); BSSvClearNodeDBTable(pDevice, 0); vMgrJoinBSSBegin((void *)pDevice, &Status); // if Infra mode if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) { // Call mgr to begin the deauthentication // reason = (3) because sta has left ESS if (pMgmt->eCurrState >= WMAC_STATE_AUTH) { vMgrDeAuthenBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (3), &Status); } // Call mgr to begin the authentication vMgrAuthenBeginSta((void *)pDevice, pMgmt, &Status); if (Status == CMD_STATUS_SUCCESS) { pDevice->byLinkWaitCount = 0; pDevice->eCommandState = WLAN_AUTHENTICATE_WAIT; vCommandTimerWait((void *)pDevice, AUTHENTICATE_TIMEOUT); spin_unlock_irq(&pDevice->lock); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set eCommandState = WLAN_AUTHENTICATE_WAIT\n"); return; } } // if Adhoc mode else if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) { if (pMgmt->eCurrState == WMAC_STATE_JOINTED) { if (netif_queue_stopped(pDevice->dev)) { netif_wake_queue(pDevice->dev); } pDevice->bLinkPass = true; pMgmt->sNodeDBTable[0].bActive = true; pMgmt->sNodeDBTable[0].uInActiveCount = 0; bClearBSSID_SCAN(pDevice); } else { // start own IBSS vMgrCreateOwnIBSS((void *)pDevice, &Status); if (Status != CMD_STATUS_SUCCESS) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " WLAN_CMD_IBSS_CREATE fail ! \n"); } BSSvAddMulticastNode(pDevice); } } // if SSID not found else if (pMgmt->eCurrMode == WMAC_MODE_STANDBY) { if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA || pMgmt->eConfigMode == WMAC_CONFIG_AUTO) { // start own IBSS vMgrCreateOwnIBSS((void *)pDevice, &Status); if (Status != CMD_STATUS_SUCCESS) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " WLAN_CMD_IBSS_CREATE fail ! \n"); } BSSvAddMulticastNode(pDevice); if (netif_queue_stopped(pDevice->dev)) { netif_wake_queue(pDevice->dev); } pDevice->bLinkPass = true; } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disconnect SSID none\n"); #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT { union iwreq_data wrqu; memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; printk("wireless_send_event--->SIOCGIWAP(disassociated:vMgrJoinBSSBegin Fail !!)\n"); wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL); } #endif } } s_bCommandComplete(pDevice); break; case WLAN_AUTHENTICATE_WAIT: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_AUTHENTICATE_WAIT\n"); if (pMgmt->eCurrState == WMAC_STATE_AUTH) { // Call mgr to begin the association pDevice->byLinkWaitCount = 0; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCurrState == WMAC_STATE_AUTH\n"); vMgrAssocBeginSta((void *)pDevice, pMgmt, &Status); if (Status == CMD_STATUS_SUCCESS) { pDevice->byLinkWaitCount = 0; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState = WLAN_ASSOCIATE_WAIT\n"); pDevice->eCommandState = WLAN_ASSOCIATE_WAIT; vCommandTimerWait((void *)pDevice, ASSOCIATE_TIMEOUT); spin_unlock_irq(&pDevice->lock); return; } } else if (pMgmt->eCurrState < WMAC_STATE_AUTHPENDING) { printk("WLAN_AUTHENTICATE_WAIT:Authen Fail???\n"); } else if (pDevice->byLinkWaitCount <= 4) { //mike add:wait another 2 sec if authenticated_frame delay! pDevice->byLinkWaitCount++; printk("WLAN_AUTHENTICATE_WAIT:wait %d times!!\n", pDevice->byLinkWaitCount); spin_unlock_irq(&pDevice->lock); vCommandTimerWait((void *)pDevice, AUTHENTICATE_TIMEOUT/2); return; } pDevice->byLinkWaitCount = 0; s_bCommandComplete(pDevice); break; case WLAN_ASSOCIATE_WAIT: if (pMgmt->eCurrState == WMAC_STATE_ASSOC) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCurrState == WMAC_STATE_ASSOC\n"); if (pDevice->ePSMode != WMAC_POWER_CAM) { PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval); } if (pMgmt->eAuthenMode >= WMAC_AUTH_WPA) { KeybRemoveAllKey(&(pDevice->sKey), pDevice->abyBSSID, pDevice->PortOffset); } pDevice->bLinkPass = true; pDevice->byLinkWaitCount = 0; pDevice->byReAssocCount = 0; bClearBSSID_SCAN(pDevice); if (pDevice->byFOETuning) { BBvSetFOE(pDevice->PortOffset); PSbSendNullPacket(pDevice); } if (netif_queue_stopped(pDevice->dev)) { netif_wake_queue(pDevice->dev); } #ifdef TxInSleep if (pDevice->IsTxDataTrigger != false) { //TxDataTimer is not triggered at the first time del_timer(&pDevice->sTimerTxData); init_timer(&pDevice->sTimerTxData); pDevice->sTimerTxData.data = (unsigned long) pDevice; pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData; pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback pDevice->fTxDataInSleep = false; pDevice->nTxDataTimeCout = 0; } else { } pDevice->IsTxDataTrigger = true; add_timer(&pDevice->sTimerTxData); #endif } else if (pMgmt->eCurrState < WMAC_STATE_ASSOCPENDING) { printk("WLAN_ASSOCIATE_WAIT:Association Fail???\n"); } else if (pDevice->byLinkWaitCount <= 4) { //mike add:wait another 2 sec if associated_frame delay! pDevice->byLinkWaitCount++; printk("WLAN_ASSOCIATE_WAIT:wait %d times!!\n", pDevice->byLinkWaitCount); spin_unlock_irq(&pDevice->lock); vCommandTimerWait((void *)pDevice, ASSOCIATE_TIMEOUT/2); return; } pDevice->byLinkWaitCount = 0; s_bCommandComplete(pDevice); break; case WLAN_CMD_AP_MODE_START: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_CMD_AP_MODE_START\n"); if (pMgmt->eConfigMode == WMAC_CONFIG_AP) { del_timer(&pMgmt->sTimerSecondCallback); pMgmt->eCurrState = WMAC_STATE_IDLE; pMgmt->eCurrMode = WMAC_MODE_STANDBY; pDevice->bLinkPass = false; if (pDevice->bEnableHostWEP == true) BSSvClearNodeDBTable(pDevice, 1); else BSSvClearNodeDBTable(pDevice, 0); pDevice->uAssocCount = 0; pMgmt->eCurrState = WMAC_STATE_IDLE; pDevice->bFixRate = false; vMgrCreateOwnIBSS((void *)pDevice, &Status); if (Status != CMD_STATUS_SUCCESS) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " vMgrCreateOwnIBSS fail ! \n"); } // alway turn off unicast bit MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_UNICAST); pDevice->byRxMode &= ~RCR_UNICAST; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode); BSSvAddMulticastNode(pDevice); if (netif_queue_stopped(pDevice->dev)) { netif_wake_queue(pDevice->dev); } pDevice->bLinkPass = true; add_timer(&pMgmt->sTimerSecondCallback); } s_bCommandComplete(pDevice); break; case WLAN_CMD_TX_PSPACKET_START: // DTIM Multicast tx if (pMgmt->sNodeDBTable[0].bRxPSPoll) { while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[0].sTxPSQueue)) != NULL) { if (skb_queue_empty(&pMgmt->sNodeDBTable[0].sTxPSQueue)) { pMgmt->abyPSTxMap[0] &= ~byMask[0]; pDevice->bMoreData = false; } else { pDevice->bMoreData = true; } if (!device_dma0_xmit(pDevice, skb, 0)) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Multicast ps tx fail \n"); } pMgmt->sNodeDBTable[0].wEnQueueCnt--; } } // PS nodes tx for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) { if (pMgmt->sNodeDBTable[ii].bActive && pMgmt->sNodeDBTable[ii].bRxPSPoll) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d Enqueu Cnt= %d\n", ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt); while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL) { if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) { // clear tx map pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &= ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7]; pDevice->bMoreData = false; } else { pDevice->bMoreData = true; } if (!device_dma0_xmit(pDevice, skb, ii)) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n"); } pMgmt->sNodeDBTable[ii].wEnQueueCnt--; // check if sta ps enabled, and wait next pspoll. // if sta ps disable, then send all pending buffers. if (pMgmt->sNodeDBTable[ii].bPSEnable) break; } if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) { // clear tx map pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &= ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7]; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d PS queue clear \n", ii); } pMgmt->sNodeDBTable[ii].bRxPSPoll = false; } } s_bCommandComplete(pDevice); break; case WLAN_CMD_RADIO_START: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_CMD_RADIO_START\n"); if (pDevice->bRadioCmd == true) CARDbRadioPowerOn(pDevice); else CARDbRadioPowerOff(pDevice); s_bCommandComplete(pDevice); break; case WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE: //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_CMD_CHECK_BBSENSITIVITY_START\n"); // wait all TD complete if (pDevice->iTDUsed[TYPE_AC0DMA] != 0) { vCommandTimerWait((void *)pDevice, 10); spin_unlock_irq(&pDevice->lock); return; } if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) { vCommandTimerWait((void *)pDevice, 10); spin_unlock_irq(&pDevice->lock); return; } pDevice->byBBVGACurrent = pDevice->byBBVGANew; BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SetVGAGainOffset %02X\n", pDevice->byBBVGACurrent); s_bCommandComplete(pDevice); break; default: s_bCommandComplete(pDevice); break; } //switch spin_unlock_irq(&pDevice->lock); return; } static bool s_bCommandComplete( PSDevice pDevice ) { PWLAN_IE_SSID pSSID; bool bRadioCmd = false; //unsigned short wDeAuthenReason = 0; bool bForceSCAN = true; PSMgmtObject pMgmt = pDevice->pMgmt; pDevice->eCommandState = WLAN_CMD_IDLE; if (pDevice->cbFreeCmdQueue == CMD_Q_SIZE) { //Command Queue Empty pDevice->bCmdRunning = false; return true; } else { pDevice->eCommand = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].eCmd; pSSID = (PWLAN_IE_SSID)pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].abyCmdDesireSSID; bRadioCmd = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bRadioCmd; bForceSCAN = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bForceSCAN; ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdDequeueIdx, CMD_Q_SIZE); pDevice->cbFreeCmdQueue++; pDevice->bCmdRunning = true; switch (pDevice->eCommand) { case WLAN_CMD_BSSID_SCAN: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState= WLAN_CMD_BSSID_SCAN\n"); pDevice->eCommandState = WLAN_CMD_SCAN_START; pMgmt->uScanChannel = 0; if (pSSID->len != 0) { memcpy(pMgmt->abyScanSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); } else { memset(pMgmt->abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); } /* if ((bForceSCAN == false) && (pDevice->bLinkPass == true)) { if ((pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) && (!memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, pSSID->len))) { pDevice->eCommandState = WLAN_CMD_IDLE; } } */ break; case WLAN_CMD_SSID: pDevice->eCommandState = WLAN_CMD_SSID_START; if (pSSID->len > WLAN_SSID_MAXLEN) pSSID->len = WLAN_SSID_MAXLEN; if (pSSID->len != 0) memcpy(pDevice->pMgmt->abyDesireSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState= WLAN_CMD_SSID_START\n"); break; case WLAN_CMD_DISASSOCIATE: pDevice->eCommandState = WLAN_CMD_DISASSOCIATE_START; break; case WLAN_CMD_RX_PSPOLL: pDevice->eCommandState = WLAN_CMD_TX_PSPACKET_START; break; case WLAN_CMD_RUN_AP: pDevice->eCommandState = WLAN_CMD_AP_MODE_START; break; case WLAN_CMD_RADIO: pDevice->eCommandState = WLAN_CMD_RADIO_START; pDevice->bRadioCmd = bRadioCmd; break; case WLAN_CMD_CHANGE_BBSENSITIVITY: pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE; break; default: break; } vCommandTimerWait((void *)pDevice, 0); } return true; } bool bScheduleCommand( void *hDeviceContext, CMD_CODE eCommand, unsigned char *pbyItem0 ) { PSDevice pDevice = (PSDevice)hDeviceContext; if (pDevice->cbFreeCmdQueue == 0) { return false; } pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].eCmd = eCommand; pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = true; memset(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, 0 , WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); if (pbyItem0 != NULL) { switch (eCommand) { case WLAN_CMD_BSSID_SCAN: memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = false; break; case WLAN_CMD_SSID: memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1); break; case WLAN_CMD_DISASSOCIATE: pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bNeedRadioOFF = *((int *)pbyItem0); break; /* case WLAN_CMD_DEAUTH: pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((unsigned short *)pbyItem0); break; */ case WLAN_CMD_RX_PSPOLL: break; case WLAN_CMD_RADIO: pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bRadioCmd = *((int *)pbyItem0); break; case WLAN_CMD_CHANGE_BBSENSITIVITY: pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE; break; default: break; } } ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdEnqueueIdx, CMD_Q_SIZE); pDevice->cbFreeCmdQueue--; if (pDevice->bCmdRunning == false) { s_bCommandComplete(pDevice); } else { } return true; } /* * Description: * Clear BSSID_SCAN cmd in CMD Queue * * Parameters: * In: * hDeviceContext - Pointer to the adapter * eCommand - Command * Out: * none * * Return Value: true if success; otherwise false * */ bool bClearBSSID_SCAN( void *hDeviceContext ) { PSDevice pDevice = (PSDevice)hDeviceContext; unsigned int uCmdDequeueIdx = pDevice->uCmdDequeueIdx; unsigned int ii; if ((pDevice->cbFreeCmdQueue < CMD_Q_SIZE) && (uCmdDequeueIdx != pDevice->uCmdEnqueueIdx)) { for (ii = 0; ii < (CMD_Q_SIZE - pDevice->cbFreeCmdQueue); ii++) { if (pDevice->eCmdQueue[uCmdDequeueIdx].eCmd == WLAN_CMD_BSSID_SCAN) pDevice->eCmdQueue[uCmdDequeueIdx].eCmd = WLAN_CMD_IDLE; ADD_ONE_WITH_WRAP_AROUND(uCmdDequeueIdx, CMD_Q_SIZE); if (uCmdDequeueIdx == pDevice->uCmdEnqueueIdx) break; } } return true; } //mike add:reset command timer void vResetCommandTimer( void *hDeviceContext ) { PSDevice pDevice = (PSDevice)hDeviceContext; //delete timer del_timer(&pDevice->sTimerCommand); //init timer init_timer(&pDevice->sTimerCommand); pDevice->sTimerCommand.data = (unsigned long) pDevice; pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer; pDevice->sTimerCommand.expires = RUN_AT(HZ); pDevice->cbFreeCmdQueue = CMD_Q_SIZE; pDevice->uCmdDequeueIdx = 0; pDevice->uCmdEnqueueIdx = 0; pDevice->eCommandState = WLAN_CMD_IDLE; pDevice->bCmdRunning = false; pDevice->bCmdClear = false; } #ifdef TxInSleep void BSSvSecondTxData( void *hDeviceContext ) { PSDevice pDevice = (PSDevice)hDeviceContext; PSMgmtObject pMgmt = &(pDevice->sMgmtObj); pDevice->nTxDataTimeCout++; if (pDevice->nTxDataTimeCout < 4) //don't tx data if timer less than 40s { pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback add_timer(&pDevice->sTimerTxData); return; } spin_lock_irq(&pDevice->lock); #if 1 if (((pDevice->bLinkPass == true) && (pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking (pDevice->fWPA_Authened == true)) { //wpa linking #else if (pDevice->bLinkPass == true) { #endif pDevice->fTxDataInSleep = true; PSbSendNullPacket(pDevice); //send null packet pDevice->fTxDataInSleep = false; } spin_unlock_irq(&pDevice->lock); pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback add_timer(&pDevice->sTimerTxData); return; } #endif