/**************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * (c) Copyright 2002, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. **************************************************************************** Module Name: mlme.c Abstract: Major MLME state machiones here Revision History: Who When What -------- ---------- ---------------------------------------------- John Chang 08-04-2003 created for 11g soft-AP */ #include "rt_config.h" #include #ifdef DOT11_N_SUPPORT int DetectOverlappingPeriodicRound; #ifdef DOT11N_DRAFT3 VOID Bss2040CoexistTimeOut( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3) { int apidx; PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; DBGPRINT(RT_DEBUG_TRACE, ("Bss2040CoexistTimeOut(): Recovery to original setting!\n")); /* Recovery to original setting when next DTIM Interval. */ pAd->CommonCfg.Bss2040CoexistFlag &= (~BSS_2040_COEXIST_TIMER_FIRED); NdisZeroMemory(&pAd->CommonCfg.LastBSSCoexist2040, sizeof(BSS_2040_COEXIST_IE)); pAd->CommonCfg.Bss2040CoexistFlag |= BSS_2040_COEXIST_INFO_SYNC; if (pAd->CommonCfg.bBssCoexEnable == FALSE) { /* TODO: Find a better way to handle this when the timer is fired and we disable the bBssCoexEable support!! */ DBGPRINT(RT_DEBUG_TRACE, ("Bss2040CoexistTimeOut(): bBssCoexEnable is FALSE, return directly!\n")); return; } for (apidx = 0; apidx < pAd->ApCfg.BssidNum; apidx++) SendBSS2040CoexistMgmtAction(pAd, MCAST_WCID, apidx, 0); } #endif /* DOT11N_DRAFT3 */ #endif /* DOT11_N_SUPPORT */ VOID APDetectOverlappingExec( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3) { #ifdef DOT11_N_SUPPORT PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; if (DetectOverlappingPeriodicRound == 0) { /* switch back 20/40 */ if ((pAd->CommonCfg.Channel <=14) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40)) { pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 1; pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; } } else { if ((DetectOverlappingPeriodicRound == 25) || (DetectOverlappingPeriodicRound == 1)) { if ((pAd->CommonCfg.Channel <=14) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth==BW_40)) { SendBeaconRequest(pAd, 1); SendBeaconRequest(pAd, 2); SendBeaconRequest(pAd, 3); } } DetectOverlappingPeriodicRound--; } #endif /* DOT11_N_SUPPORT */ } /* ========================================================================== Description: This routine is executed every second - 1. Decide the overall channel quality 2. Check if need to upgrade the TX rate to any client 3. perform MAC table maintenance, including ageout no-traffic clients, and release packet buffer in PSQ is fail to TX in time. ========================================================================== */ VOID APMlmePeriodicExec( PRTMP_ADAPTER pAd) { /* Reqeust by David 2005/05/12 It make sense to disable Adjust Tx Power on AP mode, since we can't take care all of the client's situation ToDo: need to verify compatibility issue with WiFi product. */ #ifdef CARRIER_DETECTION_SUPPORT if (isCarrierDetectExist(pAd) == TRUE) { PCARRIER_DETECTION_STRUCT pCarrierDetect = &pAd->CommonCfg.CarrierDetect; if (pCarrierDetect->OneSecIntCount < pCarrierDetect->CarrierGoneThreshold) { pCarrierDetect->CD_State = CD_NORMAL; pCarrierDetect->recheck = pCarrierDetect->recheck1; if (pCarrierDetect->Debug != RT_DEBUG_TRACE) { DBGPRINT(RT_DEBUG_TRACE, ("Carrier gone\n")); /* start all TX actions. */ APMakeAllBssBeacon(pAd); APUpdateAllBeaconFrame(pAd); AsicEnableBssSync(pAd); } else { printk("Carrier gone\n"); } } pCarrierDetect->OneSecIntCount = 0; } #endif /* CARRIER_DETECTION_SUPPORT */ RTMP_CHIP_HIGH_POWER_TUNING(pAd, &pAd->ApCfg.RssiSample); /* Disable Adjust Tx Power for WPA WiFi-test. */ /* Because high TX power results in the abnormal disconnection of Intel BG-STA. */ /*#ifndef WIFI_TEST */ /* if (pAd->CommonCfg.bWiFiTest == FALSE) */ /* for SmartBit 64-byte stream test */ /* removed based on the decision of Ralink congress at 2011/7/06 */ /* if (pAd->MacTab.Size > 0) */ AsicAdjustTxPower(pAd); /*#endif // WIFI_TEST */ RTMP_CHIP_ASIC_TEMPERATURE_COMPENSATION(pAd); /* BBP TUNING: dynamic tune BBP R66 to find a balance between sensibility and noise isolation */ /* AsicBbpTuning2(pAd); */ /* walk through MAC table, see if switching TX rate is required */ /* MAC table maintenance */ if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE == 0) { /* one second timer */ MacTableMaintenance(pAd); RTMPMaintainPMKIDCache(pAd); #ifdef WDS_SUPPORT WdsTableMaintenance(pAd); #endif /* WDS_SUPPORT */ #ifdef CLIENT_WDS CliWds_ProxyTabMaintain(pAd); #endif /* CLIENT_WDS */ } APUpdateCapabilityAndErpIe(pAd); #ifdef APCLI_SUPPORT if (pAd->Mlme.OneSecPeriodicRound % 2 == 0) ApCliIfMonitor(pAd); if (pAd->Mlme.OneSecPeriodicRound % 2 == 1) ApCliIfUp(pAd); { INT loop; ULONG Now32; NdisGetSystemUpTime(&Now32); for (loop = 0; loop < MAX_APCLI_NUM; loop++) { PAPCLI_STRUCT pApCliEntry = &pAd->ApCfg.ApCliTab[loop]; if ((pApCliEntry->Valid == TRUE) && (pApCliEntry->MacTabWCID < MAX_LEN_OF_MAC_TABLE)) { /* update channel quality for Roaming and UI LinkQuality display */ MlmeCalculateChannelQuality(pAd, &pAd->MacTab.Content[pApCliEntry->MacTabWCID], Now32); } } } #endif /* APCLI_SUPPORT */ #ifdef DOT11_N_SUPPORT if (pAd->CommonCfg.bHTProtect) { /*APUpdateCapabilityAndErpIe(pAd); */ APUpdateOperationMode(pAd); if (pAd->CommonCfg.IOTestParm.bRTSLongProtOn == FALSE) { AsicUpdateProtect(pAd, (USHORT)pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, pAd->MacTab.fAnyStationNonGF); } } #endif /* DOT11_N_SUPPORT */ #ifdef A_BAND_SUPPORT if ( (pAd->CommonCfg.Channel > 14) && (pAd->CommonCfg.bIEEE80211H == 1) ) { #ifdef DFS_SUPPORT ApRadarDetectPeriodic(pAd); #else pAd->Dot11_H.InServiceMonitorCount++; if (pAd->Dot11_H.RDMode == RD_SILENCE_MODE) { if (pAd->Dot11_H.RDCount++ > pAd->Dot11_H.ChMovingTime) { AsicEnableBssSync(pAd); pAd->Dot11_H.RDMode = RD_NORMAL_MODE; } } #endif /* !DFS_SUPPORT */ } #endif /* A_BAND_SUPPORT */ } /*! \brief To substitute the message type if the message is coming from external * \param *Fr The frame received * \param *Machine The state machine * \param *MsgType the message type for the state machine * \return TRUE if the substitution is successful, FALSE otherwise * \pre * \post */ BOOLEAN APMsgTypeSubst( IN PRTMP_ADAPTER pAd, IN PFRAME_802_11 pFrame, OUT INT *Machine, OUT INT *MsgType) { USHORT Seq; UCHAR EAPType; BOOLEAN Return = FALSE; #ifdef WSC_AP_SUPPORT UCHAR EAPCode; PMAC_TABLE_ENTRY pEntry; #endif /* WSC_AP_SUPPORT */ /* TODO: only PROBE_REQ can be broadcast, all others must be unicast-to-me && is_mybssid; otherwise, ignore this frame */ /* wpa EAPOL PACKET */ if (pFrame->Hdr.FC.Type == BTYPE_DATA) { #ifdef WSC_AP_SUPPORT /*WSC EAPOL PACKET */ pEntry = MacTableLookup(pAd, pFrame->Hdr.Addr2); if (pEntry && ((pEntry->bWscCapable) || (pAd->ApCfg.MBSSID[pEntry->apidx].AuthMode < Ndis802_11AuthModeWPA))) { if ((MAC_ADDR_EQUAL(pAd->ApCfg.MBSSID[pEntry->apidx].WscControl.EntryAddr, pEntry->Addr) || MAC_ADDR_EQUAL(pAd->ApCfg.MBSSID[pEntry->apidx].WscControl.EntryAddr, ZERO_MAC_ADDR)) && IS_ENTRY_CLIENT(pEntry) && (pAd->ApCfg.MBSSID[pEntry->apidx].WscControl.WscConfMode != WSC_DISABLE)) { *Machine = WSC_STATE_MACHINE; EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); EAPCode = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 4); Return = WscMsgTypeSubst(EAPType, EAPCode, MsgType); } } #endif /* WSC_AP_SUPPORT */ if (!Return) { *Machine = WPA_STATE_MACHINE; EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); Return = WpaMsgTypeSubst(EAPType, (INT *) MsgType); } return Return; } if (pFrame->Hdr.FC.Type != BTYPE_MGMT) return FALSE; switch (pFrame->Hdr.FC.SubType) { case SUBTYPE_ASSOC_REQ: *Machine = AP_ASSOC_STATE_MACHINE; *MsgType = APMT2_PEER_ASSOC_REQ; break; /* case SUBTYPE_ASSOC_RSP: *Machine = AP_ASSOC_STATE_MACHINE; *MsgType = APMT2_PEER_ASSOC_RSP; break; */ case SUBTYPE_REASSOC_REQ: *Machine = AP_ASSOC_STATE_MACHINE; *MsgType = APMT2_PEER_REASSOC_REQ; break; /* case SUBTYPE_REASSOC_RSP: *Machine = AP_ASSOC_STATE_MACHINE; *MsgType = APMT2_PEER_REASSOC_RSP; break; */ case SUBTYPE_PROBE_REQ: *Machine = AP_SYNC_STATE_MACHINE; *MsgType = APMT2_PEER_PROBE_REQ; break; /* test for 40Mhz intolerant */ /* For Active Scan */ case SUBTYPE_PROBE_RSP: *Machine = AP_SYNC_STATE_MACHINE; *MsgType = APMT2_PEER_PROBE_RSP; break; case SUBTYPE_BEACON: *Machine = AP_SYNC_STATE_MACHINE; *MsgType = APMT2_PEER_BEACON; break; /* case SUBTYPE_ATIM: *Machine = AP_SYNC_STATE_MACHINE; *MsgType = APMT2_PEER_ATIM; break; */ case SUBTYPE_DISASSOC: *Machine = AP_ASSOC_STATE_MACHINE; *MsgType = APMT2_PEER_DISASSOC_REQ; break; case SUBTYPE_AUTH: /* get the sequence number from payload 24 Mac Header + 2 bytes algorithm */ NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); *Machine = AP_AUTH_STATE_MACHINE; if (Seq == 1) *MsgType = APMT2_PEER_AUTH_REQ; else if (Seq == 3) *MsgType = APMT2_PEER_AUTH_CONFIRM; else { DBGPRINT(RT_DEBUG_TRACE,("wrong AUTH seq=%d Octet=%02x %02x %02x %02x %02x %02x %02x %02x\n", Seq, pFrame->Octet[0], pFrame->Octet[1], pFrame->Octet[2], pFrame->Octet[3], pFrame->Octet[4], pFrame->Octet[5], pFrame->Octet[6], pFrame->Octet[7])); return FALSE; } break; case SUBTYPE_DEAUTH: *Machine = AP_AUTH_STATE_MACHINE; /*AP_AUTH_RSP_STATE_MACHINE;*/ *MsgType = APMT2_PEER_DEAUTH; break; case SUBTYPE_ACTION: case SUBTYPE_ACTION_NO_ACK: *Machine = ACTION_STATE_MACHINE; /* Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support */ if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) { *MsgType = MT2_ACT_INVALID; } else { *MsgType = (pFrame->Octet[0]&0x7F); } break; default: return FALSE; break; } return TRUE; } /* ======================================================================== Routine Description: Periodic evaluate antenna link status Arguments: pAd - Adapter pointer Return Value: None ======================================================================== */ VOID APAsicEvaluateRxAnt( IN PRTMP_ADAPTER pAd) { ULONG TxTotalCnt; #ifdef RALINK_ATE if (ATE_ON(pAd)) return; #endif /* RALINK_ATE */ #ifdef CARRIER_DETECTION_SUPPORT if(pAd->CommonCfg.CarrierDetect.CD_State == CD_SILENCE) return; #endif /* CARRIER_DETECTION_SUPPORT */ #ifdef RT8592 // TODO: shiang-6590, for 8592, this EvaaluateRxAnt still need?? if (IS_RT8592(pAd)) return; #endif /* RT8592 */ #ifdef RT65xx //snowpin test if (IS_RT6590(pAd)) return; #endif /* RT65xx */ #ifdef MT7601 if ( IS_MT7601(pAd) ) return; #endif /* MT7601 */ #ifdef TXBF_SUPPORT /* TODO: we didn't do RxAnt evaluate for 3x3 chips */ if (IS_RT3883(pAd) || IS_RT2883(pAd)) return; #endif /* TXBF_SUPPORT */ #ifdef DOT11_N_SUPPORT #ifdef GREENAP_SUPPORT if (pAd->ApCfg.bGreenAPActive == TRUE) rtmp_bbp_set_rxpath(pAd, 1); else #endif /* GREENAP_SUPPORT */ #endif /* DOT11_N_SUPPORT */ rtmp_bbp_set_rxpath(pAd, pAd->Antenna.field.RxPath); TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount + pAd->RalinkCounters.OneSecTxFailCount; if (TxTotalCnt > 50) { RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); pAd->Mlme.bLowThroughput = FALSE; } else { RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); pAd->Mlme.bLowThroughput = TRUE; } } /* ======================================================================== Routine Description: After evaluation, check antenna link status Arguments: pAd - Adapter pointer Return Value: None ======================================================================== */ VOID APAsicRxAntEvalTimeout( PRTMP_ADAPTER pAd) { CHAR larger = -127, rssi0, rssi1, rssi2; #ifdef RALINK_ATE if (ATE_ON(pAd)) return; #endif /* RALINK_ATE */ /* if the traffic is low, use average rssi as the criteria */ if (pAd->Mlme.bLowThroughput == TRUE) { rssi0 = pAd->ApCfg.RssiSample.LastRssi0; rssi1 = pAd->ApCfg.RssiSample.LastRssi1; rssi2 = pAd->ApCfg.RssiSample.LastRssi2; } else { rssi0 = pAd->ApCfg.RssiSample.AvgRssi0; rssi1 = pAd->ApCfg.RssiSample.AvgRssi1; rssi2 = pAd->ApCfg.RssiSample.AvgRssi2; } if(pAd->Antenna.field.RxPath == 3) { larger = max(rssi0, rssi1); #ifdef DOT11N_SS3_SUPPORT if (pAd->CommonCfg.RxStream >= 3) pAd->Mlme.RealRxPath = 3; else #endif /* DOT11N_SS3_SUPPORT */ { if (larger > (rssi2 + 20)) pAd->Mlme.RealRxPath = 2; else pAd->Mlme.RealRxPath = 3; } } /* Disable the below to fix 1T/2R issue. It's suggested by Rory at 2007/7/11. */ #ifdef DOT11_N_SUPPORT #ifdef GREENAP_SUPPORT if (pAd->ApCfg.bGreenAPActive == TRUE) rtmp_bbp_set_rxpath(pAd, 1); else #endif /* GREENAP_SUPPORT */ #endif /* DOT11_N_SUPPORT */ rtmp_bbp_set_rxpath(pAd, pAd->Mlme.RealRxPath); } /* ======================================================================== Routine Description: After evaluation, check antenna link status Arguments: pAd - Adapter pointer Return Value: None ======================================================================== */ VOID APAsicAntennaAvg( IN PRTMP_ADAPTER pAd, IN UCHAR AntSelect, IN SHORT* RssiAvg) { SHORT realavgrssi; LONG realavgrssi1; ULONG recvPktNum = pAd->RxAnt.RcvPktNum[AntSelect]; realavgrssi1 = pAd->RxAnt.Pair1AvgRssiGroup1[AntSelect]; if(realavgrssi1 == 0) { *RssiAvg = 0; return; } realavgrssi = (SHORT) (realavgrssi1 / recvPktNum); pAd->RxAnt.Pair1AvgRssiGroup1[0] = 0; pAd->RxAnt.Pair1AvgRssiGroup1[1] = 0; pAd->RxAnt.Pair1AvgRssiGroup2[0] = 0; pAd->RxAnt.Pair1AvgRssiGroup2[1] = 0; pAd->RxAnt.RcvPktNum[0] = 0; pAd->RxAnt.RcvPktNum[1] = 0; *RssiAvg = realavgrssi - 256; }