dot11d.c (4933B)
1// SPDX-License-Identifier: GPL-2.0 2/* Implement 802.11d. */ 3 4#include "dot11d.h" 5 6void rtl8192u_dot11d_init(struct ieee80211_device *ieee) 7{ 8 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee); 9 10 dot11d_info->dot11d_enabled = false; 11 12 dot11d_info->state = DOT11D_STATE_NONE; 13 dot11d_info->country_ie_len = 0; 14 memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1); 15 memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1); 16 RESET_CIE_WATCHDOG(ieee); 17} 18EXPORT_SYMBOL(rtl8192u_dot11d_init); 19 20/* Reset to the state as we are just entering a regulatory domain. */ 21void dot11d_reset(struct ieee80211_device *ieee) 22{ 23 u32 i; 24 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee); 25 /* Clear old channel map */ 26 memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1); 27 memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1); 28 /* Set new channel map */ 29 for (i = 1; i <= 11; i++) 30 (dot11d_info->channel_map)[i] = 1; 31 32 for (i = 12; i <= 14; i++) 33 (dot11d_info->channel_map)[i] = 2; 34 35 dot11d_info->state = DOT11D_STATE_NONE; 36 dot11d_info->country_ie_len = 0; 37 RESET_CIE_WATCHDOG(ieee); 38} 39EXPORT_SYMBOL(dot11d_reset); 40 41/* 42 * Update country IE from Beacon or Probe Resopnse and configure PHY for 43 * operation in the regulatory domain. 44 * 45 * TODO: Configure Tx power. 46 * Assumption: 47 * 1. IS_DOT11D_ENABLE() is TRUE. 48 * 2. Input IE is an valid one. 49 */ 50void dot11d_update_country_ie(struct ieee80211_device *dev, u8 *pTaddr, 51 u16 CoutryIeLen, u8 *pCoutryIe) 52{ 53 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); 54 u8 i, j, NumTriples, MaxChnlNum; 55 struct chnl_txpower_triple *pTriple; 56 57 memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1); 58 memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1); 59 MaxChnlNum = 0; 60 NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */ 61 pTriple = (struct chnl_txpower_triple *)(pCoutryIe + 3); 62 for (i = 0; i < NumTriples; i++) { 63 if (MaxChnlNum >= pTriple->first_channel) { 64 /* It is not in a monotonically increasing order, so 65 * stop processing. 66 */ 67 netdev_err(dev->dev, "%s: Invalid country IE, skip it 1\n", __func__); 68 return; 69 } 70 if (MAX_CHANNEL_NUMBER < (pTriple->first_channel + pTriple->num_channels)) { 71 /* It is not a valid set of channel id, so stop 72 * processing. 73 */ 74 netdev_err(dev->dev, "%s: Invalid country IE, skip it 2\n", __func__); 75 return; 76 } 77 78 for (j = 0; j < pTriple->num_channels; j++) { 79 dot11d_info->channel_map[pTriple->first_channel + j] = 1; 80 dot11d_info->max_tx_pwr_dbm_list[pTriple->first_channel + j] = pTriple->max_tx_pwr_dbm; 81 MaxChnlNum = pTriple->first_channel + j; 82 } 83 84 pTriple = (struct chnl_txpower_triple *)((u8 *)pTriple + 3); 85 } 86 netdev_info(dev->dev, "Channel List:"); 87 for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) 88 if (dot11d_info->channel_map[i] > 0) 89 netdev_info(dev->dev, " %d", i); 90 netdev_info(dev->dev, "\n"); 91 92 UPDATE_CIE_SRC(dev, pTaddr); 93 94 dot11d_info->country_ie_len = CoutryIeLen; 95 memcpy(dot11d_info->country_ie_buf, pCoutryIe, CoutryIeLen); 96 dot11d_info->state = DOT11D_STATE_LEARNED; 97} 98EXPORT_SYMBOL(dot11d_update_country_ie); 99 100u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 Channel) 101{ 102 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); 103 u8 MaxTxPwrInDbm = 255; 104 105 if (Channel > MAX_CHANNEL_NUMBER) { 106 netdev_err(dev->dev, "%s: Invalid Channel\n", __func__); 107 return MaxTxPwrInDbm; 108 } 109 if (dot11d_info->channel_map[Channel]) 110 MaxTxPwrInDbm = dot11d_info->max_tx_pwr_dbm_list[Channel]; 111 112 return MaxTxPwrInDbm; 113} 114EXPORT_SYMBOL(dot11d_get_max_tx_pwr_in_dbm); 115 116void dot11d_scan_complete(struct ieee80211_device *dev) 117{ 118 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); 119 120 switch (dot11d_info->state) { 121 case DOT11D_STATE_LEARNED: 122 dot11d_info->state = DOT11D_STATE_DONE; 123 break; 124 125 case DOT11D_STATE_DONE: 126 if (GET_CIE_WATCHDOG(dev) == 0) { 127 /* Reset country IE if previous one is gone. */ 128 dot11d_reset(dev); 129 } 130 break; 131 case DOT11D_STATE_NONE: 132 break; 133 } 134} 135EXPORT_SYMBOL(dot11d_scan_complete); 136 137int is_legal_channel(struct ieee80211_device *dev, u8 channel) 138{ 139 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); 140 141 if (channel > MAX_CHANNEL_NUMBER) { 142 netdev_err(dev->dev, "%s: Invalid Channel\n", __func__); 143 return 0; 144 } 145 if (dot11d_info->channel_map[channel] > 0) 146 return 1; 147 return 0; 148} 149EXPORT_SYMBOL(is_legal_channel); 150 151int to_legal_channel(struct ieee80211_device *dev, u8 channel) 152{ 153 struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); 154 u8 default_chn = 0; 155 u32 i = 0; 156 157 for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) { 158 if (dot11d_info->channel_map[i] > 0) { 159 default_chn = i; 160 break; 161 } 162 } 163 164 if (channel > MAX_CHANNEL_NUMBER) { 165 netdev_err(dev->dev, "%s: Invalid Channel\n", __func__); 166 return default_chn; 167 } 168 169 if (dot11d_info->channel_map[channel] > 0) 170 return channel; 171 172 return default_chn; 173} 174EXPORT_SYMBOL(to_legal_channel);