/* *************************************************************************** * 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: ap_wds.c Abstract: Support WDS function. Revision History: Who When What ------ ---------- ---------------------------------------------- */ #ifdef WDS_SUPPORT #include "rt_config.h" #define VAILD_KEY_INDEX( _X ) ((((_X) >= 0) && ((_X) < 4)) ? (TRUE) : (FALSE)) INT ApWdsAllowToSendPacket( IN RTMP_ADAPTER *pAd, IN struct wifi_dev *wdev, IN PNDIS_PACKET pPacket, OUT UCHAR *pWcid) { UCHAR idx; INT allowed = FALSE; RT_802_11_WDS_ENTRY *wds_entry; if (!wdev) return FALSE; for (idx = 0; idx < MAX_WDS_ENTRY; idx++) { wds_entry = &pAd->WdsTab.WdsEntry[idx]; if (ValidWdsEntry(pAd, idx) && (wdev == (&wds_entry->wdev))) { RTMP_SET_PACKET_WDEV(pPacket, wdev->wdev_idx); *pWcid = (UCHAR)pAd->WdsTab.WdsEntry[idx].MacTabMatchWCID; allowed = TRUE; #ifdef RELEASE_EXCLUDE DBGPRINT(RT_DEBUG_INFO, ("%s():packet to (%d)\n", __FUNCTION__, idx)); #endif /* RELEASE_EXCLUDE */ break; } } return allowed; } INT wds_rx_foward_handle(RTMP_ADAPTER *pAd, struct wifi_dev *wdev, PNDIS_PACKET pPacket) { /* For WDS, direct to OS and no need to forwad the packet to WM */ return TRUE; } INT wds_rx_pkt_allow(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk) { HEADER_802_11 *pHeader = pRxBlk->pHeader; MAC_TABLE_ENTRY *pEntry = NULL; INT hdr_len = 0; /* handle WDS */ if (VALID_WCID(pRxBlk->wcid) && IS_ENTRY_WDS(&pAd->MacTab.Content[pRxBlk->wcid])) { if (MAC_ADDR_EQUAL(pHeader->Addr1, pAd->CurrentAddress)) pEntry = FindWdsEntry(pAd, pRxBlk->wcid, pHeader->Addr2, pRxBlk->rx_rate.field.MODE); else pEntry = NULL; /* have no valid wds entry exist, then discard the incoming packet.*/ if (!(pEntry && WDS_IF_UP_CHECK(pAd, pEntry->func_tb_idx))) return FALSE; /*receive corresponding WDS packet, disable TX lock state (fix WDS jam issue) */ if(pEntry && (pEntry->LockEntryTx == TRUE)) { DBGPRINT(RT_DEBUG_TRACE, ("Receive WDS packet, disable TX lock state!\n")); pEntry->ContinueTxFailCnt = 0; pEntry->LockEntryTx = FALSE; // TODO: shiang-usw, remove upper setting because we need to mirgate to tr_entry! pAd->MacTab.tr_entry[pEntry->wcid].ContinueTxFailCnt = 0; pAd->MacTab.tr_entry[pEntry->wcid].LockEntryTx = FALSE; } RX_BLK_SET_FLAG(pRxBlk, fRX_WDS); hdr_len = LENGTH_802_11_WITH_ADDR4; return hdr_len; } return FALSE; } INT WdsEntryAlloc(RTMP_ADAPTER *pAd, UCHAR *pAddr) { INT i, WdsTabIdx = -1; RT_802_11_WDS_ENTRY *wds_entry; NdisAcquireSpinLock(&pAd->WdsTabLock); for (i = 0; i < MAX_WDS_ENTRY; i++) { if ((pAd->WdsTab.Mode >= WDS_LAZY_MODE) && !WDS_IF_UP_CHECK(pAd, i)) continue; wds_entry = &pAd->WdsTab.WdsEntry[i]; if (wds_entry->Valid == FALSE) { wds_entry->Valid = TRUE; pAd->WdsTab.Size ++; COPY_MAC_ADDR(wds_entry->PeerWdsAddr, pAddr); WdsTabIdx = i; break; } else if (MAC_ADDR_EQUAL(wds_entry->PeerWdsAddr, pAddr)) { WdsTabIdx = i; break; } } NdisReleaseSpinLock(&pAd->WdsTabLock); if (i == MAX_WDS_ENTRY) DBGPRINT(RT_DEBUG_ERROR, ("%s: Unable to allocate WdsEntry.\n", __FUNCTION__)); return WdsTabIdx; } VOID WdsEntryDel(RTMP_ADAPTER *pAd, UCHAR *pAddr) { INT i; RT_802_11_WDS_ENTRY *wds_entry; /* delete one WDS entry */ NdisAcquireSpinLock(&pAd->WdsTabLock); for (i = 0; i < MAX_WDS_ENTRY; i++) { wds_entry = &pAd->WdsTab.WdsEntry[i]; if (MAC_ADDR_EQUAL(pAddr, wds_entry->PeerWdsAddr) && (wds_entry->Valid == TRUE)) { wds_entry->Valid = FALSE; NdisZeroMemory(wds_entry->PeerWdsAddr, MAC_ADDR_LEN); pAd->WdsTab.Size--; break; } } NdisReleaseSpinLock(&pAd->WdsTabLock); } /* ========================================================================== Description: Delete all WDS Entry in pAd->MacTab ========================================================================== */ BOOLEAN MacTableDeleteWDSEntry( IN PRTMP_ADAPTER pAd, IN USHORT wcid, IN PUCHAR pAddr) { if (wcid >= MAX_LEN_OF_MAC_TABLE) return FALSE; else return MacTableDeleteEntry(pAd, wcid, pAddr); } /* ================================================================ Description : because WDS and CLI share the same WCID table in ASIC. WDS entry also insert to pAd->MacTab.content[]. Also fills the pairwise key. Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert WDS from index MAX_AID_BA. ================================================================ */ MAC_TABLE_ENTRY *MacTableInsertWDSEntry( IN RTMP_ADAPTER *pAd, IN UCHAR *pAddr, UINT WdsTabIdx) { MAC_TABLE_ENTRY *pEntry = NULL; STA_TR_ENTRY *tr_entry; HTTRANSMIT_SETTING HTPhyMode; RT_802_11_WDS_ENTRY *wds_entry; struct wifi_dev *wdev; /* if FULL, return */ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) return NULL; if((pEntry = WdsTableLookup(pAd, pAddr, TRUE)) != NULL) return pEntry; wds_entry = &pAd->WdsTab.WdsEntry[WdsTabIdx]; wdev = &wds_entry->wdev; /* allocate one WDS entry */ do { /* allocate one MAC entry */ pEntry = MacTableInsertEntry(pAd, pAddr, wdev, ENTRY_WDS, OPMODE_AP, TRUE); if (pEntry) { tr_entry = &pAd->MacTab.tr_entry[pEntry->wcid]; tr_entry->PortSecured = WPA_802_1X_PORT_SECURED; /* specific Max Tx Rate for Wds link. */ NdisZeroMemory(&HTPhyMode, sizeof(HTTRANSMIT_SETTING)); switch (wdev->PhyMode) { case 0xff: /* user doesn't specific a Mode for WDS link. */ case MODE_OFDM: /* specific OFDM mode. */ HTPhyMode.field.MODE = MODE_OFDM; HTPhyMode.field.MCS = 7; pEntry->RateLen = 8; break; case MODE_CCK: HTPhyMode.field.MODE = MODE_CCK; HTPhyMode.field.MCS = 3; pEntry->RateLen = 4; break; #ifdef DOT11_N_SUPPORT case MODE_HTMIX: HTPhyMode.field.MCS = 7; HTPhyMode.field.ShortGI = wdev->HTPhyMode.field.ShortGI; HTPhyMode.field.BW = wdev->HTPhyMode.field.BW; HTPhyMode.field.STBC = wdev->HTPhyMode.field.STBC; HTPhyMode.field.MODE = MODE_HTMIX; pEntry->RateLen = 12; break; case MODE_HTGREENFIELD: HTPhyMode.field.MCS = 7; HTPhyMode.field.ShortGI = wdev->HTPhyMode.field.ShortGI; HTPhyMode.field.BW = wdev->HTPhyMode.field.BW; HTPhyMode.field.STBC = wdev->HTPhyMode.field.STBC; HTPhyMode.field.MODE = MODE_HTGREENFIELD; pEntry->RateLen = 12; break; #endif /* DOT11_N_SUPPORT */ default: break; } pEntry->MaxHTPhyMode.word = HTPhyMode.word; pEntry->MinHTPhyMode.word = wdev->MinHTPhyMode.word; pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; #ifdef DOT11_N_SUPPORT if (wdev->PhyMode >= MODE_HTMIX) { if (wdev->DesiredTransmitSetting.field.MCS != MCS_AUTO) { DBGPRINT(RT_DEBUG_TRACE, ("IF-wds%d : Desired MCS = %d\n", WdsTabIdx, wdev->DesiredTransmitSetting.field.MCS)); set_ht_fixed_mcs(pAd, pEntry, wdev->DesiredTransmitSetting.field.MCS, wdev->HTPhyMode.field.MCS); } pEntry->MmpsMode = MMPS_DISABLE; NdisMoveMemory(&pEntry->HTCapability, &pAd->CommonCfg.HtCapability, sizeof(HT_CAPABILITY_IE)); if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); set_sta_ht_cap(pAd, pEntry, &pEntry->HTCapability); CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); } #endif /* DOT11_N_SUPPORT */ else { NdisZeroMemory(&pEntry->HTCapability, sizeof(HT_CAPABILITY_IE)); } // for now, we set this by default! CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RALINK_CHIPSET); if (wdev->bAutoTxRateSwitch == FALSE) { pEntry->HTPhyMode.field.MCS = wdev->DesiredTransmitSetting.field.MCS; pEntry->bAutoTxRateSwitch = FALSE; /* If the legacy mode is set, overwrite the transmit setting of this entry. */ RTMPUpdateLegacyTxSetting((UCHAR)wdev->DesiredTransmitSetting.field.FixedTxMode, pEntry); } else { // TODO: shiang-MT7603, fix me for this, because we may need to set this only when we have WTBL entry for tx_rate! pEntry->bAutoTxRateSwitch = TRUE; } wds_entry->MacTabMatchWCID = (UCHAR)pEntry->wcid; pEntry->func_tb_idx = WdsTabIdx; pEntry->wdev = wdev; COPY_MAC_ADDR(&wdev->bssid[0], &pEntry->Addr[0]); AsicUpdateWdsEncryption(pAd, pEntry->wcid); DBGPRINT(RT_DEBUG_OFF, ("%s() - allocate entry #%d(link to WCID %d), Total= %d\n", __FUNCTION__, WdsTabIdx, wds_entry->MacTabMatchWCID, pAd->WdsTab.Size)); break; } }while(FALSE); return pEntry; } MAC_TABLE_ENTRY *WdsTableLookupByWcid( IN PRTMP_ADAPTER pAd, IN UCHAR wcid, IN PUCHAR pAddr, IN BOOLEAN bResetIdelCount) { ULONG WdsIndex; MAC_TABLE_ENTRY *pCurEntry = NULL, *pEntry = NULL; if (wcid <=0 || wcid >= MAX_LEN_OF_MAC_TABLE ) return NULL; NdisAcquireSpinLock(&pAd->WdsTabLock); NdisAcquireSpinLock(&pAd->MacTabLock); do { pCurEntry = &pAd->MacTab.Content[wcid]; WdsIndex = 0xff; if ((pCurEntry) && IS_ENTRY_WDS(pCurEntry)) WdsIndex = pCurEntry->func_tb_idx; if (WdsIndex == 0xff) break; if (pAd->WdsTab.WdsEntry[WdsIndex].Valid != TRUE) break; if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) { if(bResetIdelCount) { pCurEntry->NoDataIdleCount = 0; // TODO: shiang-usw, remove upper setting becasue we need to migrate to tr_entry! pAd->MacTab.tr_entry[pCurEntry->wcid].NoDataIdleCount = 0; } pEntry = pCurEntry; break; } } while(FALSE); NdisReleaseSpinLock(&pAd->MacTabLock); NdisReleaseSpinLock(&pAd->WdsTabLock); return pEntry; } MAC_TABLE_ENTRY *WdsTableLookup(RTMP_ADAPTER *pAd, UCHAR *addr, BOOLEAN bResetIdelCount) { USHORT HashIdx; PMAC_TABLE_ENTRY pEntry = NULL; NdisAcquireSpinLock(&pAd->WdsTabLock); NdisAcquireSpinLock(&pAd->MacTabLock); HashIdx = MAC_ADDR_HASH_INDEX(addr); pEntry = pAd->MacTab.Hash[HashIdx]; while (pEntry) { if (IS_ENTRY_WDS(pEntry) && MAC_ADDR_EQUAL(pEntry->Addr, addr)) { if(bResetIdelCount) { pEntry->NoDataIdleCount = 0; // TODO: shiang-usw, remove upper setting becasue we need to migrate to tr_entry! pAd->MacTab.tr_entry[pEntry->wcid].NoDataIdleCount = 0; } break; } else pEntry = pEntry->pNext; } NdisReleaseSpinLock(&pAd->MacTabLock); NdisReleaseSpinLock(&pAd->WdsTabLock); return pEntry; } MAC_TABLE_ENTRY *FindWdsEntry( IN RTMP_ADAPTER *pAd, IN UCHAR Wcid, IN UCHAR *pAddr, IN UINT32 PhyMode) { MAC_TABLE_ENTRY *pEntry; RT_802_11_WDS_ENTRY *wds_entry; /* lookup the match wds entry for the incoming packet. */ pEntry = WdsTableLookupByWcid(pAd, Wcid, pAddr, TRUE); if (pEntry == NULL) pEntry = WdsTableLookup(pAd, pAddr, TRUE); /* Only Lazy mode will auto learning, match with FrDs=1 and ToDs=1 */ if((pEntry == NULL) && (pAd->WdsTab.Mode >= WDS_LAZY_MODE)) { INT WdsIdx = WdsEntryAlloc(pAd, pAddr); if (WdsIdx >= 0 && WdsIdx < MAX_WDS_ENTRY) { wds_entry = &pAd->WdsTab.WdsEntry[WdsIdx]; /* user doesn't specific a phy mode for WDS link. */ if (wds_entry->wdev.PhyMode == 0xff) wds_entry->wdev.PhyMode = PhyMode; pEntry = MacTableInsertWDSEntry(pAd, pAddr, (UCHAR)WdsIdx); RTMPSetSupportMCS(pAd, OPMODE_AP, pEntry, pAd->CommonCfg.SupRate, pAd->CommonCfg.SupRateLen, pAd->CommonCfg.ExtRate, pAd->CommonCfg.ExtRateLen, #ifdef DOT11_VHT_AC 0, NULL, #endif /* DOT11_VHT_AC */ &pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); } else pEntry = NULL; } return pEntry; } /* ========================================================================== Description: This routine is called by APMlmePeriodicExec() every second to check if 1. any WDS client being idle for too long and should be aged-out from MAC table ========================================================================== */ VOID WdsTableMaintenance(RTMP_ADAPTER *pAd) { UCHAR idx; if (pAd->WdsTab.Mode != WDS_LAZY_MODE) return; for (idx = 0; idx < pAd->WdsTab.Size; idx++) { UCHAR wcid = pAd->WdsTab.WdsEntry[idx].MacTabMatchWCID; PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[wcid]; if(!IS_ENTRY_WDS(pEntry)) continue; NdisAcquireSpinLock(&pAd->WdsTabLock); NdisAcquireSpinLock(&pAd->MacTabLock); pEntry->NoDataIdleCount ++; // TODO: shiang-usw, remove upper setting becasue we need to migrate to tr_entry! pAd->MacTab.tr_entry[pEntry->wcid].NoDataIdleCount++; NdisReleaseSpinLock(&pAd->MacTabLock); NdisReleaseSpinLock(&pAd->WdsTabLock); /* delete those MAC entry that has been idle for a long time */ if (pEntry->NoDataIdleCount >= MAC_TABLE_AGEOUT_TIME) { DBGPRINT(RT_DEBUG_TRACE, ("ageout %02x:%02x:%02x:%02x:%02x:%02x from WDS #%d after %d-sec silence\n", PRINT_MAC(pEntry->Addr), idx, MAC_TABLE_AGEOUT_TIME)); WdsEntryDel(pAd, pEntry->Addr); MacTableDeleteWDSEntry(pAd, pEntry->wcid, pEntry->Addr); } } } VOID RT28xx_WDS_Close(RTMP_ADAPTER *pAd) { UINT index; for(index = 0; index < MAX_WDS_ENTRY; index++) { if (pAd->WdsTab.WdsEntry[index].wdev.if_dev) RtmpOSNetDevClose(pAd->WdsTab.WdsEntry[index].wdev.if_dev); } return; } #if 0 /* os abl move to ap/ap_wds_inf.c */ VOID RT28xx_WDS_Remove(RTMP_ADAPTER *pAd) { UINT index; for(index = 0; index < MAX_WDS_ENTRY; index++) { if (pAd->WdsTab.WdsEntry[index].dev) { RtmpOSNetDevDetach(pAd->WdsTab.WdsEntry[index].dev); rtmp_wdev_idx_unreg(pAd, wdev); RtmpOSNetDevFree(pAd->WdsTab.WdsEntry[index].dev); /* Clear it as NULL to prevent latter access error. */ pAd->WdsTab.WdsEntry[index].dev = NULL; } } } #endif /* 0 */ VOID WdsDown(RTMP_ADAPTER *pAd) { int i; for (i=0; iWdsTab.WdsEntry[i].PeerWdsAddr, TRUE)) MacTableDeleteWDSEntry(pAd, pAd->WdsTab.WdsEntry[i].MacTabMatchWCID, pAd->WdsTab.WdsEntry[i].PeerWdsAddr); } } VOID AsicUpdateWdsRxWCIDTable(RTMP_ADAPTER *pAd) { UINT index; MAC_TABLE_ENTRY *pEntry = NULL; RT_802_11_WDS_ENTRY *wds_entry; for(index = 0; index < MAX_WDS_ENTRY; index++) { wds_entry = &pAd->WdsTab.WdsEntry[index]; if (pAd->WdsTab.Mode >= WDS_LAZY_MODE) { wds_entry->wdev.PhyMode = 0xff; if (WMODE_CAP_N(pAd->CommonCfg.PhyMode)) wds_entry->wdev.PhyMode = MODE_HTMIX; else { if (WMODE_EQUAL(pAd->CommonCfg.PhyMode, WMODE_B)) wds_entry->wdev.PhyMode = MODE_CCK; else wds_entry->wdev.PhyMode = MODE_OFDM; } } if (wds_entry->Valid != TRUE) continue; pEntry = MacTableInsertWDSEntry(pAd, wds_entry->PeerWdsAddr, index); RTMPSetSupportMCS(pAd, OPMODE_AP, pEntry, pAd->CommonCfg.SupRate, pAd->CommonCfg.SupRateLen, pAd->CommonCfg.ExtRate, pAd->CommonCfg.ExtRateLen, #ifdef DOT11_VHT_AC 0, NULL, #endif /* DOT11_VHT_AC */ &pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); switch (wds_entry->wdev.PhyMode) { case 0xff: /* user doesn't specific a Mode for WDS link. */ case MODE_OFDM: /* specific OFDM mode. */ pEntry->SupportRateMode = SUPPORT_OFDM_MODE; if (WMODE_CAP_2G(pAd->CommonCfg.PhyMode)) pEntry->SupportRateMode |= SUPPORT_CCK_MODE; break; case MODE_CCK: pEntry->SupportRateMode = SUPPORT_CCK_MODE; break; #ifdef DOT11_N_SUPPORT case MODE_HTMIX: case MODE_HTGREENFIELD: pEntry->SupportRateMode = (SUPPORT_HT_MODE | SUPPORT_OFDM_MODE); if (WMODE_CAP_2G(pAd->CommonCfg.PhyMode)) pEntry->SupportRateMode |= SUPPORT_CCK_MODE; break; #endif /* DOT11_N_SUPPORT */ default: break; } } return; } VOID AsicUpdateWdsEncryption(RTMP_ADAPTER *pAd, UCHAR wcid) { UINT WdsIdex; PMAC_TABLE_ENTRY pEntry = NULL; RT_802_11_WDS_ENTRY *wds_entry; struct wifi_dev *wdev; do { if (wcid >= MAX_LEN_OF_MAC_TABLE) break; pEntry = &pAd->MacTab.Content[wcid]; if (pAd->WdsTab.WdsEntry[pEntry->func_tb_idx].Valid != TRUE) break; if (!IS_ENTRY_WDS(pEntry)) break; WdsIdex = pEntry->func_tb_idx; wds_entry = &pAd->WdsTab.WdsEntry[WdsIdex]; wdev = &wds_entry->wdev; if (((wdev->WepStatus == Ndis802_11WEPEnabled) || (wdev->WepStatus == Ndis802_11TKIPEnable) || (wdev->WepStatus == Ndis802_11AESEnable)) && (wds_entry->WdsKey.KeyLen > 0)) { INT DefaultKeyId = 0; if (wdev->WepStatus == Ndis802_11WEPEnabled) DefaultKeyId = wds_entry->KeyIdx; if (!VAILD_KEY_INDEX(DefaultKeyId)) break; /* Update key into Asic Pairwise key table */ RTMP_ASIC_PAIRWISE_KEY_TABLE( pAd, pEntry->wcid, &wds_entry->WdsKey); /* update WCID attribute table and IVEIV table for this entry */ RTMP_SET_WCID_SEC_INFO( pAd, MAIN_MBSSID + MIN_NET_DEVICE_FOR_WDS, DefaultKeyId, wds_entry->WdsKey.CipherAlg, pEntry->wcid, PAIRWISEKEY); #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) CmdProcAddRemoveKey(pAd, 0, pEntry->func_tb_idx, DefaultKeyId, pEntry->wcid, PAIRWISEKEYTABLE, &wds_entry->WdsKey, pEntry->Addr); #endif /* MT_MAC */ } } while (FALSE); return; } VOID WdsPeerBeaconProc( IN PRTMP_ADAPTER pAd, IN PMAC_TABLE_ENTRY pEntry, IN USHORT CapabilityInfo, IN UCHAR MaxSupportedRateIn500Kbps, IN UCHAR MaxSupportedRateLen, IN BOOLEAN bWmmCapable, IN ULONG ClientRalinkIe, IN HT_CAPABILITY_IE *pHtCapability, IN UCHAR HtCapabilityLen) { UCHAR MaxSupportedRate = RATE_11; MaxSupportedRate = dot11_2_ra_rate(MaxSupportedRateIn500Kbps); if (pEntry && IS_ENTRY_WDS(pEntry)) { pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); pEntry->RateLen = MaxSupportedRateLen; set_entry_phy_cfg(pAd, pEntry); pEntry->MaxHTPhyMode.field.BW = BW_20; pEntry->MinHTPhyMode.field.BW = BW_20; #ifdef DOT11_N_SUPPORT pEntry->HTCapability.MCSSet[0] = 0; pEntry->HTCapability.MCSSet[1] = 0; #endif /* DOT11_N_SUPPORT */ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); pEntry->CapabilityInfo = CapabilityInfo; set_sta_ra_cap(pAd, pEntry, ClientRalinkIe); #ifdef DOT11_N_SUPPORT /* If this Entry supports 802.11n, upgrade to HT rate. */ if ((HtCapabilityLen != 0) && WMODE_CAP_N(pAd->CommonCfg.PhyMode)) { ht_mode_adjust(pAd, pEntry, pHtCapability, &pAd->CommonCfg.DesiredHtPhy); /* find max fixed rate */ pEntry->MaxHTPhyMode.field.MCS = get_ht_max_mcs(pAd, &pAd->WdsTab.WdsEntry[pEntry->func_tb_idx].wdev.DesiredHtPhyInfo.MCSSet[0], &pHtCapability->MCSSet[0]); if ((pEntry->MaxHTPhyMode.field.MCS > pAd->WdsTab.WdsEntry[pEntry->func_tb_idx].wdev.HTPhyMode.field.MCS) && (pAd->WdsTab.WdsEntry[pEntry->func_tb_idx].wdev.HTPhyMode.field.MCS != MCS_AUTO)) pEntry->MaxHTPhyMode.field.MCS = pAd->WdsTab.WdsEntry[pEntry->func_tb_idx].wdev.HTPhyMode.field.MCS; pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity; pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor; pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs; pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize; if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); set_sta_ht_cap(pAd, pEntry, pHtCapability); NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE)); } else { NdisZeroMemory(&pEntry->HTCapability, sizeof(HT_CAPABILITY_IE)); pAd->MacTab.fAnyStationIsLegacy = TRUE; } #endif /* DOT11_N_SUPPORT */ if (bWmmCapable #ifdef DOT11_N_SUPPORT || (pEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) #endif /* DOT11_N_SUPPORT */ ) { CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); } else { CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); } pEntry->HTPhyMode.field.MODE = pEntry->MaxHTPhyMode.field.MODE; pEntry->HTPhyMode.field.STBC = pEntry->MaxHTPhyMode.field.STBC; pEntry->HTPhyMode.field.ShortGI = pEntry->MaxHTPhyMode.field.ShortGI; pEntry->HTPhyMode.field.BW = pEntry->MaxHTPhyMode.field.BW; switch (pEntry->HTPhyMode.field.MODE) { case MODE_OFDM: /* specific OFDM mode. */ pEntry->SupportRateMode = SUPPORT_OFDM_MODE; break; case MODE_CCK: pEntry->SupportRateMode = SUPPORT_CCK_MODE; break; #ifdef DOT11_N_SUPPORT case MODE_HTMIX: case MODE_HTGREENFIELD: pEntry->SupportRateMode = (SUPPORT_HT_MODE | SUPPORT_OFDM_MODE | SUPPORT_CCK_MODE); break; #endif /* DOT11_N_SUPPORT */ default: break; } } } VOID APWdsInitialize(RTMP_ADAPTER *pAd) { INT i; RT_802_11_WDS_ENTRY *wds_entry; pAd->WdsTab.Mode = WDS_DISABLE_MODE; pAd->WdsTab.Size = 0; for (i = 0; i < MAX_WDS_ENTRY; i++) { wds_entry = &pAd->WdsTab.WdsEntry[i]; wds_entry->wdev.PhyMode = 0xff; wds_entry->wdev.WepStatus = Ndis802_11EncryptionDisabled; wds_entry->wdev.bAutoTxRateSwitch = TRUE; wds_entry->wdev.DesiredTransmitSetting.field.MCS = MCS_AUTO; wds_entry->Valid = FALSE; wds_entry->MacTabMatchWCID = 0; wds_entry->KeyIdx = 0; NdisZeroMemory(&wds_entry->WdsKey, sizeof(CIPHER_KEY)); NdisZeroMemory(&wds_entry->WdsCounter, sizeof(WDS_COUNTER)); } return; } INT Show_WdsTable_Proc(RTMP_ADAPTER *pAd, RTMP_STRING *arg) { INT i; for(i = 0; i < MAX_WDS_ENTRY; i++) { DBGPRINT(RT_DEBUG_OFF, ("IF/WDS%d-%02x:%02x:%02x:%02x:%02x:%02x(%s) ,%s, KeyId=%d\n", i, PRINT_MAC(pAd->WdsTab.WdsEntry[i].PeerWdsAddr), pAd->WdsTab.WdsEntry[i].Valid == 1 ? "Valid" : "Invalid", GetEncryptType(pAd->WdsTab.WdsEntry[i].wdev.WepStatus), pAd->WdsTab.WdsEntry[i].KeyIdx)); if (pAd->WdsTab.WdsEntry[i].WdsKey.KeyLen > 0) hex_dump("Wds Key", pAd->WdsTab.WdsEntry[i].WdsKey.Key, pAd->WdsTab.WdsEntry[i].WdsKey.KeyLen); } DBGPRINT(RT_DEBUG_OFF, ("\n%-19s%-4s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", "MAC", "IDX", "AID", "PSM", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC")); for (i=0; iMacTab.Content[i]; if (IS_ENTRY_WDS(pEntry)) { DBGPRINT(RT_DEBUG_OFF, ("%02X:%02X:%02X:%02X:%02X:%02X ", PRINT_MAC(pEntry->Addr))); DBGPRINT(RT_DEBUG_OFF,("%-4d", (int)pEntry->func_tb_idx)); DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->Aid)); DBGPRINT(RT_DEBUG_OFF, ("%-4d", (int)pEntry->PsMode)); DBGPRINT(RT_DEBUG_OFF, ("%-7d", pEntry->RssiSample.AvgRssi[0])); DBGPRINT(RT_DEBUG_OFF, ("%-7d", pEntry->RssiSample.AvgRssi[1])); DBGPRINT(RT_DEBUG_OFF, ("%-7d", pEntry->RssiSample.AvgRssi[2])); DBGPRINT(RT_DEBUG_OFF, ("%-10s", get_phymode_str(pEntry->HTPhyMode.field.MODE))); DBGPRINT(RT_DEBUG_OFF, ("%-6s", get_bw_str(pEntry->HTPhyMode.field.BW))); DBGPRINT(RT_DEBUG_OFF, ("%-6d", pEntry->HTPhyMode.field.MCS)); DBGPRINT(RT_DEBUG_OFF, ("%-6d", pEntry->HTPhyMode.field.ShortGI)); DBGPRINT(RT_DEBUG_OFF, ("%-6d\n", pEntry->HTPhyMode.field.STBC)); } } return TRUE; } VOID rtmp_read_wds_from_file(RTMP_ADAPTER *pAd, RTMP_STRING *tmpbuf, RTMP_STRING *buffer) { RTMP_STRING *macptr; INT i=0, j; RTMP_STRING tok_str[16]; BOOLEAN bUsePrevFormat = FALSE; UCHAR macAddress[MAC_ADDR_LEN]; UCHAR keyMaterial[40]; UCHAR KeyLen, CipherAlg = CIPHER_NONE, KeyIdx; PRT_802_11_WDS_ENTRY pWdsEntry; struct wifi_dev *wdev; /*WdsPhyMode */ if (RTMPGetKeyParameter("WdsPhyMode", tmpbuf, MAX_PARAM_BUFFER_SIZE, buffer, TRUE)) { for (i=0, macptr = rstrtok(tmpbuf,";"); (macptr && i < MAX_WDS_ENTRY); macptr = rstrtok(NULL,";"), i++) { pWdsEntry = &pAd->WdsTab.WdsEntry[i]; wdev = &pWdsEntry->wdev; if (rtstrcasecmp(macptr, "CCK") == TRUE) wdev->PhyMode = MODE_CCK; else if (rtstrcasecmp(macptr, "OFDM") == TRUE) wdev->PhyMode = MODE_OFDM; #ifdef DOT11_N_SUPPORT else if (rtstrcasecmp(macptr, "HTMIX") == TRUE) wdev->PhyMode = MODE_HTMIX; else if (rtstrcasecmp(macptr, "GREENFIELD") == TRUE) wdev->PhyMode = MODE_HTGREENFIELD; #endif /* DOT11_N_SUPPORT */ else wdev->PhyMode = 0xff; DBGPRINT(RT_DEBUG_TRACE, ("If/wds%d - PeerPhyMode=%d\n", i, wdev->PhyMode)); } } /*WdsList */ if (RTMPGetKeyParameter("WdsList", tmpbuf, MAX_PARAM_BUFFER_SIZE, buffer, TRUE)) { if (pAd->WdsTab.Mode != WDS_LAZY_MODE) { for (i=0, macptr = rstrtok(tmpbuf,";"); (macptr && i < MAX_WDS_ENTRY); macptr = rstrtok(NULL,";"), i++) { if(strlen(macptr) != 17) /*Mac address acceptable format 01:02:03:04:05:06 length 17 */ continue; if(strcmp(macptr,"00:00:00:00:00:00") == 0) continue; if(i >= MAX_WDS_ENTRY) break; for (j=0; jWdsTab.WdsEntry[i]; wdev = &pWdsEntry->wdev; if (rtstrcasecmp(macptr, "NONE") == TRUE) wdev->WepStatus = Ndis802_11WEPDisabled; else if (rtstrcasecmp(macptr, "WEP") == TRUE) wdev->WepStatus = Ndis802_11WEPEnabled; else if (rtstrcasecmp(macptr, "TKIP") ==TRUE) wdev->WepStatus = Ndis802_11TKIPEnable; else if (rtstrcasecmp(macptr, "AES") == TRUE) wdev->WepStatus = Ndis802_11AESEnable; else wdev->WepStatus = Ndis802_11WEPDisabled; DBGPRINT(RT_DEBUG_TRACE, ("WdsEncrypType[%d]=%d(%s)\n", i, wdev->WepStatus, GetEncryptType(wdev->WepStatus))); } /* Previous WDS only supports single encryption type. */ /* For backward compatible, other wds link encryption type shall be the same with the first. */ if (i == 1) { for (j = 1; j < MAX_WDS_ENTRY; j++) { wdev = &pAd->WdsTab.WdsEntry[j].wdev; wdev->WepStatus = pAd->WdsTab.WdsEntry[0].wdev.WepStatus; DBGPRINT(RT_DEBUG_TRACE, ("WdsEncrypType[%d]=%d(%s)\n", j, wdev->WepStatus, GetEncryptType(wdev->WepStatus))); } } } /* WdsKey */ /* This is a previous parameter and it only stores WPA key material, not WEP key */ if (RTMPGetKeyParameter("WdsKey", tmpbuf, 255, buffer, FALSE)) { for (i = 0; i < MAX_WDS_ENTRY; i++) NdisZeroMemory(&pAd->WdsTab.WdsEntry[i].WdsKey, sizeof(CIPHER_KEY)); if (strlen(tmpbuf) > 0) bUsePrevFormat = TRUE; wdev = &pAd->WdsTab.WdsEntry[0].wdev; pWdsEntry = &pAd->WdsTab.WdsEntry[0]; /* check if the wds-0 link key material is valid */ if (((wdev->WepStatus == Ndis802_11TKIPEnable) || (wdev->WepStatus == Ndis802_11AESEnable)) && (strlen(tmpbuf) >= 8) && (strlen(tmpbuf) <= 64)) { #if 0 if (strlen(tmpbuf) == 64) { /* Hex mode */ AtoH(tmpbuf, keyMaterial, 32); } else { /* ASCII mode */ RtmpPasswordHash(tmpbuf, (PUCHAR) RALINK_PASSPHRASE, sizeof(RALINK_PASSPHRASE), keyMaterial); } #else RT_CfgSetWPAPSKKey(pAd, tmpbuf, strlen(tmpbuf), (PUCHAR)RALINK_PASSPHRASE, sizeof(RALINK_PASSPHRASE), keyMaterial); #endif if (wdev->WepStatus == Ndis802_11AESEnable) pWdsEntry->WdsKey.CipherAlg = CIPHER_AES; else pWdsEntry->WdsKey.CipherAlg = CIPHER_TKIP; NdisMoveMemory(&pWdsEntry->WdsKey.Key, keyMaterial, 16); pWdsEntry->WdsKey.KeyLen = 16; NdisMoveMemory(&pWdsEntry->WdsKey.RxMic, keyMaterial+16, 8); NdisMoveMemory(&pWdsEntry->WdsKey.TxMic, keyMaterial+16, 8); } /* Previous WDS only supports single key-material. */ /* For backward compatible, other wds link key-material shall be the same with the first. */ if (pAd->WdsTab.WdsEntry[0].WdsKey.KeyLen == 16) { for (j = 1; j < MAX_WDS_ENTRY; j++) { NdisMoveMemory(&pAd->WdsTab.WdsEntry[j].WdsKey, &pAd->WdsTab.WdsEntry[0].WdsKey, sizeof(CIPHER_KEY)); } } } /* The parameters can provide different key information for each WDS-Link */ /* no matter WEP or WPA */ if (!bUsePrevFormat) { for (i = 0; i < MAX_WDS_ENTRY; i++) { AP_WDS_KeyNameMakeUp(tok_str, sizeof(tok_str), i); #if 0 #ifdef __ECOS sprintf(tok_str, "Wds%dKey", i+1); #else snprintf(tok_str, sizeof(tok_str), "Wds%dKey", i); #endif /* __ECOS */ #endif /* 0 */ pWdsEntry = &pAd->WdsTab.WdsEntry[i]; wdev = &pWdsEntry->wdev; /* WdsXKey (X=0~MAX_WDS_ENTRY-1) */ if (RTMPGetKeyParameter(tok_str, tmpbuf, 128, buffer, FALSE)) { if (wdev->WepStatus == Ndis802_11WEPEnabled) { /* Ascii type */ if (strlen(tmpbuf) == 5 || strlen(tmpbuf) == 13) { KeyLen = strlen(tmpbuf); pWdsEntry->WdsKey.KeyLen = KeyLen; NdisMoveMemory(pWdsEntry->WdsKey.Key, tmpbuf, KeyLen); if (KeyLen == 5) CipherAlg = CIPHER_WEP64; else CipherAlg = CIPHER_WEP128; pWdsEntry->WdsKey.CipherAlg = CipherAlg; DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d Key=%s ,type=Ascii, CipherAlg(%s)\n", i, tmpbuf, (CipherAlg == CIPHER_WEP64 ? "wep64" : "wep128"))); } /* Hex type */ else if (strlen(tmpbuf) == 10 || strlen(tmpbuf) == 26) { KeyLen = strlen(tmpbuf); pWdsEntry->WdsKey.KeyLen = KeyLen / 2; AtoH(tmpbuf, pWdsEntry->WdsKey.Key, KeyLen / 2); if (KeyLen == 10) CipherAlg = CIPHER_WEP64; else CipherAlg = CIPHER_WEP128; pWdsEntry->WdsKey.CipherAlg = CipherAlg; DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d Key=%s ,type=Hex, CipherAlg(%s)\n", i, tmpbuf, (CipherAlg == CIPHER_WEP64 ? "wep64" : "wep128"))); } /* Invalid type */ else { wdev->WepStatus = Ndis802_11EncryptionDisabled; NdisZeroMemory(&pWdsEntry->WdsKey, sizeof(CIPHER_KEY)); DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d has invalid key for WEP, reset encryption to OPEN\n", i)); } } else if ((wdev->WepStatus == Ndis802_11TKIPEnable) || (wdev->WepStatus == Ndis802_11AESEnable)) { if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) <= 64)) { #if 0 if (strlen(tmpbuf) == 64) { /* Hex mode */ AtoH(tmpbuf, keyMaterial, 32); } else { /* ASCII mode */ RtmpPasswordHash(tmpbuf, (PUCHAR) RALINK_PASSPHRASE, sizeof(RALINK_PASSPHRASE), keyMaterial); } #else RT_CfgSetWPAPSKKey(pAd, tmpbuf, strlen(tmpbuf), (PUCHAR) RALINK_PASSPHRASE, sizeof(RALINK_PASSPHRASE), keyMaterial); #endif if (wdev->WepStatus == Ndis802_11AESEnable) pWdsEntry->WdsKey.CipherAlg = CIPHER_AES; else pWdsEntry->WdsKey.CipherAlg = CIPHER_TKIP; NdisMoveMemory(&pWdsEntry->WdsKey.Key, keyMaterial, 16); pWdsEntry->WdsKey.KeyLen = 16; NdisMoveMemory(&pWdsEntry->WdsKey.RxMic, keyMaterial+16, 8); NdisMoveMemory(&pWdsEntry->WdsKey.TxMic, keyMaterial+16, 8); DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d Key=%s, CipherAlg(%s)\n", i, tmpbuf, (CipherAlg == CIPHER_AES ? "AES" : "TKIP"))); } else { DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d has invalid key for WPA, reset encryption to OPEN\n", i)); wdev->WepStatus = Ndis802_11EncryptionDisabled; NdisZeroMemory(&pWdsEntry->WdsKey, sizeof(CIPHER_KEY)); } } else { wdev->WepStatus = Ndis802_11EncryptionDisabled; NdisZeroMemory(&pWdsEntry->WdsKey, sizeof(CIPHER_KEY)); } } } } /* WdsDefaultKeyID */ if(RTMPGetKeyParameter("WdsDefaultKeyID", tmpbuf, 10, buffer, TRUE)) { for (i = 0, macptr = rstrtok(tmpbuf,";"); (macptr && i < MAX_WDS_ENTRY); macptr = rstrtok(NULL,";"), i++) { pWdsEntry = &pAd->WdsTab.WdsEntry[i]; wdev = &pWdsEntry->wdev; KeyIdx = (UCHAR) simple_strtol(macptr, 0, 10); if((KeyIdx >= 1 ) && (KeyIdx <= 4)) pWdsEntry->KeyIdx = (UCHAR) (KeyIdx - 1); else pWdsEntry->KeyIdx = 0; if ((wdev->WepStatus == Ndis802_11TKIPEnable) || (wdev->WepStatus == Ndis802_11AESEnable)) pWdsEntry->KeyIdx = 0; DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d - WdsDefaultKeyID(0~3)=%d\n", i, pWdsEntry->KeyIdx)); } } /* WdsTxMode */ if (RTMPGetKeyParameter("WdsTxMode", tmpbuf, 25, buffer, TRUE)) { for (i = 0, macptr = rstrtok(tmpbuf,";"); (macptr && i < MAX_WDS_ENTRY); macptr = rstrtok(NULL,";"), i++) { wdev = &pAd->WdsTab.WdsEntry[i].wdev; wdev->DesiredTransmitSetting.field.FixedTxMode = RT_CfgSetFixedTxPhyMode(macptr); DBGPRINT(RT_DEBUG_TRACE, ("I/F(wds%d) Tx Mode = %d\n", i, wdev->DesiredTransmitSetting.field.FixedTxMode)); } } /* WdsTxMcs */ if (RTMPGetKeyParameter("WdsTxMcs", tmpbuf, 50, buffer, TRUE)) { for (i = 0, macptr = rstrtok(tmpbuf,";"); (macptr && i < MAX_WDS_ENTRY); macptr = rstrtok(NULL,";"), i++) { wdev = &pAd->WdsTab.WdsEntry[i].wdev; wdev->DesiredTransmitSetting.field.MCS = RT_CfgSetTxMCSProc(macptr, &wdev->bAutoTxRateSwitch); if (wdev->DesiredTransmitSetting.field.MCS == MCS_AUTO) { DBGPRINT(RT_DEBUG_TRACE, ("I/F(wds%d) Tx MCS = AUTO\n", i)); } else { DBGPRINT(RT_DEBUG_TRACE, ("I/F(wds%d) Tx MCS = %d\n", i, wdev->DesiredTransmitSetting.field.MCS)); } } } /*WdsEnable */ if(RTMPGetKeyParameter("WdsEnable", tmpbuf, 10, buffer, TRUE)) { RT_802_11_WDS_ENTRY *pWdsEntry; switch(simple_strtol(tmpbuf, 0, 10)) { case WDS_BRIDGE_MODE: /* Bridge mode, DisAllow association(stop Beacon generation and Probe Req. */ pAd->WdsTab.Mode = WDS_BRIDGE_MODE; break; case WDS_RESTRICT_MODE: case WDS_REPEATER_MODE: /* Repeater mode */ pAd->WdsTab.Mode = WDS_REPEATER_MODE; break; case WDS_LAZY_MODE: /* Lazy mode, Auto learn wds entry by same SSID, channel, security policy */ for(i = 0; i < MAX_WDS_ENTRY; i++) { pWdsEntry = &pAd->WdsTab.WdsEntry[i]; if (pWdsEntry->Valid) WdsEntryDel(pAd, pWdsEntry->PeerWdsAddr); /* When Lazy mode is enabled, the all wds-link shall share the same encryption type and key material */ if (i > 0) { pWdsEntry->wdev.WepStatus = pAd->WdsTab.WdsEntry[0].wdev.WepStatus; pWdsEntry->KeyIdx = pAd->WdsTab.WdsEntry[0].KeyIdx; NdisMoveMemory(&pWdsEntry->WdsKey, &pAd->WdsTab.WdsEntry[0].WdsKey, sizeof(CIPHER_KEY)); } } pAd->WdsTab.Mode = WDS_LAZY_MODE; break; case WDS_DISABLE_MODE: /* Disable mode */ default: APWdsInitialize(pAd); pAd->WdsTab.Mode = WDS_DISABLE_MODE; break; } DBGPRINT(RT_DEBUG_TRACE, ("WDS-Enable mode=%d\n", pAd->WdsTab.Mode)); #if 0 for(i = 0; i < MAX_WDS_ENTRY; i++) { DBGPRINT(RT_DEBUG_TRACE, ("IF/wds%d-%02x:%02x:%02x:%02x:%02x:%02x(%s) and %s\n", i, PRINT_MAC(pAd->WdsTab.WdsEntry[i].PeerWdsAddr), pAd->WdsTab.WdsEntry[i].Valid == 1 ? "Valid" : "Invalid", GetEncryptType(pAd->WdsTab.WdsEntry[i].wdev.WepStatus))); if (pAd->WdsTab.WdsEntry[i].WdsKey.KeyLen > 0) hex_dump("Wds Key", pAd->WdsTab.WdsEntry[i].WdsKey.Key, pAd->WdsTab.WdsEntry[i].WdsKey.KeyLen); } #endif /* DBG */ } #ifdef WDS_VLAN_SUPPORT /* WdsVlan */ if (RTMPGetKeyParameter("WDS_VLANID", tmpbuf, MAX_PARAM_BUFFER_SIZE, buffer, TRUE)) { for (i=0, macptr = rstrtok(tmpbuf,";"); (macptr && i < MAX_WDS_ENTRY); macptr = rstrtok(NULL,";"), i++) { pAd->WdsTab.WdsEntry[i].wdev.VLAN_VID = simple_strtol(macptr, 0, 10); pAd->WdsTab.WdsEntry[i].wdev.VLAN_Priority = 0; DBGPRINT(RT_DEBUG_TRACE, ("If/wds%d - WdsVlanId=%d\n", i, pAd->WdsTab.WdsEntry[i].wdev.VLAN_VID)); } } #endif /* WDS_VLAN_SUPPORT */ } VOID WdsPrepareWepKeyFromMainBss(RTMP_ADAPTER *pAd) { INT i; /* Prepare WEP key for each wds-link if necessary */ for (i = 0; i < MAX_WDS_ENTRY; i++) { /* For WDS backward compatible, refer to the WEP key of Main BSS in WEP mode */ if (pAd->WdsTab.WdsEntry[i].wdev.WepStatus == Ndis802_11WEPEnabled && pAd->WdsTab.WdsEntry[i].WdsKey.KeyLen == 0) { UCHAR main_bss_keyid = pAd->ApCfg.MBSSID[MAIN_MBSSID].wdev.DefaultKeyId; if (pAd->ApCfg.MBSSID[MAIN_MBSSID].wdev.WepStatus == Ndis802_11WEPEnabled && (pAd->SharedKey[MAIN_MBSSID][main_bss_keyid].KeyLen == 5 || pAd->SharedKey[MAIN_MBSSID][main_bss_keyid].KeyLen == 13)) { DBGPRINT(RT_DEBUG_TRACE, ("Duplicate IF/WDS%d wep key from main_bssid \n", (UCHAR)i)); pAd->WdsTab.WdsEntry[i].KeyIdx = main_bss_keyid; NdisMoveMemory(&pAd->WdsTab.WdsEntry[i].WdsKey, &pAd->SharedKey[MAIN_MBSSID][main_bss_keyid], sizeof(CIPHER_KEY)); } else { DBGPRINT(RT_DEBUG_TRACE, ("No available wep key for IF/WDS%d, reset its encryption as OPEN \n", (UCHAR)i)); pAd->WdsTab.WdsEntry[i].wdev.WepStatus = Ndis802_11EncryptionDisabled; NdisZeroMemory(&pAd->WdsTab.WdsEntry[i].WdsKey, sizeof(CIPHER_KEY)); } } } } VOID WDS_Init(RTMP_ADAPTER *pAd, RTMP_OS_NETDEV_OP_HOOK *pNetDevOps) { INT index; PNET_DEV pWdsNetDev; /* sanity check to avoid redundant virtual interfaces are created */ if (pAd->flg_wds_init != FALSE) return; for(index = 0; index < MAX_WDS_ENTRY; index++) { UINT32 MC_RowID = 0, IoctlIF = 0; RT_802_11_WDS_ENTRY *wds_entry; struct wifi_dev *wdev; char *dev_name; #ifdef MULTIPLE_CARD_SUPPORT MC_RowID = pAd->MC_RowID; #endif /* MULTIPLE_CARD_SUPPORT */ #ifdef HOSTAPD_SUPPORT IoctlIF = pAd->IoctlIF; #endif /* HOSTAPD_SUPPORT */ dev_name = get_dev_name_prefix(pAd, INT_WDS); pWdsNetDev = RtmpOSNetDevCreate(MC_RowID, &IoctlIF, INT_WDS, index, sizeof(struct mt_dev_priv), dev_name); #ifdef HOSTAPD_SUPPORT pAd->IoctlIF = IoctlIF; #endif /* HOSTAPD_SUPPORT */ wds_entry = &pAd->WdsTab.WdsEntry[index]; wdev = &wds_entry->wdev; if (pWdsNetDev == NULL) { /* allocation fail, exit */ DBGPRINT(RT_DEBUG_ERROR, ("Allocate network device fail (WDS)...\n")); break; } DBGPRINT(RT_DEBUG_TRACE, ("The new WDS interface MAC = %02X:%02X:%02X:%02X:%02X:%02X\n", PRINT_MAC(pAd->MacTab.Content[wds_entry->MacTabMatchWCID].Addr))); NdisZeroMemory(&wds_entry->WdsCounter, sizeof(WDS_COUNTER)); wdev->wdev_type = WDEV_TYPE_WDS; wdev->func_dev = wds_entry; wdev->func_idx = index; wdev->sys_handle = (void *)pAd; wdev->if_dev = pWdsNetDev; wdev->tx_pkt_allowed = ApWdsAllowToSendPacket; // TODO: shiang-usw, modify this to WDSSendPacket wdev->tx_pkt_handle = APSendPacket; wdev->wdev_hard_tx = APHardTransmit; wdev->rx_pkt_allowed = ap_rx_pkt_allow; wdev->rx_pkt_foward = wds_rx_foward_handle; wdev->PhyMode = 0xff; wdev->allow_data_tx = TRUE; // let tx_pkt_allowed() to check it! wdev->PortSecured = WPA_802_1X_PORT_SECURED; NdisMoveMemory(&wdev->if_addr[0], &pNetDevOps->devAddr[0], MAC_ADDR_LEN); RTMP_OS_NETDEV_SET_PRIV(pWdsNetDev, pAd); RTMP_OS_NETDEV_SET_WDEV(pWdsNetDev, wdev); if (rtmp_wdev_idx_reg(pAd, wdev) < 0) { DBGPRINT(RT_DEBUG_ERROR, ("Assign wdev idx for %s failed, free net device!\n", RTMP_OS_NETDEV_GET_DEVNAME(pWdsNetDev))); RtmpOSNetDevFree(pWdsNetDev); break; } pNetDevOps->priv_flags = INT_WDS; pNetDevOps->needProtcted = TRUE; pNetDevOps->wdev = wdev; /* Register this device */ RtmpOSNetDevAttach(pAd->OpMode, pWdsNetDev, pNetDevOps); } if (index > 0) pAd->flg_wds_init = TRUE; NdisAllocateSpinLock(pAd, &pAd->WdsTabLock); DBGPRINT(RT_DEBUG_TRACE, ("Total allocated %d WDS interfaces!\n", index)); } VOID WDS_Remove(RTMP_ADAPTER *pAd) { UINT index; struct wifi_dev *wdev; for(index = 0; index < MAX_WDS_ENTRY; index++) { wdev = &pAd->WdsTab.WdsEntry[index].wdev; if (wdev->if_dev) { RtmpOSNetDevProtect(1); RtmpOSNetDevDetach(wdev->if_dev); RtmpOSNetDevProtect(0); rtmp_wdev_idx_unreg(pAd, wdev); RtmpOSNetDevFree(wdev->if_dev); /* Clear it as NULL to prevent latter access error. */ wdev->if_dev = NULL; } } } BOOLEAN WDS_StatsGet(RTMP_ADAPTER *pAd, RT_CMD_STATS *pStats) { INT WDS_apidx = 0,index; RT_802_11_WDS_ENTRY *wds_entry; for(index = 0; index < MAX_WDS_ENTRY; index++) { if (pAd->WdsTab.WdsEntry[index].wdev.if_dev == pStats->pNetDev) { WDS_apidx = index; break; } } if(index >= MAX_WDS_ENTRY) { DBGPRINT(RT_DEBUG_ERROR, ("%s(): can not find wds I/F\n", __FUNCTION__)); return FALSE; } wds_entry = &pAd->WdsTab.WdsEntry[WDS_apidx]; pStats->pStats = pAd->stats; pStats->rx_packets = wds_entry->WdsCounter.ReceivedFragmentCount.QuadPart; pStats->tx_packets = wds_entry->WdsCounter.TransmittedFragmentCount.QuadPart; pStats->rx_bytes = wds_entry->WdsCounter.ReceivedByteCount; pStats->tx_bytes = wds_entry->WdsCounter.TransmittedByteCount; pStats->rx_errors = wds_entry->WdsCounter.RxErrorCount; pStats->tx_errors = wds_entry->WdsCounter.TxErrors; pStats->multicast = wds_entry->WdsCounter.MulticastReceivedFrameCount.QuadPart; /* multicast packets received */ pStats->collisions = 0; /* Collision packets */ pStats->rx_over_errors = wds_entry->WdsCounter.RxNoBuffer; /* receiver ring buff overflow */ pStats->rx_crc_errors = 0;/*pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error */ pStats->rx_frame_errors = 0; /* recv'd frame alignment error */ pStats->rx_fifo_errors = wds_entry->WdsCounter.RxNoBuffer; /* recv'r fifo overrun */ return TRUE; } #endif /* WDS_SUPPORT */