dhd: rename 100.10.315.x to 100.10.545.x
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.100.10.545.x / wl_roam.c
CommitLineData
d2839953
RC
1/*
2 * Linux roam cache
3 *
965f77c4 4 * Copyright (C) 1999-2019, Broadcom.
d2839953
RC
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
965f77c4 27 * $Id: wl_roam.c 798173 2019-01-07 09:23:21Z $
d2839953
RC
28 */
29
30#include <typedefs.h>
31#include <osl.h>
32#include <bcmwifi_channels.h>
33#include <wlioctl.h>
34#include <bcmutils.h>
35#ifdef WL_CFG80211
36#include <wl_cfg80211.h>
37#endif // endif
38#include <wldev_common.h>
965f77c4 39#include <bcmstdlib_s.h>
d2839953
RC
40
41#ifdef ESCAN_CHANNEL_CACHE
42#define MAX_ROAM_CACHE 200
43#define MAX_SSID_BUFSIZE 36
44
45#define ROAMSCAN_MODE_NORMAL 0
46#define ROAMSCAN_MODE_WES 1
47
48typedef struct {
49 chanspec_t chanspec;
50 int ssid_len;
51 char ssid[MAX_SSID_BUFSIZE];
52} roam_channel_cache;
53
54static int n_roam_cache = 0;
55static int roam_band = WLC_BAND_AUTO;
56static roam_channel_cache roam_cache[MAX_ROAM_CACHE];
57static uint band2G, band5G, band_bw;
58
59#ifdef ROAM_CHANNEL_CACHE
60int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver)
61{
62 int err;
63 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
64 s32 mode;
65
66 /* Check support in firmware */
67 err = wldev_iovar_getint(dev, "roamscan_mode", &mode);
68 if (err && (err == BCME_UNSUPPORTED)) {
69 /* If firmware doesn't support, return error. Else proceed */
70 WL_ERR(("roamscan_mode iovar failed. %d\n", err));
71 return err;
72 }
73
74#ifdef D11AC_IOTYPES
75 if (ioctl_ver == 1) {
76 /* legacy chanspec */
77 band2G = WL_LCHANSPEC_BAND_2G;
78 band5G = WL_LCHANSPEC_BAND_5G;
79 band_bw = WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
80 } else {
81 band2G = WL_CHANSPEC_BAND_2G;
82 band5G = WL_CHANSPEC_BAND_5G;
83 band_bw = WL_CHANSPEC_BW_20;
84 }
85#else
86 band2G = WL_CHANSPEC_BAND_2G;
87 band5G = WL_CHANSPEC_BAND_5G;
88 band_bw = WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
89#endif /* D11AC_IOTYPES */
90
91 n_roam_cache = 0;
92 roam_band = WLC_BAND_AUTO;
93
94 return 0;
95}
96#endif /* ROAM_CHANNEL_CACHE */
97
98#ifdef ESCAN_CHANNEL_CACHE
99void set_roam_band(int band)
100{
101 roam_band = band;
102}
103
104void reset_roam_cache(struct bcm_cfg80211 *cfg)
105{
106 if (!cfg->rcc_enabled) {
107 return;
108 }
109
110 n_roam_cache = 0;
111}
112
113void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi)
114{
115 int i;
116 uint8 channel;
117 char chanbuf[CHANSPEC_STR_LEN];
118
119 if (!cfg->rcc_enabled) {
120 return;
121 }
122
123 if (n_roam_cache >= MAX_ROAM_CACHE)
124 return;
125
126 for (i = 0; i < n_roam_cache; i++) {
127 if ((roam_cache[i].ssid_len == bi->SSID_len) &&
128 (roam_cache[i].chanspec == bi->chanspec) &&
129 (memcmp(roam_cache[i].ssid, bi->SSID, bi->SSID_len) == 0)) {
130 /* identical one found, just return */
131 return;
132 }
133 }
134
135 roam_cache[n_roam_cache].ssid_len = bi->SSID_len;
136 channel = wf_chspec_ctlchan(bi->chanspec);
137 WL_DBG(("CHSPEC = %s, CTL %d\n", wf_chspec_ntoa_ex(bi->chanspec, chanbuf), channel));
138 roam_cache[n_roam_cache].chanspec =
139 (channel <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw | channel;
965f77c4 140 (void)memcpy_s(roam_cache[n_roam_cache].ssid, bi->SSID_len, bi->SSID, bi->SSID_len);
d2839953
RC
141
142 n_roam_cache++;
143}
144
145static bool is_duplicated_channel(const chanspec_t *channels, int n_channels, chanspec_t new)
146{
147 int i;
148
149 for (i = 0; i < n_channels; i++) {
150 if (channels[i] == new)
151 return TRUE;
152 }
153
154 return FALSE;
155}
156
157int get_roam_channel_list(int target_chan,
158 chanspec_t *channels, int n_channels, const wlc_ssid_t *ssid, int ioctl_ver)
159{
160 int i, n = 1;
161 char chanbuf[CHANSPEC_STR_LEN];
162
163 /* first index is filled with the given target channel */
164 if (target_chan) {
165 channels[0] = (target_chan & WL_CHANSPEC_CHAN_MASK) |
166 (target_chan <= CH_MAX_2G_CHANNEL ? band2G : band5G) | band_bw;
167 } else {
168 /* If target channel is not provided, set the index to 0 */
169 n = 0;
170 }
171
172 WL_DBG((" %s: %03d 0x%04X\n", __FUNCTION__, target_chan, channels[0]));
173
174 for (i = 0; i < n_roam_cache; i++) {
175 chanspec_t ch = roam_cache[i].chanspec;
176 bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch);
177 bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch);
178 bool band_match = ((roam_band == WLC_BAND_AUTO) ||
179 ((roam_band == WLC_BAND_2G) && is_2G) ||
180 ((roam_band == WLC_BAND_5G) && is_5G));
181
182 ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw;
183 if ((roam_cache[i].ssid_len == ssid->SSID_len) &&
184 band_match && !is_duplicated_channel(channels, n, ch) &&
185 (memcmp(roam_cache[i].ssid, ssid->SSID, ssid->SSID_len) == 0)) {
186 /* match found, add it */
187 WL_DBG(("%s: Chanspec = %s\n", __FUNCTION__,
188 wf_chspec_ntoa_ex(ch, chanbuf)));
189 channels[n++] = ch;
190 if (n >= n_channels) {
191 WL_ERR(("Too many roam scan channels\n"));
192 return n;
193 }
194 }
195 }
196
197 return n;
198}
199#endif /* ESCAN_CHANNEL_CACHE */
200
201#ifdef ROAM_CHANNEL_CACHE
202void print_roam_cache(struct bcm_cfg80211 *cfg)
203{
204 int i;
205
206 if (!cfg->rcc_enabled) {
207 return;
208 }
209
210 WL_DBG((" %d cache\n", n_roam_cache));
211
212 for (i = 0; i < n_roam_cache; i++) {
213 roam_cache[i].ssid[roam_cache[i].ssid_len] = 0;
214 WL_DBG(("0x%02X %02d %s\n", roam_cache[i].chanspec,
215 roam_cache[i].ssid_len, roam_cache[i].ssid));
216 }
217}
218
219static void add_roamcache_channel(wl_roam_channel_list_t *channels, chanspec_t ch)
220{
221 int i;
222
223 if (channels->n >= MAX_ROAM_CHANNEL) /* buffer full */
224 return;
225
226 for (i = 0; i < channels->n; i++) {
227 if (channels->channels[i] == ch) /* already in the list */
228 return;
229 }
230
231 channels->channels[i] = ch;
232 channels->n++;
233
234 WL_DBG((" RCC: %02d 0x%04X\n",
235 ch & WL_CHANSPEC_CHAN_MASK, ch));
236}
237
238void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver)
239{
240 int error, i, prev_channels;
241 wl_roam_channel_list_t channel_list;
242 char iobuf[WLC_IOCTL_SMLEN];
243 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
244 wlc_ssid_t ssid;
245
246 if (!cfg->rcc_enabled) {
247 return;
248 }
249
250 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
251 WL_DBG(("Not associated\n"));
252 return;
253 }
254
255 /* need to read out the current cache list
256 as the firmware may change dynamically
257 */
258 error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
259 (void *)&channel_list, sizeof(channel_list), NULL);
260 if (error) {
261 WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
262 return;
263 }
264
265 error = wldev_get_ssid(dev, &ssid);
266 if (error) {
267 WL_ERR(("Failed to get SSID, err=%d\n", error));
268 return;
269 }
270
271 prev_channels = channel_list.n;
272 for (i = 0; i < n_roam_cache; i++) {
273 chanspec_t ch = roam_cache[i].chanspec;
274 bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch);
275 bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(ch) : CHSPEC_IS5G(ch);
276 bool band_match = ((roam_band == WLC_BAND_AUTO) ||
277 ((roam_band == WLC_BAND_2G) && is_2G) ||
278 ((roam_band == WLC_BAND_5G) && is_5G));
279
280 if ((roam_cache[i].ssid_len == ssid.SSID_len) &&
281 band_match && (memcmp(roam_cache[i].ssid, ssid.SSID, ssid.SSID_len) == 0)) {
282 /* match found, add it */
283 ch = CHSPEC_CHANNEL(ch) | (is_2G ? band2G : band5G) | band_bw;
284 add_roamcache_channel(&channel_list, ch);
285 }
286 }
287 if (prev_channels != channel_list.n) {
288 /* channel list updated */
289 error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
290 sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
291 if (error) {
292 WL_ERR(("Failed to update roamscan channels, error = %d\n", error));
293 }
294 }
295
296 WL_DBG(("%d AP, %d cache item(s), err=%d\n", n_roam_cache, channel_list.n, error));
297}
298
299void wl_update_roamscan_cache_by_band(struct net_device *dev, int band)
300{
301 int i, error, ioctl_ver, wes_mode;
302 wl_roam_channel_list_t chanlist_before, chanlist_after;
303 char iobuf[WLC_IOCTL_SMLEN];
304
305 roam_band = band;
306
307 error = wldev_iovar_getint(dev, "roamscan_mode", &wes_mode);
308 if (error) {
309 WL_ERR(("Failed to get roamscan mode, error = %d\n", error));
310 return;
311 }
312
313 ioctl_ver = wl_cfg80211_get_ioctl_version();
314 /* in case of WES mode, update channel list by band based on the cache in DHD */
315 if (wes_mode) {
316 int n = 0;
317 chanlist_before.n = n_roam_cache;
318
319 for (n = 0; n < n_roam_cache; n++) {
320 chanspec_t ch = roam_cache[n].chanspec;
321 bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(ch) : CHSPEC_IS2G(ch);
322 chanlist_before.channels[n] = CHSPEC_CHANNEL(ch) |
323 (is_2G ? band2G : band5G) | band_bw;
324 }
325 } else {
326 if (band == WLC_BAND_AUTO) {
327 return;
328 }
329 error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
330 (void *)&chanlist_before, sizeof(wl_roam_channel_list_t), NULL);
331 if (error) {
332 WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
333 return;
334 }
335 }
336 chanlist_after.n = 0;
337 /* filtering by the given band */
338 for (i = 0; i < chanlist_before.n; i++) {
339 chanspec_t chspec = chanlist_before.channels[i];
340 bool is_2G = ioctl_ver == 1 ? LCHSPEC_IS2G(chspec) : CHSPEC_IS2G(chspec);
341 bool is_5G = ioctl_ver == 1 ? LCHSPEC_IS5G(chspec) : CHSPEC_IS5G(chspec);
342 bool band_match = ((band == WLC_BAND_AUTO) ||
343 ((band == WLC_BAND_2G) && is_2G) ||
344 ((band == WLC_BAND_5G) && is_5G));
345 if (band_match) {
346 chanlist_after.channels[chanlist_after.n++] = chspec;
347 }
348 }
349
350 if (wes_mode) {
351 /* need to set ROAMSCAN_MODE_NORMAL to update roamscan_channels,
352 * otherwise, it won't be updated
353 */
354 wldev_iovar_setint(dev, "roamscan_mode", ROAMSCAN_MODE_NORMAL);
355
356 error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after,
357 sizeof(wl_roam_channel_list_t), iobuf, sizeof(iobuf), NULL);
358 if (error) {
359 WL_ERR(("Failed to update roamscan channels, error = %d\n", error));
360 }
361 wldev_iovar_setint(dev, "roamscan_mode", ROAMSCAN_MODE_WES);
362 } else {
363 if (chanlist_before.n == chanlist_after.n) {
364 return;
365 }
366 error = wldev_iovar_setbuf(dev, "roamscan_channels", &chanlist_after,
367 sizeof(wl_roam_channel_list_t), iobuf, sizeof(iobuf), NULL);
368 if (error) {
369 WL_ERR(("Failed to update roamscan channels, error = %d\n", error));
370 }
371 }
372}
373#endif /* ROAM_CHANNEL_CACHE */
374#endif /* ESCAN_CHANNEL_CACHE */