Merge tag 'rust-fixes-6.3-rc1' of https://github.com/Rust-for-Linux/linux
[linux-block.git] / drivers / staging / rtl8192u / ieee80211 / dot11d.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
c21ce6c7 2/* Implement 802.11d. */
8fc8598e
JC
3
4#include "dot11d.h"
5
9003987a 6void 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 18EXPORT_SYMBOL(rtl8192u_dot11d_init);
8fc8598e 19
c21ce6c7 20/* Reset to the state as we are just entering a regulatory domain. */
6a184731 21void 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 39EXPORT_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 50void 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 98EXPORT_SYMBOL(dot11d_update_country_ie);
8fc8598e 99
869b4372 100u8 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 114EXPORT_SYMBOL(dot11d_get_max_tx_pwr_in_dbm);
8fc8598e 115
e859737a 116void 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 135EXPORT_SYMBOL(dot11d_scan_complete);
8fc8598e 136
b56b1438 137int 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 149EXPORT_SYMBOL(is_legal_channel);
8fc8598e 150
f1d18719 151int 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 174EXPORT_SYMBOL(to_legal_channel);