diff options
Diffstat (limited to 'drivers/staging/rtl8187se/ieee80211/dot11d.c')
| -rw-r--r-- | drivers/staging/rtl8187se/ieee80211/dot11d.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c new file mode 100644 index 00000000..9d2d5c58 --- /dev/null +++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c @@ -0,0 +1,213 @@ +//----------------------------------------------------------------------------- +// File: +// Dot11d.c +// +// Description: +// Implement 802.11d. +// +//----------------------------------------------------------------------------- + +#include "dot11d.h" + +void +Dot11d_Init(struct ieee80211_device *ieee) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); + + pDot11dInfo->bEnabled = 0; + + pDot11dInfo->State = DOT11D_STATE_NONE; + pDot11dInfo->CountryIeLen = 0; + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + RESET_CIE_WATCHDOG(ieee); + + printk("Dot11d_Init()\n"); +} + +// +// Description: +// Reset to the state as we are just entering a regulatory domain. +// +void +Dot11d_Reset(struct ieee80211_device *ieee) +{ + u32 i; + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); + + // Clear old channel map + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + // Set new channel map + for (i = 1; i <= 11; i++) + (pDot11dInfo->channel_map)[i] = 1; + + for (i = 12; i <= 14; i++) + (pDot11dInfo->channel_map)[i] = 2; + + pDot11dInfo->State = DOT11D_STATE_NONE; + pDot11dInfo->CountryIeLen = 0; + RESET_CIE_WATCHDOG(ieee); + + //printk("Dot11d_Reset()\n"); +} + +// +// Description: +// Update country IE from Beacon or Probe Response +// and configure PHY for operation in the regulatory domain. +// +// TODO: +// Configure Tx power. +// +// Assumption: +// 1. IS_DOT11D_ENABLE() is TRUE. +// 2. Input IE is an valid one. +// +void +Dot11d_UpdateCountryIe( + struct ieee80211_device *dev, + u8 *pTaddr, + u16 CoutryIeLen, + u8 *pCoutryIe + ) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + u8 i, j, NumTriples, MaxChnlNum; + PCHNL_TXPOWER_TRIPLE pTriple; + + if ((CoutryIeLen - 3)%3 != 0) { + printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); + Dot11d_Reset(dev); + return; + } + + memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); + memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); + MaxChnlNum = 0; + NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string. + pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3); + for (i = 0; i < NumTriples; i++) { + if (MaxChnlNum >= pTriple->FirstChnl) { + // It is not in a monotonically increasing order, so stop processing. + printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); + Dot11d_Reset(dev); + return; + } + if (MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls)) { + // It is not a valid set of channel id, so stop processing. + printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n"); + Dot11d_Reset(dev); + return; + } + + for (j = 0 ; j < pTriple->NumChnls; j++) { + pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1; + pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm; + MaxChnlNum = pTriple->FirstChnl + j; + } + + pTriple = (PCHNL_TXPOWER_TRIPLE)((u8 *)pTriple + 3); + } +#if 1 + //printk("Dot11d_UpdateCountryIe(): Channel List:\n"); + printk("Channel List:"); + for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) + if (pDot11dInfo->channel_map[i] > 0) + printk(" %d", i); + printk("\n"); +#endif + + UPDATE_CIE_SRC(dev, pTaddr); + + pDot11dInfo->CountryIeLen = CoutryIeLen; + memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe, CoutryIeLen); + pDot11dInfo->State = DOT11D_STATE_LEARNED; +} + +u8 +DOT11D_GetMaxTxPwrInDbm( + struct ieee80211_device *dev, + u8 Channel + ) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + u8 MaxTxPwrInDbm = 255; + + if (MAX_CHANNEL_NUMBER < Channel) { + printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); + return MaxTxPwrInDbm; + } + if (pDot11dInfo->channel_map[Channel]) { + MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; + } + + return MaxTxPwrInDbm; +} + + +void +DOT11D_ScanComplete( + struct ieee80211_device *dev + ) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + + switch (pDot11dInfo->State) { + case DOT11D_STATE_LEARNED: + pDot11dInfo->State = DOT11D_STATE_DONE; + break; + + case DOT11D_STATE_DONE: + if (GET_CIE_WATCHDOG(dev) == 0) { + // Reset country IE if previous one is gone. + Dot11d_Reset(dev); + } + break; + case DOT11D_STATE_NONE: + break; + } +} + +int IsLegalChannel( + struct ieee80211_device *dev, + u8 channel +) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + + if (MAX_CHANNEL_NUMBER < channel) { + printk("IsLegalChannel(): Invalid Channel\n"); + return 0; + } + if (pDot11dInfo->channel_map[channel] > 0) + return 1; + return 0; +} + +int ToLegalChannel( + struct ieee80211_device *dev, + u8 channel +) +{ + PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); + u8 default_chn = 0; + u32 i = 0; + + for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) { + if (pDot11dInfo->channel_map[i] > 0) { + default_chn = i; + break; + } + } + + if (MAX_CHANNEL_NUMBER < channel) { + printk("IsLegalChannel(): Invalid Channel\n"); + return default_chn; + } + + if (pDot11dInfo->channel_map[channel] > 0) + return channel; + + return default_chn; +} |
