Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
c21ce6c7 | 2 | /* Implement 802.11d. */ |
8fc8598e JC |
3 | |
4 | #include "dot11d.h" | |
5 | ||
9003987a | 6 | void rtl8192u_dot11d_init(struct ieee80211_device *ieee) |
8fc8598e | 7 | { |
b972c798 | 8 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee); |
8fc8598e | 9 | |
b972c798 | 10 | dot11d_info->dot11d_enabled = false; |
8fc8598e | 11 | |
b972c798 JW |
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); | |
f401441d | 15 | memset(dot11d_info->max_tx_pwr_dbm_list, 0xFF, MAX_CHANNEL_NUMBER + 1); |
8fc8598e | 16 | RESET_CIE_WATCHDOG(ieee); |
8fc8598e | 17 | } |
9003987a | 18 | EXPORT_SYMBOL(rtl8192u_dot11d_init); |
8fc8598e | 19 | |
c21ce6c7 | 20 | /* Reset to the state as we are just entering a regulatory domain. */ |
6a184731 | 21 | void dot11d_reset(struct ieee80211_device *ieee) |
8fc8598e JC |
22 | { |
23 | u32 i; | |
b972c798 | 24 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee); |
c21ce6c7 | 25 | /* Clear old channel map */ |
f401441d SB |
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); | |
c21ce6c7 | 28 | /* Set new channel map */ |
faec7c97 | 29 | for (i = 1; i <= 11; i++) |
b972c798 | 30 | (dot11d_info->channel_map)[i] = 1; |
faec7c97 AR |
31 | |
32 | for (i = 12; i <= 14; i++) | |
b972c798 | 33 | (dot11d_info->channel_map)[i] = 2; |
8fc8598e | 34 | |
b972c798 JW |
35 | dot11d_info->state = DOT11D_STATE_NONE; |
36 | dot11d_info->country_ie_len = 0; | |
8fc8598e | 37 | RESET_CIE_WATCHDOG(ieee); |
8fc8598e | 38 | } |
6a184731 | 39 | EXPORT_SYMBOL(dot11d_reset); |
8fc8598e | 40 | |
c21ce6c7 AR |
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 | */ | |
d1f91e04 | 50 | void dot11d_update_country_ie(struct ieee80211_device *dev, u8 *pTaddr, |
fee5a5fb | 51 | u16 CoutryIeLen, u8 *pCoutryIe) |
8fc8598e | 52 | { |
b972c798 | 53 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); |
8fc8598e | 54 | u8 i, j, NumTriples, MaxChnlNum; |
1f1590f2 | 55 | struct chnl_txpower_triple *pTriple; |
8fc8598e | 56 | |
f401441d SB |
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); | |
8fc8598e | 59 | MaxChnlNum = 0; |
c21ce6c7 | 60 | NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */ |
1f1590f2 | 61 | pTriple = (struct chnl_txpower_triple *)(pCoutryIe + 3); |
0d86eba5 | 62 | for (i = 0; i < NumTriples; i++) { |
85f24df0 | 63 | if (MaxChnlNum >= pTriple->first_channel) { |
c21ce6c7 AR |
64 | /* It is not in a monotonically increasing order, so |
65 | * stop processing. | |
66 | */ | |
e13ff19e | 67 | netdev_err(dev->dev, "%s: Invalid country IE, skip it 1\n", __func__); |
8fc8598e JC |
68 | return; |
69 | } | |
321639a7 | 70 | if (MAX_CHANNEL_NUMBER < (pTriple->first_channel + pTriple->num_channels)) { |
c21ce6c7 AR |
71 | /* It is not a valid set of channel id, so stop |
72 | * processing. | |
73 | */ | |
e13ff19e | 74 | netdev_err(dev->dev, "%s: Invalid country IE, skip it 2\n", __func__); |
8fc8598e JC |
75 | return; |
76 | } | |
77 | ||
321639a7 | 78 | for (j = 0; j < pTriple->num_channels; j++) { |
b972c798 JW |
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; | |
85f24df0 | 81 | MaxChnlNum = pTriple->first_channel + j; |
8fc8598e JC |
82 | } |
83 | ||
1f1590f2 | 84 | pTriple = (struct chnl_txpower_triple *)((u8 *)pTriple + 3); |
8fc8598e | 85 | } |
14108510 | 86 | netdev_info(dev->dev, "Channel List:"); |
3777aac5 | 87 | for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) |
b972c798 | 88 | if (dot11d_info->channel_map[i] > 0) |
14108510 AR |
89 | netdev_info(dev->dev, " %d", i); |
90 | netdev_info(dev->dev, "\n"); | |
8fc8598e JC |
91 | |
92 | UPDATE_CIE_SRC(dev, pTaddr); | |
93 | ||
b972c798 JW |
94 | dot11d_info->country_ie_len = CoutryIeLen; |
95 | memcpy(dot11d_info->country_ie_buf, pCoutryIe, CoutryIeLen); | |
96 | dot11d_info->state = DOT11D_STATE_LEARNED; | |
8fc8598e | 97 | } |
d1f91e04 | 98 | EXPORT_SYMBOL(dot11d_update_country_ie); |
8fc8598e | 99 | |
869b4372 | 100 | u8 dot11d_get_max_tx_pwr_in_dbm(struct ieee80211_device *dev, u8 Channel) |
8fc8598e | 101 | { |
b972c798 | 102 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); |
8fc8598e JC |
103 | u8 MaxTxPwrInDbm = 255; |
104 | ||
56c4a799 | 105 | if (Channel > MAX_CHANNEL_NUMBER) { |
e13ff19e | 106 | netdev_err(dev->dev, "%s: Invalid Channel\n", __func__); |
8fc8598e JC |
107 | return MaxTxPwrInDbm; |
108 | } | |
b972c798 JW |
109 | if (dot11d_info->channel_map[Channel]) |
110 | MaxTxPwrInDbm = dot11d_info->max_tx_pwr_dbm_list[Channel]; | |
8fc8598e JC |
111 | |
112 | return MaxTxPwrInDbm; | |
113 | } | |
869b4372 | 114 | EXPORT_SYMBOL(dot11d_get_max_tx_pwr_in_dbm); |
8fc8598e | 115 | |
e859737a | 116 | void dot11d_scan_complete(struct ieee80211_device *dev) |
8fc8598e | 117 | { |
b972c798 | 118 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); |
8fc8598e | 119 | |
b972c798 | 120 | switch (dot11d_info->state) { |
8fc8598e | 121 | case DOT11D_STATE_LEARNED: |
b972c798 | 122 | dot11d_info->state = DOT11D_STATE_DONE; |
8fc8598e JC |
123 | break; |
124 | ||
125 | case DOT11D_STATE_DONE: | |
c21ce6c7 AR |
126 | if (GET_CIE_WATCHDOG(dev) == 0) { |
127 | /* Reset country IE if previous one is gone. */ | |
6a184731 | 128 | dot11d_reset(dev); |
8fc8598e JC |
129 | } |
130 | break; | |
131 | case DOT11D_STATE_NONE: | |
132 | break; | |
133 | } | |
134 | } | |
e859737a | 135 | EXPORT_SYMBOL(dot11d_scan_complete); |
8fc8598e | 136 | |
b56b1438 | 137 | int is_legal_channel(struct ieee80211_device *dev, u8 channel) |
8fc8598e | 138 | { |
b972c798 | 139 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); |
8fc8598e | 140 | |
56c4a799 | 141 | if (channel > MAX_CHANNEL_NUMBER) { |
e13ff19e | 142 | netdev_err(dev->dev, "%s: Invalid Channel\n", __func__); |
8fc8598e JC |
143 | return 0; |
144 | } | |
b972c798 | 145 | if (dot11d_info->channel_map[channel] > 0) |
8fc8598e JC |
146 | return 1; |
147 | return 0; | |
148 | } | |
b56b1438 | 149 | EXPORT_SYMBOL(is_legal_channel); |
8fc8598e | 150 | |
f1d18719 | 151 | int to_legal_channel(struct ieee80211_device *dev, u8 channel) |
8fc8598e | 152 | { |
b972c798 | 153 | struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev); |
8fc8598e JC |
154 | u8 default_chn = 0; |
155 | u32 i = 0; | |
156 | ||
0d86eba5 | 157 | for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) { |
b972c798 | 158 | if (dot11d_info->channel_map[i] > 0) { |
8fc8598e JC |
159 | default_chn = i; |
160 | break; | |
161 | } | |
162 | } | |
163 | ||
56c4a799 | 164 | if (channel > MAX_CHANNEL_NUMBER) { |
e13ff19e | 165 | netdev_err(dev->dev, "%s: Invalid Channel\n", __func__); |
8fc8598e JC |
166 | return default_chn; |
167 | } | |
168 | ||
b972c798 | 169 | if (dot11d_info->channel_map[channel] > 0) |
8fc8598e JC |
170 | return channel; |
171 | ||
172 | return default_chn; | |
173 | } | |
f1d18719 | 174 | EXPORT_SYMBOL(to_legal_channel); |