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