Commit | Line | Data |
---|---|---|
cc6398c8 TK |
1 | /****************************************************************************** |
2 | * | |
3 | * Copyright (c) 2012 - 2020 Samsung Electronics Co., Ltd. All rights reserved | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | #include <linux/delay.h> | |
8 | #include <linux/firmware.h> | |
9 | #include <scsc/kic/slsi_kic_lib.h> | |
10 | ||
11 | #if defined(CONFIG_ARCH_EXYNOS) || defined(CONFIG_ARCH_EXYNOS9) | |
12 | #include <linux/soc/samsung/exynos-soc.h> | |
13 | #endif | |
14 | ||
15 | #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER | |
16 | #include <linux/if_ether.h> | |
17 | #include <linux/in.h> | |
18 | #endif | |
19 | ||
20 | #include <scsc/scsc_mx.h> | |
21 | #include <scsc/scsc_release.h> | |
22 | #include "mgt.h" | |
23 | #include "debug.h" | |
24 | #include "mlme.h" | |
25 | #include "netif.h" | |
26 | #include "utils.h" | |
27 | #include "udi.h" | |
28 | #include "log_clients.h" | |
29 | #ifdef SLSI_TEST_DEV | |
30 | #include "unittest.h" | |
31 | #endif | |
32 | #include "hip.h" | |
33 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
34 | #include <scsc/scsc_log_collector.h> | |
35 | #endif | |
36 | ||
37 | #include "procfs.h" | |
38 | #include "mib.h" | |
39 | #include "unifiio.h" | |
40 | #include "ba.h" | |
41 | #include "scsc_wifi_fcq.h" | |
42 | #include "cac.h" | |
43 | #include "cfg80211_ops.h" | |
44 | #include "nl80211_vendor.h" | |
45 | ||
46 | #ifdef CONFIG_SCSC_WLBTD | |
47 | #include "scsc_wlbtd.h" | |
48 | #endif | |
49 | #define CSR_WIFI_SME_MIB2_HOST_PSID_MASK 0x8000 | |
50 | #define SLSI_DEFAULT_HW_MAC_ADDR "\x00\x00\x0F\x11\x22\x33" | |
51 | #define MX_WLAN_FILE_PATH_LEN_MAX (128) | |
52 | #define SLSI_MIB_REG_RULES_MAX (50) | |
53 | #define SLSI_MIB_MAX_CLIENT (10) | |
54 | #define SLSI_REG_PARAM_START_INDEX (1) | |
55 | ||
56 | #ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL | |
57 | /* To do Autogen for this mib later */ | |
58 | #define SLSI_PSID_UNIFI_ARP_OUTSTANDING_MAX 0x0A1E | |
59 | #endif | |
60 | ||
61 | static char *mib_file_t = "wlan_t.hcf"; | |
62 | module_param(mib_file_t, charp, S_IRUGO | S_IWUSR); | |
63 | MODULE_PARM_DESC(mib_file_t, "mib data filename"); | |
64 | ||
65 | static char *mib_file2_t = "wlan_t_sw.hcf"; | |
66 | module_param(mib_file2_t, charp, S_IRUGO | S_IWUSR); | |
67 | MODULE_PARM_DESC(mib_file2_t, "mib data filename"); | |
68 | ||
69 | /* MAC address override. If set to FF's, then | |
70 | * the address is taken from config files or | |
71 | * default derived from HW ID. | |
72 | */ | |
73 | static char mac_addr_override[] = "ff:ff:ff:ff:ff:ff"; | |
74 | module_param_string(mac_addr, mac_addr_override, sizeof(mac_addr_override), S_IRUGO | S_IWUSR); | |
75 | MODULE_PARM_DESC(mac_addr_override, "WLAN MAC address override"); | |
76 | ||
77 | static int slsi_mib_open_file(struct slsi_dev *sdev, struct slsi_dev_mib_info *mib_info, const struct firmware **fw); | |
78 | static int slsi_mib_close_file(struct slsi_dev *sdev, const struct firmware *e); | |
79 | static int slsi_mib_download_file(struct slsi_dev *sdev, struct slsi_dev_mib_info *mib_info); | |
80 | static int slsi_country_to_index(struct slsi_802_11d_reg_domain *domain_info, const char *alpha2); | |
81 | static int slsi_mib_initial_get(struct slsi_dev *sdev); | |
82 | static int slsi_hanged_event_count; | |
83 | #ifdef CONFIG_SCSC_WLAN_WIFI_SHARING | |
84 | #define SLSI_MAX_CHAN_5G_BAND 25 | |
85 | #define SLSI_2G_CHANNEL_ONE 2412 | |
86 | #endif | |
87 | ||
88 | /* MAC address override stored in /sys/wifi/mac_addr */ | |
89 | static ssize_t sysfs_show_macaddr(struct kobject *kobj, struct kobj_attribute *attr, | |
90 | char *buf); | |
91 | static ssize_t sysfs_store_macaddr(struct kobject *kobj, struct kobj_attribute *attr, | |
92 | const char *buf, size_t count); | |
93 | ||
94 | static struct kobject *wifi_kobj_ref; | |
95 | static char sysfs_mac_override[] = "ff:ff:ff:ff:ff:ff"; | |
96 | static struct kobj_attribute mac_attr = __ATTR(mac_addr, 0660, sysfs_show_macaddr, sysfs_store_macaddr); | |
97 | ||
98 | /* Retrieve mac address in sysfs global */ | |
99 | static ssize_t sysfs_show_macaddr(struct kobject *kobj, | |
100 | struct kobj_attribute *attr, | |
101 | char *buf) | |
102 | { | |
103 | return snprintf(buf, sizeof(sysfs_mac_override), "%s", sysfs_mac_override); | |
104 | } | |
105 | ||
106 | /* Update mac address in sysfs global */ | |
107 | static ssize_t sysfs_store_macaddr(struct kobject *kobj, | |
108 | struct kobj_attribute *attr, | |
109 | const char *buf, | |
110 | size_t count) | |
111 | { | |
112 | int r; | |
113 | ||
114 | SLSI_INFO_NODEV("Override WLAN MAC address %s\n", buf); | |
115 | ||
116 | /* size of macaddr string */ | |
117 | r = sscanf(buf, "%17s", (char *)&sysfs_mac_override); | |
118 | return (r > 0) ? count : 0; | |
119 | } | |
120 | ||
121 | /* Register sysfs mac address override */ | |
122 | void slsi_create_sysfs_macaddr(void) | |
123 | { | |
124 | #ifndef SLSI_TEST_DEV | |
125 | int r; | |
126 | ||
127 | wifi_kobj_ref = mxman_wifi_kobject_ref_get(); | |
128 | pr_info("wifi_kobj_ref: 0x%p\n", wifi_kobj_ref); | |
129 | ||
130 | if (wifi_kobj_ref) { | |
131 | /* Create sysfs file /sys/wifi/mac_addr */ | |
132 | r = sysfs_create_file(wifi_kobj_ref, &mac_attr.attr); | |
133 | if (r) { | |
134 | /* Failed, so clean up dir */ | |
135 | pr_err("Can't create /sys/wifi/mac_addr\n"); | |
136 | return; | |
137 | } | |
138 | } else { | |
139 | pr_err("failed to create /sys/wifi/mac_addr\n"); | |
140 | } | |
141 | #endif | |
142 | } | |
143 | ||
144 | /* Unregister sysfs mac address override */ | |
145 | void slsi_destroy_sysfs_macaddr(void) | |
146 | { | |
147 | if (!wifi_kobj_ref) | |
148 | return; | |
149 | ||
150 | /* Destroy /sys/wifi/mac_addr file */ | |
151 | sysfs_remove_file(wifi_kobj_ref, &mac_attr.attr); | |
152 | ||
153 | /* Destroy /sys/wifi virtual dir */ | |
154 | mxman_wifi_kobject_ref_put(); | |
155 | } | |
156 | ||
157 | void slsi_purge_scan_results_locked(struct netdev_vif *ndev_vif, u16 scan_id) | |
158 | { | |
159 | struct slsi_scan_result *scan_result; | |
160 | struct slsi_scan_result *prev = NULL; | |
161 | ||
162 | scan_result = ndev_vif->scan[scan_id].scan_results; | |
163 | while (scan_result) { | |
164 | slsi_kfree_skb(scan_result->beacon); | |
165 | slsi_kfree_skb(scan_result->probe_resp); | |
166 | prev = scan_result; | |
167 | scan_result = scan_result->next; | |
168 | kfree(prev); | |
169 | } | |
170 | ndev_vif->scan[scan_id].scan_results = NULL; | |
171 | } | |
172 | ||
173 | void slsi_purge_scan_results(struct netdev_vif *ndev_vif, u16 scan_id) | |
174 | { | |
175 | SLSI_MUTEX_LOCK(ndev_vif->scan_result_mutex); | |
176 | slsi_purge_scan_results_locked(ndev_vif, scan_id); | |
177 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_result_mutex); | |
178 | } | |
179 | ||
180 | struct sk_buff *slsi_dequeue_cached_scan_result(struct slsi_scan *scan, int *count) | |
181 | { | |
182 | struct sk_buff *skb = NULL; | |
183 | struct slsi_scan_result *scan_result = scan->scan_results; | |
184 | ||
185 | if (scan_result) { | |
186 | if (scan_result->beacon) { | |
187 | skb = scan_result->beacon; | |
188 | scan_result->beacon = NULL; | |
189 | } else if (scan_result->probe_resp) { | |
190 | skb = scan_result->probe_resp; | |
191 | scan_result->probe_resp = NULL; | |
192 | } else { | |
193 | SLSI_ERR_NODEV("Scan entry with no beacon /probe resp!!\n"); | |
194 | } | |
195 | ||
196 | /*If beacon and probe response indicated above , remove the entry*/ | |
197 | if (!scan_result->beacon && !scan_result->probe_resp) { | |
198 | scan->scan_results = scan_result->next; | |
199 | kfree(scan_result); | |
200 | if (count) | |
201 | (*count)++; | |
202 | } | |
203 | } | |
204 | return skb; | |
205 | } | |
206 | ||
207 | void slsi_get_hw_mac_address(struct slsi_dev *sdev, u8 *addr) | |
208 | { | |
209 | #ifndef SLSI_TEST_DEV | |
210 | const struct firmware *e = NULL; | |
211 | int i; | |
212 | u32 u[ETH_ALEN]; | |
213 | char path_name[MX_WLAN_FILE_PATH_LEN_MAX]; | |
214 | int r; | |
cc66ecb0 | 215 | bool valid = false; |
216 | //BEGIN IKKANE-6 | |
217 | #ifdef MOTO_UTAGS_MAC | |
218 | struct device_node *chosen_node = NULL; | |
219 | //Moto, read MACs from bootparams | |
220 | chosen_node = of_find_node_by_name(NULL, "chosen"); | |
221 | if (!chosen_node) { | |
222 | SLSI_ERR(sdev, "%s: get chosen node read failed\n", __func__); | |
223 | goto mac_ss; | |
224 | } else { | |
225 | int len=0; | |
226 | const char *cmd_line = NULL; | |
227 | cmd_line = of_get_property(chosen_node, "bootargs", &len); | |
228 | if (!cmd_line || len <= 0) { | |
229 | SLSI_ERR(sdev, "%s: get wlan MACs bootargs failed\n", __func__); | |
230 | goto mac_ss; | |
231 | } else { | |
232 | char * mac_idx = NULL; | |
233 | mac_idx = strstr(cmd_line, WIFI_MAC_BOOTARG); | |
234 | if (mac_idx == NULL) { | |
235 | SLSI_ERR(sdev, "%s: " WIFI_MAC_BOOTARG " not present in bootargs", __func__); | |
236 | goto mac_ss; | |
237 | } else { | |
238 | char macStr[MACSTRLEN+1] = {0}; | |
239 | // extract MAC from boot params | |
240 | mac_idx += strlen(WIFI_MAC_BOOTARG); | |
241 | memcpy(macStr, mac_idx, MACSTRLEN); | |
242 | sscanf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", | |
2331bbba | 243 | &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]); |
cc66ecb0 | 244 | for (i = 0; i < ETH_ALEN; i++) |
245 | addr[i] = u[i] & 0xff; | |
246 | SLSI_INFO(sdev, "WiFi MAC address loaded from utag: %02X:%02X:%02X:%02X:%02X:%02X\n", | |
247 | u[0], u[1], u[2], u[3], u[4], u[5]); | |
248 | } | |
249 | } | |
cc6398c8 | 250 | } |
cc66ecb0 | 251 | return; |
252 | mac_ss: | |
253 | #endif | |
254 | //END IKKANE-6 | |
255 | ||
256 | /* Module parameter override */ | |
257 | r = sscanf(mac_addr_override, "%02X:%02X:%02X:%02X:%02X:%02X", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]); | |
258 | if (r != ETH_ALEN) { | |
259 | SLSI_ERR(sdev, "mac_addr modparam set, but format is incorrect (should be e.g. xx:xx:xx:xx:xx:xx)\n"); | |
260 | goto mac_sysfs; | |
261 | } | |
262 | for (i = 0; i < ETH_ALEN; i++) { | |
263 | if (u[i] != 0xff) | |
264 | valid = true; | |
265 | addr[i] = u[i] & 0xff; | |
266 | } | |
cc6398c8 TK |
267 | |
268 | /* If the override is valid, use it */ | |
269 | if (valid) { | |
270 | SLSI_INFO(sdev, "MAC address from modparam: %02X:%02X:%02X:%02X:%02X:%02X\n", | |
271 | u[0], u[1], u[2], u[3], u[4], u[5]); | |
272 | return; | |
273 | } | |
274 | ||
275 | /* Sysfs parameter override */ | |
276 | mac_sysfs: | |
277 | r = sscanf(sysfs_mac_override, "%02X:%02X:%02X:%02X:%02X:%02X", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]); | |
278 | if (r != ETH_ALEN) { | |
279 | SLSI_ERR(sdev, "mac_addr in sysfs set, but format is incorrect (should be e.g. xx:xx:xx:xx:xx:xx)\n"); | |
280 | goto mac_file; | |
281 | } | |
282 | for (i = 0; i < ETH_ALEN; i++) { | |
283 | if (u[i] != 0xff) | |
284 | valid = true; | |
285 | addr[i] = u[i] & 0xff; | |
286 | } | |
287 | ||
288 | /* If the override is valid, use it */ | |
289 | if (valid) { | |
290 | SLSI_INFO(sdev, "MAC address from sysfs: %02X:%02X:%02X:%02X:%02X:%02X\n", | |
291 | u[0], u[1], u[2], u[3], u[4], u[5]); | |
292 | return; | |
293 | } | |
294 | ||
295 | /* read mac.txt */ | |
296 | mac_file: | |
297 | if (sdev->maddr_file_name) { | |
298 | scnprintf(path_name, MX_WLAN_FILE_PATH_LEN_MAX, "wlan/%s", sdev->maddr_file_name); | |
299 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "MAC address file : %s\n", path_name); | |
300 | ||
301 | r = mx140_file_request_device_conf(sdev->maxwell_core, &e, path_name); | |
302 | if (r != 0) | |
303 | goto mac_efs; | |
304 | ||
305 | if (!e) { | |
306 | SLSI_ERR(sdev, "mx140_file_request_device_conf() returned succes, but firmware was null\n"); | |
307 | goto mac_efs; | |
308 | } | |
309 | r = sscanf(e->data, "%02X:%02X:%02X:%02X:%02X:%02X", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]); | |
310 | mx140_file_release_conf(sdev->maxwell_core, e); | |
311 | if (r != ETH_ALEN) { | |
312 | SLSI_ERR(sdev, "%s exists, but format is incorrect (should be e.g. xx:xx:xx:xx:xx:xx)\n", path_name); | |
313 | goto mac_efs; | |
314 | } | |
315 | for (i = 0; i < ETH_ALEN; i++) | |
316 | addr[i] = u[i] & 0xff; | |
317 | SLSI_INFO(sdev, "MAC address loaded from %s: %02X:%02X:%02X:%02X:%02X:%02X\n", path_name, u[0], u[1], u[2], u[3], u[4], u[5]); | |
318 | return; | |
319 | } | |
320 | mac_efs: | |
321 | #ifdef CONFIG_SCSC_WLAN_MAC_ADDRESS_FILENAME | |
322 | r = mx140_request_file(sdev->maxwell_core, CONFIG_SCSC_WLAN_MAC_ADDRESS_FILENAME, &e); | |
323 | if (r != 0) | |
324 | goto mac_default; | |
325 | if (!e) { | |
326 | SLSI_ERR(sdev, "mx140_request_file() returned succes, but firmware was null\n"); | |
327 | goto mac_default; | |
328 | } | |
329 | r = sscanf(e->data, "%02X:%02X:%02X:%02X:%02X:%02X", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]); | |
330 | if (r != ETH_ALEN) { | |
331 | SLSI_ERR(sdev, "%s exists, but format is incorrect (%d) [%20s] (should be e.g. xx:xx:xx:xx:xx:xx)\n", | |
332 | CONFIG_SCSC_WLAN_MAC_ADDRESS_FILENAME, r, e->data); | |
333 | goto mac_default; | |
334 | } | |
335 | for (i = 0; i < ETH_ALEN; i++) { | |
336 | if (u[i] != 0xff) | |
337 | valid = true; | |
338 | addr[i] = u[i] & 0xff; | |
339 | } | |
340 | #endif | |
341 | /* If MAC address seems valid, finished */ | |
342 | if (valid) { | |
343 | SLSI_INFO(sdev, "MAC address loaded from %s: %02X:%02X:%02X:%02X:%02X:%02X\n", | |
344 | CONFIG_SCSC_WLAN_MAC_ADDRESS_FILENAME, u[0], u[1], u[2], u[3], u[4], u[5]); | |
345 | ||
346 | /* MAC address read could hold invalid values, try to fix it to normal address */ | |
347 | if (addr[0] & 0x01) { | |
348 | addr[0] = addr[0] & 0xfe; | |
349 | SLSI_INFO(sdev, "MAC address invalid, fixed address: %pM\n", addr); | |
350 | } | |
351 | mx140_release_file(sdev->maxwell_core, e); | |
352 | return; | |
353 | } | |
354 | mac_default: | |
355 | /* This is safe to call, even if the struct firmware handle is NULL */ | |
356 | mx140_file_release_conf(sdev->maxwell_core, e); | |
357 | ||
358 | SLSI_ETHER_COPY(addr, SLSI_DEFAULT_HW_MAC_ADDR); | |
cc66ecb0 | 359 | //BEGIN IKKANE-6 |
360 | #ifdef MOTO_UTAGS_MAC | |
361 | /* Motorola OUI */ | |
362 | addr[0] = 0xF0; | |
363 | addr[1] = 0xD7; | |
364 | addr[2] = 0xAA; | |
365 | #endif | |
366 | //END IKKANE-6 | |
367 | ||
cc6398c8 TK |
368 | #if defined(CONFIG_ARCH_EXYNOS) || defined(CONFIG_ARCH_EXYNOS9) |
369 | /* Randomise MAC address from the soc uid */ | |
370 | addr[3] = (exynos_soc_info.unique_id & 0xFF0000000000) >> 40; | |
371 | addr[4] = (exynos_soc_info.unique_id & 0x00FF00000000) >> 32; | |
372 | addr[5] = (exynos_soc_info.unique_id & 0x0000FF000000) >> 24; | |
373 | #endif | |
374 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, | |
375 | "MAC addr file NOT found, using default MAC ADDR: %pM\n", addr); | |
376 | #else | |
377 | /* We use FIXED Mac addresses with the unittest driver */ | |
378 | struct slsi_test_dev *uftestdev = (struct slsi_test_dev *)sdev->maxwell_core; | |
379 | ||
380 | SLSI_ETHER_COPY(addr, uftestdev->hw_addr); | |
381 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "Test Device Address: %pM\n", addr); | |
382 | #endif | |
383 | } | |
384 | ||
385 | static void write_wifi_version_info_file(struct slsi_dev *sdev) | |
386 | { | |
387 | #if defined(SCSC_SEP_VERSION) && (SCSC_SEP_VERSION >= 90000) | |
388 | char *filepath = "/data/vendor/conn/.wifiver.info"; | |
389 | #else | |
390 | char *filepath = "/data/misc/conn/.wifiver.info"; | |
391 | #endif | |
392 | char buf[256]; | |
393 | char build_id_fw[128]; | |
394 | char build_id_drv[64]; | |
395 | ||
396 | #ifndef CONFIG_SCSC_WLBTD | |
397 | struct file *fp = NULL; | |
398 | ||
399 | fp = filp_open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0644); | |
400 | ||
401 | if (IS_ERR(fp)) { | |
402 | SLSI_WARN(sdev, "version file wasn't found\n"); | |
403 | return; | |
404 | } else if (!fp) { | |
405 | SLSI_WARN(sdev, "%s doesn't exist.\n", filepath); | |
406 | return; | |
407 | } | |
408 | #endif | |
409 | #ifndef SLSI_TEST_DEV | |
410 | mxman_get_fw_version(build_id_fw, 128); | |
411 | mxman_get_driver_version(build_id_drv, 64); | |
412 | #endif | |
413 | ||
414 | /* WARNING: | |
415 | * Please do not change the format of the following string | |
416 | * as it can have fatal consequences. | |
417 | * The framework parser for the version may depend on this | |
418 | * exact formatting. | |
419 | * | |
420 | * Also beware that SCSC_SEP_VERSION will not be defined in AOSP. | |
421 | */ | |
422 | #if defined(SCSC_SEP_VERSION) && (SCSC_SEP_VERSION >= 90000) | |
423 | /* P-OS */ | |
424 | snprintf(buf, sizeof(buf), | |
425 | "%s\n" /* drv_ver: already appended by mxman_get_driver_version() */ | |
426 | "f/w_ver: %s\n" | |
427 | "hcf_ver_hw: %s\n" | |
428 | "hcf_ver_sw: %s\n" | |
429 | "regDom_ver: %d.%d\n", | |
430 | build_id_drv, | |
431 | build_id_fw, | |
432 | sdev->mib[0].platform, | |
433 | sdev->mib[1].platform, | |
434 | ((sdev->reg_dom_version >> 8) & 0xFF), (sdev->reg_dom_version & 0xFF)); | |
435 | #else | |
436 | /* O-OS, or unknown */ | |
437 | snprintf(buf, sizeof(buf), | |
438 | "%s (f/w_ver: %s)\nregDom_ver: %d.%d\n", | |
439 | build_id_drv, | |
440 | build_id_fw, | |
441 | ((sdev->reg_dom_version >> 8) & 0xFF), (sdev->reg_dom_version & 0xFF)); | |
442 | #endif | |
443 | ||
444 | /* If SCSC_SEP_VERSION is not known, avoid writing the file, as it could go to the wrong | |
445 | * location. | |
446 | */ | |
447 | #ifdef SCSC_SEP_VERSION | |
448 | #ifdef CONFIG_SCSC_WLBTD | |
449 | wlbtd_write_file(filepath, buf); | |
450 | #else | |
451 | kernel_write(fp, buf, strlen(buf), 0); | |
452 | if (fp) | |
453 | filp_close(fp, NULL); | |
454 | #endif | |
455 | ||
456 | SLSI_INFO(sdev, "Succeed to write firmware/host information to .wifiver.info\n"); | |
457 | #else | |
458 | SLSI_UNUSED_PARAMETER(filepath); | |
459 | #endif | |
460 | } | |
461 | ||
462 | static void write_m_test_chip_version_file(struct slsi_dev *sdev) | |
463 | { | |
464 | #ifdef CONFIG_SCSC_WLBTD | |
465 | char *filepath = "/data/vendor/conn/.cid.info"; | |
466 | char buf[256]; | |
467 | ||
468 | snprintf(buf, sizeof(buf), "%s\n", SCSC_RELEASE_SOLUTION); | |
469 | ||
470 | wlbtd_write_file(filepath, buf); | |
471 | ||
472 | SLSI_WARN(sdev, "Wrote chip information to .cid.info\n"); | |
473 | #endif | |
474 | } | |
475 | ||
476 | ||
477 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
478 | int slsi_start_monitor_mode(struct slsi_dev *sdev, struct net_device *dev) | |
479 | { | |
480 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
481 | u8 device_address[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
482 | ||
483 | ndev_vif->vif_type = FAPI_VIFTYPE_MONITOR; | |
484 | ||
485 | if (slsi_mlme_add_vif(sdev, dev, dev->dev_addr, device_address) != 0) { | |
486 | SLSI_NET_ERR(dev, "add VIF for Monitor mode failed\n"); | |
487 | ndev_vif->vif_type = SLSI_VIFTYPE_UNSPECIFIED; | |
488 | return -EINVAL; | |
489 | } | |
490 | ||
491 | /* set the link type for the device; it depends on the format of | |
492 | * packet the firmware is going to Pass to Host. | |
493 | * | |
494 | * If the firmware passes MA data in 802.11 frame format, then | |
495 | * dev->type = ARPHRD_IEEE80211; | |
496 | * | |
497 | * If the firmware adds Radio TAP header to MA data, | |
498 | * dev->type = ARPHRD_IEEE80211_RADIOTAP; | |
499 | */ | |
500 | dev->type = ARPHRD_IEEE80211_RADIOTAP; | |
501 | ndev_vif->activated = true; | |
502 | return 0; | |
503 | } | |
504 | ||
505 | void slsi_stop_monitor_mode(struct slsi_dev *sdev, struct net_device *dev) | |
506 | { | |
507 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
508 | ||
509 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
510 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "de-activate monitor VIF\n"); | |
511 | slsi_mlme_del_vif(sdev, dev); | |
512 | slsi_vif_deactivated(sdev, dev); | |
513 | } | |
514 | #endif | |
515 | ||
516 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
517 | static int slsi_hcf_collect(struct scsc_log_collector_client *collect_client, size_t size) | |
518 | { | |
519 | struct slsi_dev *sdev = (struct slsi_dev *)collect_client->prv; | |
520 | int ret = 0; | |
521 | u8 index = sdev->collect_mib.num_files; | |
522 | u8 i; | |
523 | u8 *data; | |
524 | ||
525 | SLSI_INFO_NODEV("Collecting WLAN HCF\n"); | |
526 | ||
527 | if (!sdev->collect_mib.enabled) | |
528 | SLSI_INFO_NODEV("Collection not enabled\n"); | |
529 | ||
530 | spin_lock(&sdev->collect_mib.in_collection); | |
531 | ret = scsc_log_collector_write(&index, sizeof(char), 1); | |
532 | if (ret) { | |
533 | spin_unlock(&sdev->collect_mib.in_collection); | |
534 | return ret; | |
535 | } | |
536 | ||
537 | for (i = 0; i < index; i++) { | |
538 | SLSI_INFO_NODEV("Collecting WLAN HCF. File %s\n", sdev->collect_mib.file[i].file_name); | |
539 | /* Write file name */ | |
540 | ret = scsc_log_collector_write((char *)&sdev->collect_mib.file[i].file_name, 32, 1); | |
541 | if (ret) { | |
542 | spin_unlock(&sdev->collect_mib.in_collection); | |
543 | return ret; | |
544 | } | |
545 | /* Write file len */ | |
546 | ret = scsc_log_collector_write((char *)&sdev->collect_mib.file[i].len, sizeof(u16), 1); | |
547 | if (ret) { | |
548 | spin_unlock(&sdev->collect_mib.in_collection); | |
549 | return ret; | |
550 | } | |
551 | /* Write data */ | |
552 | data = sdev->collect_mib.file[i].data; | |
553 | if (!data) | |
554 | continue; | |
555 | ret = scsc_log_collector_write((char *)data, sdev->collect_mib.file[i].len, 1); | |
556 | if (ret) { | |
557 | spin_unlock(&sdev->collect_mib.in_collection); | |
558 | return ret; | |
559 | } | |
560 | } | |
561 | spin_unlock(&sdev->collect_mib.in_collection); | |
562 | ||
563 | return ret; | |
564 | } | |
565 | ||
566 | /* Collect client registration for HCF file*/ | |
567 | struct scsc_log_collector_client slsi_hcf_client = { | |
568 | .name = "wlan_hcf", | |
569 | .type = SCSC_LOG_CHUNK_WLAN_HCF, | |
570 | .collect_init = NULL, | |
571 | .collect = slsi_hcf_collect, | |
572 | .collect_end = NULL, | |
573 | .prv = NULL, | |
574 | }; | |
575 | #endif | |
576 | ||
577 | int slsi_start(struct slsi_dev *sdev) | |
578 | { | |
579 | #ifndef CONFIG_SCSC_DOWNLOAD_FILE | |
580 | const struct firmware *fw[SLSI_WLAN_MAX_MIB_FILE] = { NULL, NULL }; | |
581 | #endif | |
582 | int err = 0, r, reg_err = 0; | |
583 | int i; | |
584 | char alpha2[3]; | |
585 | #ifdef CONFIG_SCSC_WLAN_AP_INFO_FILE | |
586 | u32 offset = 0; | |
587 | struct file *fp = NULL; | |
588 | #if defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION >= 90000 | |
589 | char *filepath = "/data/vendor/conn/.softap.info"; | |
590 | #else | |
591 | char *filepath = "/data/misc/conn/.softap.info"; | |
592 | #endif | |
593 | char buf[512]; | |
594 | #endif | |
595 | #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA | |
596 | char *ant_file_path = "/data/vendor/conn/.ant.info"; | |
597 | char *antenna_file_path = "/data/vendor/wifi/antenna.info"; | |
598 | #endif | |
599 | ||
600 | if (WARN_ON(!sdev)) | |
601 | return -EINVAL; | |
602 | ||
603 | SLSI_MUTEX_LOCK(sdev->start_stop_mutex); | |
604 | ||
605 | slsi_wake_lock(&sdev->wlan_wl); | |
606 | ||
607 | if (sdev->device_state != SLSI_DEVICE_STATE_STOPPED) { | |
608 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "Device already started: device_state:%d\n", sdev->device_state); | |
609 | goto done; | |
610 | } | |
611 | ||
612 | if (!sdev->mac_changed) { | |
613 | slsi_reset_channel_flags(sdev); | |
614 | slsi_regd_init(sdev); | |
615 | } else { | |
616 | sdev->mac_changed = false; | |
617 | } | |
618 | ||
619 | if (sdev->recovery_status) { | |
620 | r = wait_for_completion_timeout(&sdev->recovery_completed, | |
621 | msecs_to_jiffies(sdev->recovery_timeout)); | |
622 | if (r == 0) | |
623 | SLSI_INFO(sdev, "recovery_completed timeout\n"); | |
624 | ||
625 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | |
626 | reinit_completion(&sdev->recovery_completed); | |
627 | #else | |
628 | /*This is how the macro is used in the older version.*/ | |
629 | INIT_COMPLETION(sdev->recovery_completed); | |
630 | #endif | |
631 | } | |
632 | ||
633 | sdev->device_state = SLSI_DEVICE_STATE_STARTING; | |
634 | sdev->require_service_close = false; | |
635 | ||
636 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | |
637 | reinit_completion(&sdev->sig_wait.completion); | |
638 | #else | |
639 | INIT_COMPLETION(sdev->sig_wait.completion); | |
640 | #endif | |
641 | ||
642 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Step [1/2]: Start WLAN service\n"); | |
643 | SLSI_EC_GOTO(slsi_sm_wlan_service_open(sdev), err, err_done); | |
644 | /** | |
645 | * Download MIB data, if any. | |
646 | */ | |
647 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Step [2/3]: Send MIB configuration\n"); | |
648 | ||
649 | sdev->local_mib.mib_hash = 0; /* Reset localmib hash value */ | |
650 | #ifndef SLSI_TEST_DEV | |
651 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
652 | spin_lock_init(&sdev->collect_mib.in_collection); | |
653 | sdev->collect_mib.num_files = 0; | |
654 | sdev->collect_mib.enabled = false; | |
655 | #endif | |
656 | #ifndef CONFIG_SCSC_DOWNLOAD_FILE | |
657 | /* The "_t" HCF is used in RF Test mode and wlanlite/production test mode */ | |
658 | if (slsi_is_rf_test_mode_enabled() || slsi_is_test_mode_enabled()) { | |
659 | sdev->mib[0].mib_file_name = mib_file_t; | |
660 | sdev->mib[1].mib_file_name = mib_file2_t; | |
661 | } else { | |
662 | sdev->mib[0].mib_file_name = slsi_mib_file; | |
663 | sdev->mib[1].mib_file_name = slsi_mib_file2; | |
664 | } | |
665 | ||
666 | /* Place MIB files in shared memory */ | |
667 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) { | |
668 | err = slsi_mib_open_file(sdev, &sdev->mib[i], &fw[i]); | |
669 | ||
670 | /* Only the first file is mandatory */ | |
671 | if (i == 0 && err) { | |
672 | SLSI_ERR(sdev, "mib: Mandatory wlan hcf missing. WLAN will not start (err=%d)\n", err); | |
673 | slsi_sm_wlan_service_close(sdev); | |
674 | goto err_done; | |
675 | } | |
676 | } | |
677 | ||
678 | err = slsi_sm_wlan_service_start(sdev); | |
679 | if (err) { | |
680 | SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); | |
681 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) | |
682 | slsi_mib_close_file(sdev, fw[i]); | |
683 | if (err != -EILSEQ) | |
684 | slsi_sm_wlan_service_close(sdev); | |
685 | goto err_done; | |
686 | } | |
687 | ||
688 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) | |
689 | slsi_mib_close_file(sdev, fw[i]); | |
690 | #else | |
691 | /* Download main MIB file via mlme_set */ | |
692 | err = slsi_sm_wlan_service_start(sdev); | |
693 | if (err) { | |
694 | SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); | |
695 | if (err != -EILSEQ) | |
696 | slsi_sm_wlan_service_close(sdev); | |
697 | goto err_done; | |
698 | } | |
699 | SLSI_EC_GOTO(slsi_mib_download_file(sdev, &sdev->mib), err, err_hip_started); | |
700 | #endif | |
701 | /* Always try to download optional localmib file via mlme_set, ignore error */ | |
702 | (void)slsi_mib_download_file(sdev, &sdev->local_mib); | |
703 | #endif | |
704 | /** | |
705 | * Download MIB data, if any. | |
706 | * Get f/w capabilities and default configuration | |
707 | * configure firmware | |
708 | */ | |
709 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
710 | sdev->device_config.rssi_boost_2g = 0; | |
711 | sdev->device_config.rssi_boost_5g = 0; | |
712 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
713 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Step [3/3]: Get MIB configuration\n"); | |
714 | SLSI_EC_GOTO(slsi_mib_initial_get(sdev), err, err_hip_started); | |
715 | SLSI_INFO(sdev, "=== Version info from the [MIB] ===\n"); | |
716 | SLSI_INFO(sdev, "HW Version : 0x%.4X (%u)\n", sdev->chip_info_mib.chip_version, sdev->chip_info_mib.chip_version); | |
717 | SLSI_INFO(sdev, "Platform : 0x%.4X (%u)\n", sdev->plat_info_mib.plat_build, sdev->plat_info_mib.plat_build); | |
718 | slsi_cfg80211_update_wiphy(sdev); | |
719 | ||
720 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
721 | sdev->device_config.host_state = SLSI_HOSTSTATE_CELLULAR_ACTIVE; | |
722 | reg_err = slsi_read_regulatory(sdev); | |
723 | if (reg_err) { | |
724 | SLSI_ERR(sdev, "Error in reading regulatory!\n"); | |
725 | /* Get UnifiCountryList */ | |
726 | err = slsi_read_unifi_countrylist(sdev, SLSI_PSID_UNIFI_COUNTRY_LIST); | |
727 | if (err) { | |
728 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
729 | goto err_hip_started; | |
730 | } | |
731 | } | |
732 | if (sdev->regdb.regdb_state == SLSI_REG_DB_SET) { | |
733 | sdev->reg_dom_version = ((sdev->regdb.db_major_version & 0xFF) << 8) | | |
734 | (sdev->regdb.db_minor_version & 0xFF); | |
735 | } | |
736 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
737 | ||
738 | if (!slsi_is_test_mode_enabled()) { | |
739 | err = slsi_mlme_set_country(sdev, sdev->device_config.domain_info.regdomain->alpha2); | |
740 | ||
741 | if (err < 0) | |
742 | goto err_hip_started; | |
743 | } | |
744 | ||
745 | memcpy(alpha2, sdev->device_config.domain_info.regdomain->alpha2, 2); | |
746 | ||
747 | /* unifiDefaultCountry != world_domain */ | |
748 | if (!(alpha2[0] == '0' && alpha2[1] == '0')) | |
749 | /* Read the regulatory params for the country*/ | |
750 | if (slsi_read_regulatory_rules(sdev, &sdev->device_config.domain_info, alpha2) == 0) { | |
751 | slsi_reset_channel_flags(sdev); | |
752 | wiphy_apply_custom_regulatory(sdev->wiphy, sdev->device_config.domain_info.regdomain); | |
753 | } | |
754 | /* Do nothing for unifiDefaultCountry == world_domain */ | |
755 | ||
756 | /* write .wifiver.info */ | |
757 | write_wifi_version_info_file(sdev); | |
758 | ||
759 | /* write .cid.info */ | |
760 | write_m_test_chip_version_file(sdev); | |
761 | ||
762 | #ifdef CONFIG_SCSC_WLAN_AP_INFO_FILE | |
763 | /* writing .softap.info in /data/vendor/conn */ | |
764 | fp = filp_open(filepath, O_WRONLY | O_CREAT, 0644); | |
765 | ||
766 | if (!fp) { | |
767 | WARN(1, "%s doesn't exist\n", filepath); | |
768 | } else if (IS_ERR(fp)) { | |
769 | WARN(1, "%s open returned error %d\n", filepath, IS_ERR(fp)); | |
770 | } else { | |
771 | offset = snprintf(buf + offset, sizeof(buf), "#softap.info\n"); | |
772 | offset += snprintf(buf + offset, sizeof(buf), "DualBandConcurrency=%s\n", sdev->dualband_concurrency ? "yes" : "no"); | |
773 | offset += snprintf(buf + offset, sizeof(buf), "DualInterface=%s\n", "yes"); | |
774 | offset += snprintf(buf + offset, sizeof(buf), "5G=%s\n", sdev->band_5g_supported ? "yes" : "no"); | |
775 | offset += snprintf(buf + offset, sizeof(buf), "maxClient=%d\n", !sdev->softap_max_client ? SLSI_MIB_MAX_CLIENT : sdev->softap_max_client); | |
776 | ||
777 | /* following are always supported */ | |
778 | offset += snprintf(buf + offset, sizeof(buf), "HalFn_setCountryCodeHal=yes\n"); | |
779 | offset += snprintf(buf + offset, sizeof(buf), "HalFn_getValidChannels=yes\n"); | |
780 | #ifdef CONFIG_SCSC_WLBTD | |
781 | wlbtd_write_file(filepath, buf); | |
782 | #else | |
783 | ||
784 | kernel_write(fp, buf, strlen(buf), 0); | |
785 | #endif | |
786 | if (fp) | |
787 | filp_close(fp, NULL); | |
788 | ||
789 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Succeed to write softap information to .softap.info\n"); | |
790 | } | |
791 | #endif | |
792 | ||
793 | #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA | |
794 | if (slsi_is_rf_test_mode_enabled()) { | |
795 | /* reading antenna mode from configured file /data/vendor/conn/.ant.info */ | |
796 | if (!(slsi_read_preferred_antenna_from_file(sdev, ant_file_path))) { | |
797 | /* reading antenna mode from configured file /data/vendor/wifi/antenna.info */ | |
798 | slsi_read_preferred_antenna_from_file(sdev, antenna_file_path); | |
799 | } | |
800 | } | |
801 | #endif | |
802 | ||
803 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
804 | /* Register with log collector to collect wlan hcf file */ | |
805 | slsi_hcf_client.prv = sdev; | |
806 | scsc_log_collector_register_client(&slsi_hcf_client); | |
807 | sdev->collect_mib.enabled = true; | |
808 | #endif | |
809 | slsi_update_supported_channels_regd_flags(sdev); | |
810 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "---Driver started successfully---\n"); | |
811 | sdev->device_state = SLSI_DEVICE_STATE_STARTED; | |
812 | memset(sdev->rtt_vif, -1, sizeof(sdev->rtt_vif)); | |
813 | #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY | |
814 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STARTED; | |
815 | #endif | |
816 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
817 | ||
818 | slsi_kic_system_event(slsi_kic_system_event_category_initialisation, | |
819 | slsi_kic_system_events_wifi_service_driver_started, GFP_KERNEL); | |
820 | ||
821 | slsi_wake_unlock(&sdev->wlan_wl); | |
822 | return err; | |
823 | ||
824 | err_hip_started: | |
825 | #ifndef SLSI_TEST_DEV | |
826 | slsi_sm_wlan_service_stop(sdev); | |
827 | slsi_hip_stop(sdev); | |
828 | slsi_sm_wlan_service_close(sdev); | |
829 | #endif | |
830 | ||
831 | err_done: | |
832 | sdev->device_state = SLSI_DEVICE_STATE_STOPPED; | |
833 | ||
834 | done: | |
835 | slsi_wake_unlock(&sdev->wlan_wl); | |
836 | ||
837 | slsi_kic_system_event(slsi_kic_system_event_category_initialisation, | |
838 | slsi_kic_system_events_wifi_on, GFP_KERNEL); | |
839 | ||
840 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
841 | return err; | |
842 | } | |
843 | ||
844 | #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA | |
845 | bool slsi_read_preferred_antenna_from_file(struct slsi_dev *sdev, char *antenna_file_path) | |
846 | { | |
847 | char ant_mode = '0'; | |
848 | u16 antenna = 0; | |
849 | struct file *file_ptr = NULL; | |
850 | ||
851 | file_ptr = filp_open(antenna_file_path, O_RDONLY, 0); | |
852 | if (!file_ptr || IS_ERR(file_ptr)) { | |
853 | SLSI_DBG1(sdev, SLSI_CFG80211, "%s open returned error %d\n", antenna_file_path, IS_ERR(file_ptr)); | |
854 | return false; | |
855 | } else { | |
856 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) | |
857 | kernel_read(file_ptr, &ant_mode, 1, &file_ptr->f_pos); | |
858 | #else | |
859 | kernel_read(file_ptr, file_ptr->f_pos, &ant_mode, 1); | |
860 | #endif | |
861 | antenna = ant_mode - '0'; | |
862 | filp_close(file_ptr, NULL); | |
863 | slsi_set_mib_preferred_antenna(sdev, antenna); | |
864 | return true; | |
865 | } | |
866 | } | |
867 | #endif | |
868 | ||
869 | struct net_device *slsi_dynamic_interface_create(struct wiphy *wiphy, | |
870 | const char *name, | |
871 | enum nl80211_iftype type, | |
872 | struct vif_params *params) | |
873 | { | |
874 | struct slsi_dev *sdev = SDEV_FROM_WIPHY(wiphy); | |
875 | struct net_device *dev = NULL; | |
876 | struct netdev_vif *ndev_vif = NULL; | |
877 | int err = -EINVAL; | |
878 | int iface; | |
879 | ||
880 | SLSI_DBG1(sdev, SLSI_CFG80211, "name:%s\n", name); | |
881 | ||
882 | iface = slsi_netif_dynamic_iface_add(sdev, name); | |
883 | if (iface < 0) | |
884 | return NULL; | |
885 | ||
886 | dev = slsi_get_netdev(sdev, iface); | |
887 | if (!dev) | |
888 | return NULL; | |
889 | ||
890 | ndev_vif = netdev_priv(dev); | |
891 | ||
892 | err = slsi_netif_register_rtlnl_locked(sdev, dev); | |
893 | if (err) | |
894 | return NULL; | |
895 | ||
896 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
897 | ndev_vif->iftype = type; | |
898 | dev->ieee80211_ptr->iftype = type; | |
899 | if (params) | |
900 | dev->ieee80211_ptr->use_4addr = params->use_4addr; | |
901 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
902 | ||
903 | return dev; | |
904 | } | |
905 | ||
906 | static void slsi_stop_chip(struct slsi_dev *sdev) | |
907 | { | |
908 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
909 | u8 index = sdev->collect_mib.num_files; | |
910 | u8 i; | |
911 | #endif | |
912 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(sdev->start_stop_mutex)); | |
913 | ||
914 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "netdev_up_count:%d device_state:%d\n", sdev->netdev_up_count, sdev->device_state); | |
915 | sdev->mac_changed = false; | |
916 | ||
917 | if (sdev->device_state != SLSI_DEVICE_STATE_STARTED) | |
918 | return; | |
919 | ||
920 | /* Only shutdown on the last device going down. */ | |
921 | if (sdev->netdev_up_count) | |
922 | return; | |
923 | ||
924 | complete_all(&sdev->sig_wait.completion); | |
925 | ||
926 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
927 | sdev->collect_mib.enabled = false; | |
928 | scsc_log_collector_unregister_client(&slsi_hcf_client); | |
929 | for (i = 0; i < index; i++) | |
930 | kfree(sdev->collect_mib.file[i].data); | |
931 | #endif | |
932 | ||
933 | sdev->device_state = SLSI_DEVICE_STATE_STOPPING; | |
934 | ||
935 | slsi_sm_wlan_service_stop(sdev); | |
936 | sdev->device_state = SLSI_DEVICE_STATE_STOPPED; | |
937 | ||
938 | slsi_hip_stop(sdev); | |
939 | #ifndef SLSI_TEST_DEV | |
940 | slsi_sm_wlan_service_close(sdev); | |
941 | #endif | |
942 | slsi_kic_system_event(slsi_kic_system_event_category_deinitialisation, | |
943 | slsi_kic_system_events_wifi_service_driver_stopped, GFP_KERNEL); | |
944 | ||
945 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
946 | sdev->mlme_blocked = false; | |
947 | ||
948 | slsi_kic_system_event(slsi_kic_system_event_category_deinitialisation, | |
949 | slsi_kic_system_events_wifi_off, GFP_KERNEL); | |
950 | ||
951 | slsi_dbg_track_skb_report(); | |
952 | slsi_dbg_track_skb_reset(); | |
953 | #ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL | |
954 | if (atomic_read(&sdev->arp_tx_count) && atomic_read(&sdev->ctrl_pause_state)) | |
955 | scsc_wifi_unpause_ctrl_q_all_vif(sdev); | |
956 | atomic_set(&sdev->arp_tx_count, 0); | |
957 | #endif | |
958 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
959 | } | |
960 | ||
961 | #ifdef CONFIG_SCSC_WIFI_NAN_ENABLE | |
962 | void slsi_ndl_vif_cleanup(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) | |
963 | { | |
964 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
965 | int i; | |
966 | struct slsi_peer *peer; | |
967 | u32 ndp_id; | |
968 | struct net_device *nan_mgmt_dev = slsi_nan_get_netdev(sdev); | |
969 | ||
970 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
971 | netif_carrier_off(dev); | |
972 | for (i = 0; i < SLSI_ADHOC_PEER_CONNECTIONS_MAX; i++) { | |
973 | peer = ndev_vif->peer_sta_record[i]; | |
974 | if (peer && peer->valid) { | |
975 | ndp_id = slsi_nan_get_ndp_from_ndl_local_ndi(nan_mgmt_dev, peer->ndl_vif, dev->dev_addr); | |
976 | slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); | |
977 | slsi_peer_remove(sdev, dev, peer); | |
978 | if (nan_mgmt_dev && ndp_id < SLSI_NAN_MAX_NDP_INSTANCES + 1) | |
979 | slsi_nan_ndp_del_entry(sdev, nan_mgmt_dev, ndp_id, true); | |
980 | } | |
981 | } | |
982 | } | |
983 | #endif | |
984 | void slsi_vif_cleanup(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) | |
985 | { | |
986 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
987 | int i; | |
988 | ||
989 | SLSI_NET_DBG3(dev, SLSI_INIT_DEINIT, "clean VIF\n"); | |
990 | ||
991 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
992 | #ifdef CONFIG_SCSC_WIFI_NAN_ENABLE | |
993 | if (ndev_vif->ifnum >= SLSI_NAN_DATA_IFINDEX_START) { | |
994 | slsi_ndl_vif_cleanup(sdev, dev, hw_available); | |
995 | return; | |
996 | } | |
997 | #endif | |
998 | if (ndev_vif->activated) { | |
999 | netif_carrier_off(dev); | |
1000 | for (i = 0; i < SLSI_ADHOC_PEER_CONNECTIONS_MAX; i++) { | |
1001 | struct slsi_peer *peer = ndev_vif->peer_sta_record[i]; | |
1002 | ||
1003 | if (peer && peer->valid) | |
1004 | slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); | |
1005 | } | |
1006 | ||
1007 | if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION) { | |
1008 | bool already_disconnected = false; | |
1009 | ||
1010 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Station active: hw_available=%d\n", hw_available); | |
1011 | if (hw_available) { | |
1012 | if (ndev_vif->sta.sta_bss) { | |
1013 | slsi_mlme_disconnect(sdev, dev, ndev_vif->sta.sta_bss->bssid, FAPI_REASONCODE_UNSPECIFIED_REASON, true); | |
1014 | slsi_handle_disconnect(sdev, dev, ndev_vif->sta.sta_bss->bssid, 0, NULL, 0); | |
1015 | already_disconnected = true; | |
1016 | } else { | |
1017 | slsi_mlme_del_vif(sdev, dev); | |
1018 | } | |
1019 | } | |
1020 | if (!already_disconnected) { | |
1021 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Calling slsi_vif_deactivated\n"); | |
1022 | slsi_vif_deactivated(sdev, dev); | |
1023 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) | |
1024 | cfg80211_disconnected(dev, FAPI_REASONCODE_UNSPECIFIED_REASON, NULL, 0, false, GFP_ATOMIC); | |
1025 | #else | |
1026 | cfg80211_disconnected(dev, FAPI_REASONCODE_UNSPECIFIED_REASON, NULL, 0, GFP_ATOMIC); | |
1027 | #endif | |
1028 | } | |
1029 | } else if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) { | |
1030 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "AP active\n"); | |
1031 | if (hw_available) { | |
1032 | struct slsi_peer *peer; | |
1033 | int j = 0; | |
1034 | ||
1035 | while (j < SLSI_PEER_INDEX_MAX) { | |
1036 | peer = ndev_vif->peer_sta_record[j]; | |
1037 | if (peer && peer->valid) | |
1038 | slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); | |
1039 | ++j; | |
1040 | } | |
1041 | slsi_mlme_del_vif(sdev, dev); | |
1042 | } | |
1043 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Calling slsi_vif_deactivated\n"); | |
1044 | slsi_vif_deactivated(sdev, dev); | |
1045 | ||
1046 | if (ndev_vif->iftype == NL80211_IFTYPE_P2P_GO) | |
1047 | SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_NO_VIF); | |
1048 | } else if (ndev_vif->vif_type == FAPI_VIFTYPE_UNSYNCHRONISED) { | |
1049 | if (SLSI_IS_VIF_INDEX_WLAN(ndev_vif)) { | |
1050 | slsi_wlan_unsync_vif_deactivate(sdev, dev, hw_available); | |
1051 | } else { | |
1052 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "P2P active - Deactivate\n"); | |
1053 | slsi_p2p_vif_deactivate(sdev, dev, hw_available); | |
1054 | } | |
1055 | } | |
1056 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
1057 | else if (ndev_vif->vif_type == FAPI_VIFTYPE_MONITOR) | |
1058 | slsi_stop_monitor_mode(sdev, dev); | |
1059 | #endif | |
1060 | } | |
1061 | } | |
1062 | ||
1063 | void slsi_scan_cleanup(struct slsi_dev *sdev, struct net_device *dev) | |
1064 | { | |
1065 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
1066 | int i; | |
1067 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) | |
1068 | struct cfg80211_scan_info info = {.aborted = false}; | |
1069 | #endif | |
1070 | ||
1071 | SLSI_NET_DBG3(dev, SLSI_INIT_DEINIT, "clean scan_data\n"); | |
1072 | ||
1073 | SLSI_MUTEX_LOCK(ndev_vif->scan_mutex); | |
1074 | for (i = 0; i < SLSI_SCAN_MAX; i++) { | |
1075 | if ((ndev_vif->scan[i].scan_req || ndev_vif->scan[i].acs_request) && | |
1076 | !sdev->mlme_blocked) | |
1077 | slsi_mlme_del_scan(sdev, dev, (ndev_vif->ifnum << 8 | i), false); | |
1078 | slsi_purge_scan_results(ndev_vif, i); | |
1079 | if (ndev_vif->scan[i].scan_req && i == SLSI_SCAN_HW_ID) { | |
1080 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) | |
1081 | info.aborted = true; | |
1082 | cfg80211_scan_done(ndev_vif->scan[i].scan_req, &info); | |
1083 | #else | |
1084 | cfg80211_scan_done(ndev_vif->scan[i].scan_req, true); | |
1085 | #endif | |
1086 | } | |
1087 | ||
1088 | if (ndev_vif->scan[i].sched_req && i == SLSI_SCAN_SCHED_ID) | |
1089 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) | |
1090 | cfg80211_sched_scan_stopped(sdev->wiphy, ndev_vif->scan[i].sched_req->reqid); | |
1091 | #else | |
1092 | cfg80211_sched_scan_stopped(sdev->wiphy); | |
1093 | #endif | |
1094 | ||
1095 | ndev_vif->scan[i].scan_req = NULL; | |
1096 | kfree(ndev_vif->scan[i].acs_request); | |
1097 | ndev_vif->scan[i].acs_request = NULL; | |
1098 | ndev_vif->scan[i].sched_req = NULL; | |
1099 | } | |
1100 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_mutex); | |
1101 | } | |
1102 | ||
1103 | static void slsi_stop_net_dev_locked(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) | |
1104 | { | |
1105 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
1106 | ||
1107 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "Stopping netdev_up_count=%d, hw_available = %d\n", sdev->netdev_up_count, hw_available); | |
1108 | ||
1109 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(sdev->start_stop_mutex)); | |
1110 | ||
1111 | if (!ndev_vif->is_available) { | |
1112 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "Not Available\n"); | |
1113 | return; | |
1114 | } | |
1115 | ||
1116 | if (WARN_ON(!sdev->netdev_up_count)) { | |
1117 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "sdev->netdev_up_count=%d\n", sdev->netdev_up_count); | |
1118 | return; | |
1119 | } | |
1120 | ||
1121 | slsi_scan_cleanup(sdev, dev); | |
1122 | ||
1123 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
1124 | slsi_vif_cleanup(sdev, dev, hw_available); | |
1125 | ndev_vif->is_available = false; | |
1126 | sdev->netdev_up_count--; | |
1127 | #ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL | |
1128 | if (atomic_read(&ndev_vif->arp_tx_count) && atomic_read(&sdev->ctrl_pause_state)) | |
1129 | scsc_wifi_unpause_ctrl_q_all_vif(sdev); | |
1130 | atomic_set(&ndev_vif->arp_tx_count, 0); | |
1131 | #endif | |
1132 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
1133 | ||
1134 | complete_all(&ndev_vif->sig_wait.completion); | |
1135 | slsi_stop_chip(sdev); | |
1136 | } | |
1137 | ||
1138 | /* Called when a net device wants to go DOWN */ | |
1139 | void slsi_stop_net_dev(struct slsi_dev *sdev, struct net_device *dev) | |
1140 | { | |
1141 | SLSI_MUTEX_LOCK(sdev->start_stop_mutex); | |
1142 | slsi_stop_net_dev_locked(sdev, dev, sdev->recovery_status ? false : true); | |
1143 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
1144 | } | |
1145 | ||
1146 | /* Called when we get sdio_removed */ | |
1147 | void slsi_stop(struct slsi_dev *sdev) | |
1148 | { | |
1149 | struct net_device *dev; | |
1150 | int i; | |
1151 | ||
1152 | SLSI_MUTEX_LOCK(sdev->start_stop_mutex); | |
1153 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "netdev_up_count:%d\n", sdev->netdev_up_count); | |
1154 | ||
1155 | complete_all(&sdev->sig_wait.completion); | |
1156 | ||
1157 | SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); | |
1158 | for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { | |
1159 | dev = slsi_get_netdev_locked(sdev, i); | |
1160 | if (dev) | |
1161 | slsi_stop_net_dev_locked(sdev, sdev->netdev[i], false); | |
1162 | } | |
1163 | SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); | |
1164 | ||
1165 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
1166 | } | |
1167 | ||
1168 | /* MIB download handling */ | |
1169 | static u8 *slsi_mib_slice(struct slsi_dev *sdev, const u8 *data, u32 length, u32 *p_parsed_len, | |
1170 | u32 *p_mib_slice_len) | |
1171 | { | |
1172 | const u8 *p = data; | |
1173 | u8 *mib_slice; | |
1174 | u32 mib_slice_len = 0; | |
1175 | ||
1176 | SLSI_UNUSED_PARAMETER(sdev); | |
1177 | ||
1178 | if (!length) | |
1179 | return NULL; | |
1180 | ||
1181 | mib_slice = kmalloc(length + 4, GFP_KERNEL); | |
1182 | if (!mib_slice) | |
1183 | return NULL; | |
1184 | ||
1185 | while (length >= 4) { | |
1186 | u16 psid = SLSI_BUFF_LE_TO_U16(p); | |
1187 | u16 pslen = (u16)(4 + SLSI_BUFF_LE_TO_U16(&p[2])); | |
1188 | ||
1189 | if (pslen & 0x1) | |
1190 | pslen++; | |
1191 | ||
1192 | if (psid & CSR_WIFI_SME_MIB2_HOST_PSID_MASK) { | |
1193 | /* do nothing */ | |
1194 | } else { | |
1195 | /* SLSI_ERR (sdev, "PSID=0x%04X : FW\n", psid); */ | |
1196 | #define CSR_WIFI_HOSTIO_MIB_SET_MAX (1800) | |
1197 | if ((mib_slice_len + pslen) > CSR_WIFI_HOSTIO_MIB_SET_MAX) | |
1198 | break; | |
1199 | if (pslen > length + 4) { | |
1200 | SLSI_ERR(sdev, "length %u read from MIB file > space %u - corrupt file?\n", pslen, length + 4); | |
1201 | mib_slice_len = 0; | |
1202 | break; | |
1203 | } | |
1204 | memcpy(&mib_slice[mib_slice_len], p, pslen); | |
1205 | mib_slice_len += pslen; | |
1206 | } | |
1207 | p += pslen; | |
1208 | length -= pslen; | |
1209 | } | |
1210 | ||
1211 | *p_mib_slice_len = mib_slice_len; | |
1212 | *p_parsed_len = (p - data); | |
1213 | ||
1214 | return mib_slice; | |
1215 | } | |
1216 | ||
1217 | /* Extract the platform name string from the HCF file */ | |
1218 | static int slsi_mib_get_platform(struct slsi_dev_mib_info *mib_info) | |
1219 | { | |
1220 | size_t plat_name_len; | |
1221 | int pos = 0; | |
1222 | ||
1223 | /* The mib_data passed to this function should already | |
1224 | * have had its HCF header skipped. | |
1225 | * | |
1226 | * This is shoehorned into specific PSIDs to allow backward | |
1227 | * compatibility, so we must look into the HCF payload | |
1228 | * instead of the header :( | |
1229 | * | |
1230 | * The updated configcmd util guarantees that these keys | |
1231 | * will appear first: | |
1232 | * | |
1233 | * PSIDs: | |
1234 | * 0xfffe - 16 bit version ID, value 1. | |
1235 | * 0xffff - If version ID=1, holds platform name string. | |
1236 | */ | |
1237 | ||
1238 | mib_info->platform[0] = '\0'; | |
1239 | ||
1240 | /* Sanity - payload long enough for info? */ | |
1241 | if (mib_info->mib_len < 12) { | |
1242 | SLSI_INFO_NODEV("HCF file too short\n"); | |
1243 | return -EINVAL; /* file too short */ | |
1244 | } | |
1245 | ||
1246 | if (mib_info->mib_data[pos++] != 0xFE || /* Version ID FFFE */ | |
1247 | mib_info->mib_data[pos++] != 0xFF) { | |
1248 | SLSI_INFO_NODEV("No HCF version ID\n"); | |
1249 | return -EINVAL; /* No version ID */ | |
1250 | } | |
1251 | if (mib_info->mib_data[pos++] != 0x01 || /* Len 1, LE */ | |
1252 | mib_info->mib_data[pos++] != 0x00) { | |
1253 | SLSI_INFO_NODEV("Bad length\n"); | |
1254 | return -EINVAL; /* Unknown length */ | |
1255 | } | |
1256 | if (mib_info->mib_data[pos++] != 0x01 || /* Header ID 1, LE */ | |
1257 | mib_info->mib_data[pos++] != 0x00) { | |
1258 | SLSI_INFO_NODEV("Bad version ID\n"); | |
1259 | return -EINVAL; /* Unknown version ID */ | |
1260 | } | |
1261 | if (mib_info->mib_data[pos++] != 0xFF || /* Platform Name FFFF */ | |
1262 | mib_info->mib_data[pos++] != 0xFF) { | |
1263 | SLSI_INFO_NODEV("No HCF platform name\n"); | |
1264 | return -EINVAL; /* No platform name */ | |
1265 | } | |
1266 | ||
1267 | /* Length of platform name */ | |
1268 | plat_name_len = mib_info->mib_data[pos++]; | |
1269 | plat_name_len |= (mib_info->mib_data[pos++] << 16); | |
1270 | ||
1271 | /* Sanity check */ | |
1272 | if (plat_name_len + pos > mib_info->mib_len || plat_name_len < 2) { | |
1273 | SLSI_ERR_NODEV("Bad HCF FFFF key length %zu\n", | |
1274 | plat_name_len); | |
1275 | return -EINVAL; /* Implausible length */ | |
1276 | } | |
1277 | ||
1278 | /* Skip vldata header SC-506179-SP. This conveys the | |
1279 | * length of the platform string and is 2 or 3 octets long | |
1280 | * depending on the length of the string. | |
1281 | */ | |
1282 | { | |
1283 | #define SLSI_VLDATA_STRING 0xA0 | |
1284 | #define SLSI_VLDATA_LEN 0x17 | |
1285 | ||
1286 | u8 vlen_hdr = mib_info->mib_data[pos++]; | |
1287 | u8 vlen_len = vlen_hdr & SLSI_VLDATA_LEN; /* size of length field */ | |
1288 | ||
1289 | /* Skip vlen header octet */ | |
1290 | plat_name_len--; | |
1291 | ||
1292 | SLSI_DBG1_NODEV(SLSI_INIT_DEINIT, "vlhdr 0x%x, len %u\n", vlen_hdr, vlen_len); | |
1293 | ||
1294 | /* Is it an octet string type? */ | |
1295 | if (!(vlen_hdr & SLSI_VLDATA_STRING)) { | |
1296 | SLSI_ERR_NODEV("No string vlen header 0x%x\n", vlen_hdr); | |
1297 | return -EINVAL; | |
1298 | } | |
1299 | ||
1300 | /* Handle 1 or 2 octet length field only */ | |
1301 | if (vlen_len > 2) { | |
1302 | SLSI_ERR_NODEV("Too long octet string header %u\n", vlen_len); | |
1303 | return -EINVAL; | |
1304 | } | |
1305 | ||
1306 | /* Skip over the string length field. | |
1307 | * Note we just use datalength anyway. | |
1308 | */ | |
1309 | pos += vlen_len; | |
1310 | plat_name_len -= vlen_len; | |
1311 | } | |
1312 | ||
1313 | /* Limit the platform name to space in driver and read */ | |
1314 | { | |
1315 | size_t trunc_len = plat_name_len; | |
1316 | ||
1317 | if (trunc_len >= sizeof(mib_info->platform)) | |
1318 | trunc_len = sizeof(mib_info->platform) - 1; | |
1319 | ||
1320 | /* Extract platform name */ | |
1321 | memcpy(mib_info->platform, &mib_info->mib_data[pos], trunc_len); | |
1322 | mib_info->platform[trunc_len] = '\0'; | |
1323 | ||
1324 | /* Print non-truncated string in log now */ | |
1325 | SLSI_INFO_NODEV("MIB platform: %.*s\n", (int)plat_name_len, &mib_info->mib_data[pos]); | |
1326 | ||
1327 | SLSI_DBG1_NODEV(SLSI_INIT_DEINIT, "plat_name_len: %zu + %u\n", | |
1328 | plat_name_len, (plat_name_len & 1)); | |
1329 | } | |
1330 | ||
1331 | /* Pad string to 16-bit boundary */ | |
1332 | plat_name_len += (plat_name_len & 1); | |
1333 | pos += plat_name_len; | |
1334 | ||
1335 | /* Advance over the keys we read, FW doesn't need them */ | |
1336 | mib_info->mib_data += pos; | |
1337 | mib_info->mib_len -= pos; | |
1338 | ||
1339 | SLSI_DBG1_NODEV(SLSI_INIT_DEINIT, "Skip %d octets HCF payload\n", pos); | |
1340 | ||
1341 | return 0; | |
1342 | } | |
1343 | ||
1344 | #define MGT_HASH_SIZE_BYTES 2 /* Hash will be contained in a uint32 */ | |
1345 | #define MGT_HASH_OFFSET 4 | |
1346 | static int slsi_mib_open_file(struct slsi_dev *sdev, struct slsi_dev_mib_info *mib_info, const struct firmware **fw) | |
1347 | { | |
1348 | int r = -1; | |
1349 | const struct firmware *e = NULL; | |
1350 | const char *mib_file_ext; | |
1351 | char path_name[MX_WLAN_FILE_PATH_LEN_MAX]; | |
1352 | char *mib_file_name = mib_info->mib_file_name; | |
1353 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
1354 | u8 index = sdev->collect_mib.num_files; | |
1355 | u8 *data; | |
1356 | #endif | |
1357 | ||
1358 | if (!mib_file_name || !fw) | |
1359 | return -EINVAL; | |
1360 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
1361 | if (index > SLSI_WLAN_MAX_MIB_FILE + 1) { | |
1362 | SLSI_ERR(sdev, "collect mib index is invalid:%d\n", index); | |
1363 | return -EINVAL; | |
1364 | } | |
1365 | #endif | |
1366 | mib_info->mib_data = NULL; | |
1367 | mib_info->mib_len = 0; | |
1368 | mib_info->mib_hash = 0; /* Reset mib hash value */ | |
1369 | ||
1370 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "MIB file - Name : %s\n", mib_file_name); | |
1371 | ||
1372 | /* Use MIB file compatibility mode? */ | |
1373 | mib_file_ext = strrchr(mib_file_name, '.'); | |
1374 | if (!mib_file_ext) { | |
1375 | SLSI_ERR(sdev, "configuration file name '%s' invalid\n", mib_file_name); | |
1376 | return -EINVAL; | |
1377 | } | |
1378 | ||
1379 | /* Build MIB file path from override */ | |
1380 | scnprintf(path_name, MX_WLAN_FILE_PATH_LEN_MAX, "wlan/%s", mib_file_name); | |
1381 | SLSI_INFO(sdev, "Path to the MIB file : %s\n", path_name); | |
1382 | ||
1383 | r = mx140_file_request_conf(sdev->maxwell_core, &e, "wlan", mib_file_name); | |
1384 | if (r || (!e)) { | |
1385 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "Skip MIB download as file %s is NOT found\n", mib_file_name); | |
1386 | *fw = e; | |
1387 | return r; | |
1388 | } | |
1389 | ||
1390 | mib_info->mib_data = (u8 *)e->data; | |
1391 | mib_info->mib_len = e->size; | |
1392 | ||
1393 | #ifdef CONFIG_SCSC_LOG_COLLECTION | |
1394 | spin_lock(&sdev->collect_mib.in_collection); | |
1395 | memset(&sdev->collect_mib.file[index].file_name, 0, 32); | |
1396 | memcpy(&sdev->collect_mib.file[index].file_name, mib_file_name, 32); | |
1397 | sdev->collect_mib.file[index].len = mib_info->mib_len; | |
1398 | data = kmalloc(mib_info->mib_len, GFP_ATOMIC); | |
1399 | if (!data) { | |
1400 | spin_unlock(&sdev->collect_mib.in_collection); | |
1401 | goto cont; | |
1402 | } | |
1403 | memcpy(data, mib_info->mib_data, mib_info->mib_len); | |
1404 | sdev->collect_mib.file[index].data = data; | |
1405 | sdev->collect_mib.num_files += 1; | |
1406 | spin_unlock(&sdev->collect_mib.in_collection); | |
1407 | cont: | |
1408 | #endif | |
1409 | /* Check MIB file header */ | |
1410 | if (mib_info->mib_len >= 8 && /* Room for header */ | |
1411 | /*(sdev->mib_data[6] & 0xF0) == 0x20 && */ /* WLAN subsystem */ | |
1412 | mib_info->mib_data[7] == 1) { /* First file format */ | |
1413 | int i; | |
1414 | ||
1415 | mib_info->mib_hash = 0; | |
1416 | ||
1417 | for (i = 0; i < MGT_HASH_SIZE_BYTES; i++) | |
1418 | mib_info->mib_hash = (mib_info->mib_hash << 8) | mib_info->mib_data[i + MGT_HASH_OFFSET]; | |
1419 | ||
1420 | SLSI_INFO(sdev, "MIB hash: 0x%.04x\n", mib_info->mib_hash); | |
1421 | /* All good - skip header and continue */ | |
1422 | mib_info->mib_data += 8; | |
1423 | mib_info->mib_len -= 8; | |
1424 | ||
1425 | /* Extract platform name if available */ | |
1426 | slsi_mib_get_platform(mib_info); | |
1427 | } else { | |
1428 | /* Bad header */ | |
1429 | SLSI_ERR(sdev, "configuration file '%s' has bad header\n", mib_info->mib_file_name); | |
1430 | mx140_file_release_conf(sdev->maxwell_core, e); | |
1431 | return -EINVAL; | |
1432 | } | |
1433 | ||
1434 | *fw = e; | |
1435 | return 0; | |
1436 | } | |
1437 | ||
1438 | static int slsi_mib_close_file(struct slsi_dev *sdev, const struct firmware *e) | |
1439 | { | |
1440 | SLSI_DBG2(sdev, SLSI_INIT_DEINIT, "MIB close %p\n", e); | |
1441 | ||
1442 | if (!e || !sdev) | |
1443 | return -EIO; | |
1444 | ||
1445 | mx140_file_release_conf(sdev->maxwell_core, e); | |
1446 | ||
1447 | return 0; | |
1448 | } | |
1449 | ||
1450 | static int slsi_mib_download_file(struct slsi_dev *sdev, struct slsi_dev_mib_info *mib_info) | |
1451 | { | |
1452 | int r = -1; | |
1453 | const struct firmware *e = NULL; | |
1454 | u8 *mib_slice; | |
1455 | u32 mib_slice_len, parsed_len; | |
1456 | ||
1457 | r = slsi_mib_open_file(sdev, mib_info, &e); | |
1458 | if (r) | |
1459 | return r; | |
1460 | /** | |
1461 | * MIB data should not be larger than CSR_WIFI_HOSTIO_MIB_SET_MAX. | |
1462 | * Slice it into smaller ones and download one by one | |
1463 | */ | |
1464 | while (mib_info->mib_len > 0) { | |
1465 | mib_slice = slsi_mib_slice(sdev, mib_info->mib_data, mib_info->mib_len, &parsed_len, &mib_slice_len); | |
1466 | if (!mib_slice) | |
1467 | break; | |
1468 | if (mib_slice_len == 0 || mib_slice_len > mib_info->mib_len) { | |
1469 | /* Sanity check MIB parsing */ | |
1470 | SLSI_ERR(sdev, "slsi_mib_slice returned implausible %d\n", mib_slice_len); | |
1471 | r = -EINVAL; | |
1472 | kfree(mib_slice); | |
1473 | break; | |
1474 | } | |
1475 | r = slsi_mlme_set(sdev, NULL, mib_slice, mib_slice_len); | |
1476 | kfree(mib_slice); | |
1477 | if (r != 0) /* some mib can fail to be set, but continue */ | |
1478 | SLSI_ERR(sdev, "mlme set failed r=0x%x during downloading:'%s'\n", | |
1479 | r, mib_info->mib_file_name); | |
1480 | ||
1481 | mib_info->mib_data += parsed_len; | |
1482 | mib_info->mib_len -= parsed_len; | |
1483 | } | |
1484 | ||
1485 | slsi_mib_close_file(sdev, e); | |
1486 | ||
1487 | return r; | |
1488 | } | |
1489 | ||
1490 | static int slsi_mib_initial_get(struct slsi_dev *sdev) | |
1491 | { | |
1492 | struct slsi_mib_data mibreq = { 0, NULL }; | |
1493 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
1494 | int *band = sdev->supported_5g_channels; | |
1495 | int rx_len = 0; | |
1496 | int r; | |
1497 | int i = 0; | |
1498 | int j = 0; | |
1499 | int chan_start = 0; | |
1500 | int chan_count = 0; | |
1501 | int index = 0; | |
1502 | int mib_index = 0; | |
1503 | u16 num_antenna = 0; | |
1504 | u16 antenna_lw_bit = 0; | |
1505 | u16 antenna_hg_bit = 0; | |
1506 | static const struct slsi_mib_get_entry get_values[] = {{ SLSI_PSID_UNIFI_CHIP_VERSION, { 0, 0 } }, | |
1507 | { SLSI_PSID_UNIFI_SUPPORTED_CHANNELS, { 0, 0 } }, | |
1508 | { SLSI_PSID_UNIFI_HT_ACTIVATED, {0, 0} }, | |
1509 | { SLSI_PSID_UNIFI_VHT_ACTIVATED, {0, 0} }, | |
1510 | { SLSI_PSID_UNIFI_HT_CAPABILITIES, {0, 0} }, | |
1511 | { SLSI_PSID_UNIFI_VHT_CAPABILITIES, {0, 0} }, | |
1512 | { SLSI_PSID_UNIFI_HARDWARE_PLATFORM, {0, 0} }, | |
1513 | { SLSI_PSID_UNIFI_REG_DOM_VERSION, {0, 0} }, | |
1514 | { SLSI_PSID_UNIFI_NAN_ACTIVATED, {0, 0} }, | |
1515 | { SLSI_PSID_UNIFI_DEFAULT_DWELL_TIME, {0, 0} }, | |
1516 | #ifdef CONFIG_SCSC_WLAN_WIFI_SHARING | |
1517 | { SLSI_PSID_UNIFI_WI_FI_SHARING5_GHZ_CHANNEL, {0, 0} }, | |
1518 | #endif | |
1519 | #ifdef CONFIG_SCSC_WLAN_AP_INFO_FILE | |
1520 | { SLSI_PSID_UNIFI_DUAL_BAND_CONCURRENCY, {0, 0} }, | |
1521 | { SLSI_PSID_UNIFI_MAX_CLIENT, {0, 0} }, | |
1522 | #endif | |
1523 | #ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION | |
1524 | { SLSI_PSID_UNIFI_MAC_ADDRESS_RANDOMISATION, {0, 0} }, | |
1525 | #endif | |
1526 | { SLSI_PSID_UNIFI_DEFAULT_COUNTRY_WITHOUT_CH12_CH13, {0, 0} }, | |
1527 | #ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT | |
1528 | { SLSI_PSID_UNIFI_ARP_DETECT_ACTIVATED, {0, 0} }, | |
1529 | #endif | |
1530 | #ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL | |
1531 | { SLSI_PSID_UNIFI_ARP_OUTSTANDING_MAX, {0, 0} }, | |
1532 | #endif | |
1533 | { SLSI_PSID_UNIFI_APF_ACTIVATED, {0, 0} }, | |
1534 | { SLSI_PSID_UNIFI_SOFT_AP40_MHZ_ON24G, {0, 0} }, | |
1535 | { SLSI_PSID_UNIFI_MAX_NUM_ANTENNA_TO_USE, {0, 0} }, | |
1536 | };/*Check the mibrsp.dataLength when a new mib is added*/ | |
1537 | ||
1538 | r = slsi_mib_encode_get_list(&mibreq, sizeof(get_values) / sizeof(struct slsi_mib_get_entry), get_values); | |
1539 | if (r != SLSI_MIB_STATUS_SUCCESS) | |
1540 | return -ENOMEM; | |
1541 | ||
1542 | mibrsp.dataLength = 220; | |
1543 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
1544 | if (!mibrsp.data) { | |
1545 | kfree(mibreq.data); | |
1546 | return -ENOMEM; | |
1547 | } | |
1548 | ||
1549 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, mibrsp.data, mibrsp.dataLength, &rx_len); | |
1550 | kfree(mibreq.data); | |
1551 | if (r == 0) { | |
1552 | struct slsi_mib_value *values; | |
1553 | ||
1554 | mibrsp.dataLength = (u32)rx_len; | |
1555 | ||
1556 | values = slsi_mib_decode_get_list(&mibrsp, sizeof(get_values) / sizeof(struct slsi_mib_get_entry), get_values); | |
1557 | ||
1558 | if (!values) { | |
1559 | kfree(mibrsp.data); | |
1560 | return -EINVAL; | |
1561 | } | |
1562 | ||
1563 | if (values[mib_index].type != SLSI_MIB_TYPE_NONE) { /* CHIP_VERSION */ | |
1564 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_UINT); | |
1565 | sdev->chip_info_mib.chip_version = values[mib_index].u.uintValue; | |
1566 | } | |
1567 | ||
1568 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { /* SUPPORTED_CHANNELS */ | |
1569 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_OCTET); | |
1570 | if (values[mib_index].type == SLSI_MIB_TYPE_OCTET) { | |
1571 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
1572 | int k = 0; | |
1573 | int increment = 4; /* increment channel by 4 for 5G and by 1 for 2G */ | |
1574 | int buf_len = 150; /* 150 bytes for 14+25=39 channels and spaces between them */ | |
1575 | char *supported_channels_buffer = NULL; | |
1576 | int buf_pos = 0; | |
1577 | ||
1578 | supported_channels_buffer = kmalloc(buf_len, GFP_KERNEL); | |
1579 | if (!supported_channels_buffer) | |
1580 | return -ENOMEM; | |
1581 | #endif | |
1582 | sdev->band_5g_supported = 0; | |
1583 | memset(sdev->supported_2g_channels, 0, sizeof(sdev->supported_2g_channels)); | |
1584 | memset(sdev->supported_5g_channels, 0, sizeof(sdev->supported_5g_channels)); | |
1585 | for (i = 0; i < values[mib_index].u.octetValue.dataLength / 2; i++) { | |
1586 | /* If any 5GHz channel is supported, update band_5g_supported */ | |
1587 | if ((values[mib_index].u.octetValue.data[i * 2] > 14) && | |
1588 | (values[mib_index].u.octetValue.data[i * 2 + 1] > 0)) { | |
1589 | sdev->band_5g_supported = 1; | |
1590 | break; | |
1591 | } | |
1592 | } | |
1593 | for (i = 0; i < values[mib_index].u.octetValue.dataLength; i += 2) { | |
1594 | chan_start = values[mib_index].u.octetValue.data[i]; | |
1595 | chan_count = values[mib_index].u.octetValue.data[i + 1]; | |
1596 | band = sdev->supported_5g_channels; | |
1597 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
1598 | k = 0; | |
1599 | if (chan_start < 15) | |
1600 | increment = 1; | |
1601 | else | |
1602 | increment = 4; | |
1603 | #endif | |
1604 | if (chan_start < 15) { | |
1605 | index = chan_start - 1; | |
1606 | band = sdev->supported_2g_channels; | |
1607 | } else if (chan_start >= 36 && chan_start <= 48) { | |
1608 | index = (chan_start - 36) / 4; | |
1609 | } else if (chan_start >= 52 && chan_start <= 64) { | |
1610 | index = ((chan_start - 52) / 4) + 4; | |
1611 | } else if (chan_start >= 100 && chan_start <= 140) { | |
1612 | index = ((chan_start - 100) / 4) + 8; | |
1613 | } else if (chan_start >= 149 && chan_start <= 165) { | |
1614 | index = ((chan_start - 149) / 4) + 20; | |
1615 | } else { | |
1616 | continue; | |
1617 | } | |
1618 | ||
1619 | for (j = 0; j < chan_count; j++) { | |
1620 | band[index + j] = 1; | |
1621 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
1622 | buf_pos += snprintf(supported_channels_buffer + buf_pos, | |
1623 | buf_len - buf_pos, "%d ", (chan_start + k)); | |
1624 | k = k + increment; | |
1625 | #endif | |
1626 | } | |
1627 | sdev->enabled_channel_count += chan_count; | |
1628 | } | |
1629 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
1630 | SLSI_DBG1(sdev, SLSI_CFG80211, "Value for Supported Channels mib: %s\n", | |
1631 | supported_channels_buffer); | |
1632 | kfree(supported_channels_buffer); | |
1633 | #endif | |
1634 | } | |
1635 | } | |
1636 | ||
1637 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* HT enabled? */ | |
1638 | sdev->fw_ht_enabled = values[mib_index].u.boolValue; | |
1639 | else | |
1640 | SLSI_WARN(sdev, "Error reading HT enabled mib\n"); | |
1641 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* VHT enabled? */ | |
1642 | sdev->fw_vht_enabled = values[mib_index].u.boolValue; | |
1643 | else | |
1644 | SLSI_WARN(sdev, "Error reading VHT enabled mib\n"); | |
1645 | if (values[++mib_index].type == SLSI_MIB_TYPE_OCTET) { /* HT capabilities */ | |
1646 | if (values[mib_index].u.octetValue.dataLength >= 4) | |
1647 | memcpy(&sdev->fw_ht_cap, values[mib_index].u.octetValue.data, 4); | |
1648 | else | |
1649 | SLSI_WARN(sdev, "Error reading HT capabilities\n"); | |
1650 | } else { | |
1651 | SLSI_WARN(sdev, "Error reading HT capabilities\n"); | |
1652 | } | |
1653 | if (values[++mib_index].type == SLSI_MIB_TYPE_OCTET) { /* VHT capabilities */ | |
1654 | if (values[mib_index].u.octetValue.dataLength >= 4) | |
1655 | memcpy(&sdev->fw_vht_cap, values[mib_index].u.octetValue.data, 4); | |
1656 | else | |
1657 | SLSI_WARN(sdev, "Error reading VHT capabilities\n"); | |
1658 | } else { | |
1659 | SLSI_WARN(sdev, "Error reading VHT capabilities\n"); | |
1660 | } | |
1661 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { /* HARDWARE_PLATFORM */ | |
1662 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_UINT); | |
1663 | sdev->plat_info_mib.plat_build = values[mib_index].u.uintValue; | |
1664 | } else { | |
1665 | SLSI_WARN(sdev, "Error reading Hardware platform\n"); | |
1666 | } | |
1667 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { /* REG_DOM_VERSION */ | |
1668 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_UINT); | |
1669 | sdev->reg_dom_version = values[mib_index].u.uintValue; | |
1670 | } else { | |
1671 | SLSI_WARN(sdev, "Error reading Reg domain version\n"); | |
1672 | } | |
1673 | ||
1674 | /* NAN enabled? */ | |
1675 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { | |
1676 | sdev->nan_enabled = values[mib_index].u.boolValue; | |
1677 | } else { | |
1678 | sdev->nan_enabled = false; | |
1679 | SLSI_WARN(sdev, "Error reading NAN enabled mib\n"); | |
1680 | } | |
1681 | SLSI_DBG1(sdev, SLSI_CFG80211, "Value for NAN enabled mib : %d\n", sdev->nan_enabled); | |
1682 | ||
1683 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { /* UnifiDefaultDwellTime */ | |
1684 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_UINT); | |
1685 | sdev->fw_dwell_time = (values[mib_index].u.uintValue) * 1024; /* Conveting TU to Microseconds */ | |
1686 | } else { | |
1687 | SLSI_WARN(sdev, "Error reading UnifiForcedScheduleDuration\n"); | |
1688 | } | |
1689 | ||
1690 | #ifdef CONFIG_SCSC_WLAN_WIFI_SHARING | |
1691 | if (values[++mib_index].type == SLSI_MIB_TYPE_OCTET) { /* 5Ghz Allowed Channels */ | |
1692 | if (values[mib_index].u.octetValue.dataLength >= 8) { | |
1693 | memcpy(&sdev->wifi_sharing_5ghz_channel, values[mib_index].u.octetValue.data, 8); | |
1694 | slsi_extract_valid_wifi_sharing_channels(sdev); | |
1695 | } else { | |
1696 | SLSI_WARN(sdev, "Error reading 5Ghz Allowed Channels\n"); | |
1697 | } | |
1698 | } else { | |
1699 | SLSI_WARN(sdev, "Error reading 5Ghz Allowed Channels\n"); | |
1700 | } | |
1701 | #endif | |
1702 | ||
1703 | #ifdef CONFIG_SCSC_WLAN_AP_INFO_FILE | |
1704 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* Dual band concurrency */ | |
1705 | sdev->dualband_concurrency = values[mib_index].u.boolValue; | |
1706 | else | |
1707 | SLSI_WARN(sdev, "Error reading dual band concurrency\n"); | |
1708 | if (values[++mib_index].type == SLSI_MIB_TYPE_UINT) /* max client for soft AP */ | |
1709 | sdev->softap_max_client = values[mib_index].u.uintValue; | |
1710 | else | |
1711 | SLSI_WARN(sdev, "Error reading SoftAP max client\n"); | |
1712 | #endif | |
1713 | #ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION | |
1714 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* Mac Randomization enable? */ | |
1715 | sdev->fw_mac_randomization_enabled = values[mib_index].u.boolValue; | |
1716 | else | |
1717 | SLSI_WARN(sdev, "Error reading Mac Randomization Support\n"); | |
1718 | #endif | |
1719 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { /* Disable ch12/ch13 */ | |
1720 | sdev->device_config.disable_ch12_ch13 = values[mib_index].u.boolValue; | |
1721 | SLSI_DBG1(sdev, SLSI_CFG80211, "Value for default country without ch12/13 mib: %d\n", | |
1722 | sdev->device_config.disable_ch12_ch13); | |
1723 | } else { | |
1724 | SLSI_WARN(sdev, "Error reading default country without ch12/13 mib\n"); | |
1725 | } | |
1726 | #ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT | |
1727 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* Enhanced Arp Detect Support */ | |
1728 | sdev->device_config.fw_enhanced_arp_detect_supported = values[mib_index].u.boolValue; | |
1729 | else | |
1730 | SLSI_DBG2(sdev, SLSI_MLME, "Enhanced Arp Detect is disabled!\n"); | |
1731 | #endif | |
1732 | #ifdef CONFIG_SCSC_WLAN_ARP_FLOW_CONTROL | |
1733 | /* Max ARP support in FW */ | |
1734 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { | |
1735 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_UINT); | |
1736 | sdev->fw_max_arp_count = values[mib_index].u.uintValue; | |
1737 | if (sdev->fw_max_arp_count <= SLSI_ARP_UNPAUSE_THRESHOLD) { | |
1738 | SLSI_INFO(sdev, | |
1739 | "qlen:%d less. NO ArpFlowControl\n", | |
1740 | sdev->fw_max_arp_count); | |
1741 | sdev->fw_max_arp_count = 0; | |
1742 | } | |
1743 | } else { | |
1744 | sdev->fw_max_arp_count = 0; | |
1745 | SLSI_DBG3(sdev, SLSI_MLME, | |
1746 | "NO ARP flow control support in FW\n"); | |
1747 | } | |
1748 | #endif | |
1749 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* APF Support */ | |
1750 | sdev->device_config.fw_apf_supported = values[mib_index].u.boolValue; | |
1751 | else | |
1752 | SLSI_DBG2(sdev, SLSI_MLME, "APF Support is disabled!\n"); | |
1753 | ||
1754 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) /* 40MHz for Soft AP */ | |
1755 | sdev->fw_SoftAp_2g_40mhz_enabled = values[mib_index].u.boolValue; | |
1756 | else | |
1757 | SLSI_DBG2(sdev, SLSI_MLME, "40MHz for Soft AP is disabled!\n"); | |
1758 | /* Num of Antenna */ | |
1759 | if (values[++mib_index].type != SLSI_MIB_TYPE_NONE) { | |
1760 | SLSI_CHECK_TYPE(sdev, values[mib_index].type, SLSI_MIB_TYPE_UINT); | |
1761 | num_antenna = values[mib_index].u.uintValue; | |
1762 | antenna_lw_bit = num_antenna & 0xff; | |
1763 | antenna_hg_bit = ((num_antenna >> 8) & 0xff); | |
1764 | sdev->lls_num_radio = (antenna_lw_bit > antenna_hg_bit) ? antenna_lw_bit : antenna_hg_bit; | |
1765 | SLSI_DBG2(sdev, SLSI_MLME, "sdev->lls_num_radio = %d\n", sdev->lls_num_radio); | |
1766 | } else | |
1767 | SLSI_DBG2(sdev, SLSI_MLME, "Failed to read number of antennas\n"); | |
1768 | ||
1769 | kfree(values); | |
1770 | } | |
1771 | kfree(mibrsp.data); | |
1772 | ||
1773 | return r; | |
1774 | } | |
1775 | ||
1776 | int slsi_set_mib_roam(struct slsi_dev *dev, struct net_device *ndev, u16 psid, int value) | |
1777 | { | |
1778 | struct slsi_mib_data mib_data = { 0, NULL }; | |
1779 | int error = SLSI_MIB_STATUS_FAILURE; | |
1780 | ||
1781 | if (slsi_mib_encode_int(&mib_data, psid, value, 0) == SLSI_MIB_STATUS_SUCCESS) | |
1782 | if (mib_data.dataLength) { | |
1783 | error = slsi_mlme_set(dev, ndev, mib_data.data, mib_data.dataLength); | |
1784 | if (error) | |
1785 | SLSI_ERR(dev, "Err Setting MIB failed. error = %d\n", error); | |
1786 | kfree(mib_data.data); | |
1787 | } | |
1788 | ||
1789 | return error; | |
1790 | } | |
1791 | ||
1792 | #ifdef CONFIG_SCSC_WLAN_SET_PREFERRED_ANTENNA | |
1793 | int slsi_set_mib_preferred_antenna(struct slsi_dev *dev, u16 value) | |
1794 | { | |
1795 | struct slsi_mib_data mib_data = { 0, NULL }; | |
1796 | int error = SLSI_MIB_STATUS_FAILURE; | |
1797 | ||
1798 | if (slsi_mib_encode_uint(&mib_data, SLSI_PSID_UNIFI_PREFERRED_ANTENNA_BITMAP, | |
1799 | value, 0) == SLSI_MIB_STATUS_SUCCESS) | |
1800 | if (mib_data.dataLength) { | |
1801 | error = slsi_mlme_set(dev, NULL, mib_data.data, mib_data.dataLength); | |
1802 | if (error) | |
1803 | SLSI_ERR(dev, "Err Setting MIB failed. error = %d\n", error); | |
1804 | kfree(mib_data.data); | |
1805 | } | |
1806 | ||
1807 | return error; | |
1808 | } | |
1809 | #endif | |
1810 | ||
1811 | void slsi_reset_throughput_stats(struct net_device *dev) | |
1812 | { | |
1813 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
1814 | struct slsi_dev *sdev = ndev_vif->sdev; | |
1815 | struct slsi_mib_data mib_data = { 0, NULL }; | |
1816 | int error = SLSI_MIB_STATUS_FAILURE; | |
1817 | ||
1818 | if (slsi_mib_encode_int(&mib_data, SLSI_PSID_UNIFI_THROUGHPUT_DEBUG, 0, 0) == SLSI_MIB_STATUS_SUCCESS) | |
1819 | if (mib_data.dataLength) { | |
1820 | error = slsi_mlme_set(sdev, dev, mib_data.data, mib_data.dataLength); | |
1821 | if (error) | |
1822 | SLSI_ERR(sdev, "Err Setting MIB failed. error = %d\n", error); | |
1823 | kfree(mib_data.data); | |
1824 | } | |
1825 | } | |
1826 | ||
1827 | int slsi_get_mib_roam(struct slsi_dev *sdev, u16 psid, int *mib_value) | |
1828 | { | |
1829 | struct slsi_mib_data mibreq = { 0, NULL }; | |
1830 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
1831 | int rx_len = 0; | |
1832 | int r; | |
1833 | struct slsi_mib_get_entry get_values[] = { { psid, { 0, 0 } } }; | |
1834 | ||
1835 | r = slsi_mib_encode_get_list(&mibreq, sizeof(get_values) / sizeof(struct slsi_mib_get_entry), get_values); | |
1836 | if (r != SLSI_MIB_STATUS_SUCCESS) | |
1837 | return -ENOMEM; | |
1838 | ||
1839 | mibrsp.dataLength = 64; | |
1840 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
1841 | if (!mibrsp.data) { | |
1842 | kfree(mibreq.data); | |
1843 | return -ENOMEM; | |
1844 | } | |
1845 | ||
1846 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, mibrsp.data, mibrsp.dataLength, &rx_len); | |
1847 | kfree(mibreq.data); | |
1848 | ||
1849 | if (r == 0) { | |
1850 | struct slsi_mib_value *values; | |
1851 | ||
1852 | mibrsp.dataLength = (u32)rx_len; | |
1853 | ||
1854 | values = slsi_mib_decode_get_list(&mibrsp, sizeof(get_values) / sizeof(struct slsi_mib_get_entry), get_values); | |
1855 | ||
1856 | if (!values) { | |
1857 | kfree(mibrsp.data); | |
1858 | return -EINVAL; | |
1859 | } | |
1860 | ||
1861 | WARN_ON(values[0].type == SLSI_MIB_TYPE_OCTET || | |
1862 | values[0].type == SLSI_MIB_TYPE_NONE); | |
1863 | ||
1864 | if (values[0].type == SLSI_MIB_TYPE_INT) | |
1865 | *mib_value = (int)(values->u.intValue); | |
1866 | else if (values[0].type == SLSI_MIB_TYPE_UINT) | |
1867 | *mib_value = (int)(values->u.uintValue); | |
1868 | else if (values[0].type == SLSI_MIB_TYPE_BOOL) | |
1869 | *mib_value = (int)(values->u.boolValue); | |
1870 | ||
1871 | SLSI_DBG2(sdev, SLSI_MLME, "MIB value = %d\n", *mib_value); | |
1872 | kfree(values); | |
1873 | } else { | |
1874 | SLSI_ERR(sdev, "Mib read failed (error: %d)\n", r); | |
1875 | } | |
1876 | ||
1877 | kfree(mibrsp.data); | |
1878 | return r; | |
1879 | } | |
1880 | ||
1881 | #ifdef CONFIG_SCSC_WLAN_GSCAN_ENABLE | |
1882 | int slsi_mib_get_gscan_cap(struct slsi_dev *sdev, struct slsi_nl_gscan_capabilities *cap) | |
1883 | { | |
1884 | struct slsi_mib_data mibreq = { 0, NULL }; | |
1885 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
1886 | int rx_len = 0; | |
1887 | int r; | |
1888 | static const struct slsi_mib_get_entry get_values[] = { { SLSI_PSID_UNIFI_GOOGLE_MAX_NUMBER_OF_PERIODIC_SCANS, { 0, 0 } }, | |
1889 | { SLSI_PSID_UNIFI_GOOGLE_MAX_RSSI_SAMPLE_SIZE, { 0, 0 } }, | |
1890 | { SLSI_PSID_UNIFI_GOOGLE_MAX_HOTLIST_APS, { 0, 0 } }, | |
1891 | { SLSI_PSID_UNIFI_GOOGLE_MAX_SIGNIFICANT_WIFI_CHANGE_APS, { 0, 0 } }, | |
1892 | { SLSI_PSID_UNIFI_GOOGLE_MAX_BSSID_HISTORY_ENTRIES, { 0, 0 } },}; | |
1893 | ||
1894 | r = slsi_mib_encode_get_list(&mibreq, sizeof(get_values) / sizeof(struct slsi_mib_get_entry), get_values); | |
1895 | if (r != SLSI_MIB_STATUS_SUCCESS) | |
1896 | return -ENOMEM; | |
1897 | ||
1898 | mibrsp.dataLength = 64; | |
1899 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
1900 | if (!mibrsp.data) { | |
1901 | kfree(mibreq.data); | |
1902 | return -ENOMEM; | |
1903 | } | |
1904 | ||
1905 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, mibrsp.data, mibrsp.dataLength, &rx_len); | |
1906 | kfree(mibreq.data); | |
1907 | ||
1908 | if (r == 0) { | |
1909 | struct slsi_mib_value *values; | |
1910 | ||
1911 | mibrsp.dataLength = (u32)rx_len; | |
1912 | ||
1913 | values = slsi_mib_decode_get_list(&mibrsp, sizeof(get_values) / sizeof(struct slsi_mib_get_entry), get_values); | |
1914 | ||
1915 | if (!values) { | |
1916 | kfree(mibrsp.data); | |
1917 | return -EINVAL; | |
1918 | } | |
1919 | ||
1920 | if (values[0].type != SLSI_MIB_TYPE_NONE) { | |
1921 | SLSI_CHECK_TYPE(sdev, values[0].type, SLSI_MIB_TYPE_UINT); | |
1922 | cap->max_scan_buckets = values[0].u.uintValue; | |
1923 | } | |
1924 | ||
1925 | if (values[1].type != SLSI_MIB_TYPE_NONE) { | |
1926 | SLSI_CHECK_TYPE(sdev, values[1].type, SLSI_MIB_TYPE_UINT); | |
1927 | cap->max_rssi_sample_size = values[1].u.uintValue; | |
1928 | } | |
1929 | ||
1930 | if (values[2].type != SLSI_MIB_TYPE_NONE) { | |
1931 | SLSI_CHECK_TYPE(sdev, values[2].type, SLSI_MIB_TYPE_UINT); | |
1932 | cap->max_hotlist_aps = values[2].u.uintValue; | |
1933 | } | |
1934 | ||
1935 | if (values[3].type != SLSI_MIB_TYPE_NONE) { | |
1936 | SLSI_CHECK_TYPE(sdev, values[3].type, SLSI_MIB_TYPE_UINT); | |
1937 | cap->max_significant_wifi_change_aps = values[3].u.uintValue; | |
1938 | } | |
1939 | ||
1940 | if (values[4].type != SLSI_MIB_TYPE_NONE) { | |
1941 | SLSI_CHECK_TYPE(sdev, values[4].type, SLSI_MIB_TYPE_UINT); | |
1942 | cap->max_bssid_history_entries = values[4].u.uintValue; | |
1943 | } | |
1944 | ||
1945 | kfree(values); | |
1946 | } | |
1947 | kfree(mibrsp.data); | |
1948 | return r; | |
1949 | } | |
1950 | #endif | |
1951 | ||
1952 | int slsi_mib_get_apf_cap(struct slsi_dev *sdev, struct net_device *dev) | |
1953 | { | |
1954 | struct slsi_mib_data mibreq = { 0, NULL }; | |
1955 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
1956 | struct slsi_mib_value *values = NULL; | |
1957 | int data_length = 0; | |
1958 | int r = 0; | |
1959 | static const struct slsi_mib_get_entry get_values[] = { | |
1960 | { SLSI_PSID_UNIFI_APF_VERSION, { 0, 0 } }, /* to get the supported APF version*/ | |
1961 | { SLSI_PSID_UNIFI_APF_MAX_SIZE, { 0, 0 } } /* to get APF_MAX_SIZE*/ | |
1962 | }; | |
1963 | ||
1964 | r = slsi_mib_encode_get_list(&mibreq, (sizeof(get_values) / sizeof(struct slsi_mib_get_entry)), | |
1965 | get_values); | |
1966 | if (r != SLSI_MIB_STATUS_SUCCESS) | |
1967 | return -ENOMEM; | |
1968 | ||
1969 | /* 15*2 bytes for 2 Mib's */ | |
1970 | mibrsp.dataLength = 30; | |
1971 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
1972 | ||
1973 | if (!mibrsp.data) { | |
1974 | SLSI_NET_DBG1(dev, SLSI_MLME, "failed to allocate memory\n"); | |
1975 | kfree(mibreq.data); | |
1976 | return -ENOMEM; | |
1977 | } | |
1978 | ||
1979 | r = slsi_mlme_get(sdev, dev, mibreq.data, mibreq.dataLength, mibrsp.data, | |
1980 | mibrsp.dataLength, &data_length); | |
1981 | kfree(mibreq.data); | |
1982 | ||
1983 | if (r == 0) { | |
1984 | mibrsp.dataLength = (u32)data_length; | |
1985 | values = slsi_mib_decode_get_list(&mibrsp, | |
1986 | (sizeof(get_values) / sizeof(struct slsi_mib_get_entry)), get_values); | |
1987 | if (!values) { | |
1988 | SLSI_NET_DBG1(dev, SLSI_MLME, "mib decode list failed\n"); | |
1989 | kfree(mibrsp.data); | |
1990 | return -ENOMEM; | |
1991 | } | |
1992 | ||
1993 | if (values[0].type == SLSI_MIB_TYPE_UINT) | |
1994 | sdev->device_config.apf_cap.version = values[0].u.uintValue; /* supported APF version */ | |
1995 | else | |
1996 | SLSI_ERR(sdev, "invalid type. index:%d\n", 0); | |
1997 | if (values[1].type == SLSI_MIB_TYPE_UINT) | |
1998 | sdev->device_config.apf_cap.max_length = values[1].u.uintValue; /* APF_MAX_LENGTH */ | |
1999 | else | |
2000 | SLSI_ERR(sdev, "invalid type. index:%d\n", 1); | |
2001 | } else { | |
2002 | SLSI_NET_DBG1(dev, SLSI_MLME, "mlme_get_req failed(result:0x%4x)\n", r); | |
2003 | } | |
2004 | ||
2005 | kfree(mibrsp.data); | |
2006 | kfree(values); | |
2007 | return r; | |
2008 | } | |
2009 | ||
2010 | int slsi_mib_get_rtt_cap(struct slsi_dev *sdev, struct net_device *dev, struct slsi_rtt_capabilities *cap) | |
2011 | { | |
2012 | struct slsi_mib_data supported_rtt_capab = { 0, NULL }; | |
2013 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
2014 | struct slsi_mib_value *values = NULL; | |
2015 | ||
2016 | struct slsi_mib_get_entry get_values[] = { { SLSI_PSID_UNIFI_RTT_CAPABILITIES, { 0, 0 } } }; | |
2017 | ||
2018 | mibrsp.dataLength = 64; | |
2019 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
2020 | if (!mibrsp.data) { | |
2021 | SLSI_ERR(sdev, "Cannot kmalloc %d bytes\n", mibrsp.dataLength); | |
2022 | kfree(mibrsp.data); | |
2023 | return -ENOMEM; | |
2024 | } | |
2025 | ||
2026 | values = slsi_read_mibs(sdev, dev, get_values, 1, &mibrsp); | |
2027 | if (!values) { | |
2028 | kfree(mibrsp.data); | |
2029 | return -EINVAL; | |
2030 | } | |
2031 | ||
2032 | if (values[0].type != SLSI_MIB_TYPE_OCTET) { | |
2033 | SLSI_ERR(sdev, "Invalid type (%d) for SLSI_PSID_UNIFI_RTT_CAPABILITIES", values[0].type); | |
2034 | kfree(mibrsp.data); | |
2035 | kfree(values); | |
2036 | return -EINVAL; | |
2037 | } | |
2038 | supported_rtt_capab = values[0].u.octetValue; | |
2039 | cap->rtt_one_sided_supported = supported_rtt_capab.data[0]; | |
2040 | cap->rtt_ftm_supported = supported_rtt_capab.data[1]; | |
2041 | cap->lci_support = supported_rtt_capab.data[2]; | |
2042 | cap->lcr_support = supported_rtt_capab.data[3]; | |
2043 | cap->responder_supported = supported_rtt_capab.data[4]; | |
2044 | cap->preamble_support = supported_rtt_capab.data[5]; | |
2045 | cap->bw_support = supported_rtt_capab.data[6]; | |
2046 | cap->mc_version = supported_rtt_capab.data[7]; | |
2047 | ||
2048 | kfree(values); | |
2049 | kfree(mibrsp.data); | |
2050 | return 0; | |
2051 | } | |
2052 | ||
2053 | struct slsi_peer *slsi_peer_add(struct slsi_dev *sdev, struct net_device *dev, u8 *peer_address, u16 aid) | |
2054 | { | |
2055 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2056 | struct slsi_peer *peer = NULL; | |
2057 | u16 queueset = 0; | |
2058 | ||
2059 | if (WARN_ON(!aid)) { | |
2060 | SLSI_NET_ERR(dev, "Invalid aid(0) received\n"); | |
2061 | return NULL; | |
2062 | } | |
2063 | queueset = MAP_AID_TO_QS(aid); | |
2064 | ||
2065 | /* MUST only be called from the control path that has acquired the lock */ | |
2066 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2067 | ||
2068 | if (WARN_ON(!ndev_vif->activated)) | |
2069 | return NULL; | |
2070 | ||
2071 | if (!peer_address) { | |
2072 | SLSI_NET_WARN(dev, "Peer without address\n"); | |
2073 | return NULL; | |
2074 | } | |
2075 | ||
2076 | peer = slsi_get_peer_from_mac(sdev, dev, peer_address); | |
2077 | if (peer) { | |
2078 | if (ndev_vif->sta.tdls_enabled && (peer->queueset == 0)) { | |
2079 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "TDLS enabled and its station queueset\n"); | |
2080 | } else { | |
2081 | SLSI_NET_WARN(dev, "Peer (MAC:%pM) already exists\n", peer_address); | |
2082 | return NULL; | |
2083 | } | |
2084 | } | |
2085 | ||
2086 | if (slsi_get_peer_from_qs(sdev, dev, queueset)) { | |
2087 | SLSI_NET_WARN(dev, "Peer (queueset:%d) already exists\n", queueset); | |
2088 | return NULL; | |
2089 | } | |
2090 | ||
2091 | SLSI_NET_DBG2(dev, SLSI_CFG80211, "%pM, aid:%d\n", peer_address, aid); | |
2092 | ||
2093 | peer = ndev_vif->peer_sta_record[queueset]; | |
2094 | if (!peer) { | |
2095 | /* If it reaches here, something has gone wrong */ | |
2096 | SLSI_NET_ERR(dev, "Peer (queueset:%d) is NULL\n", queueset); | |
2097 | return NULL; | |
2098 | } | |
2099 | ||
2100 | peer->aid = aid; | |
2101 | peer->queueset = queueset; | |
2102 | SLSI_ETHER_COPY(peer->address, peer_address); | |
2103 | peer->assoc_ie = NULL; | |
2104 | peer->assoc_resp_ie = NULL; | |
2105 | peer->is_wps = false; | |
2106 | peer->connected_state = SLSI_STA_CONN_STATE_DISCONNECTED; | |
2107 | /* Initialise the Station info */ | |
2108 | slsi_peer_reset_stats(sdev, dev, peer); | |
2109 | ratelimit_state_init(&peer->sinfo_mib_get_rs, SLSI_SINFO_MIB_ACCESS_TIMEOUT, 0); | |
2110 | ||
2111 | if (scsc_wifi_fcq_ctrl_q_init(&peer->ctrl_q) < 0) { | |
2112 | SLSI_NET_ERR(dev, "scsc_wifi_fcq_ctrl_q_init failed\n"); | |
2113 | return NULL; | |
2114 | } | |
2115 | ||
2116 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
2117 | if (scsc_wifi_fcq_unicast_qset_init(dev, &peer->data_qs, peer->queueset, sdev, ndev_vif->ifnum, peer) < 0) { | |
2118 | #else | |
2119 | if (scsc_wifi_fcq_unicast_qset_init(dev, &peer->data_qs, peer->queueset, sdev, ndev_vif->ifnum, peer) < 0) { | |
2120 | #endif | |
2121 | SLSI_NET_ERR(dev, "scsc_wifi_fcq_unicast_qset_init failed\n"); | |
2122 | scsc_wifi_fcq_ctrl_q_deinit(&peer->ctrl_q); | |
2123 | return NULL; | |
2124 | } | |
2125 | ||
2126 | /* A peer is only valid once all the data is initialised | |
2127 | * otherwise a process could check the flag and start to read | |
2128 | * uninitialised data. | |
2129 | */ | |
2130 | ||
2131 | if (ndev_vif->sta.tdls_enabled) | |
2132 | ndev_vif->sta.tdls_peer_sta_records++; | |
2133 | else | |
2134 | ndev_vif->peer_sta_records++; | |
2135 | ||
2136 | ndev_vif->cfg80211_sinfo_generation++; | |
2137 | skb_queue_head_init(&peer->buffered_frames); | |
2138 | ||
2139 | /* For TDLS this flag will be set while moving the packets from STAQ to TDLSQ */ | |
2140 | /* TODO: changes for moving packets is removed for now. Enable this when these data path changes go in*/ | |
2141 | /* if (!ndev_vif->sta.tdls_enabled) | |
2142 | * peer->valid = true; | |
2143 | */ | |
2144 | peer->valid = true; | |
2145 | ||
2146 | SLSI_NET_DBG2(dev, SLSI_CFG80211, "created station peer %pM AID:%d\n", peer->address, aid); | |
2147 | return peer; | |
2148 | } | |
2149 | ||
2150 | void slsi_peer_reset_stats(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *peer) | |
2151 | { | |
2152 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2153 | ||
2154 | SLSI_UNUSED_PARAMETER(sdev); | |
2155 | ||
2156 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "Peer:%pM\n", peer->address); | |
2157 | ||
2158 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2159 | ||
2160 | memset(&peer->sinfo, 0x00, sizeof(peer->sinfo)); | |
2161 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) | |
2162 | peer->sinfo.filled = BIT(NL80211_STA_INFO_RX_BYTES) | | |
2163 | BIT(NL80211_STA_INFO_TX_BYTES) | | |
2164 | BIT(NL80211_STA_INFO_RX_PACKETS) | | |
2165 | BIT(NL80211_STA_INFO_TX_PACKETS) | | |
2166 | BIT(NL80211_STA_INFO_RX_DROP_MISC) | | |
2167 | BIT(NL80211_STA_INFO_TX_FAILED) | | |
2168 | BIT(NL80211_STA_INFO_SIGNAL) | | |
2169 | BIT(NL80211_STA_INFO_BSS_PARAM); | |
2170 | #else | |
2171 | peer->sinfo.filled = STATION_INFO_RX_BYTES | | |
2172 | STATION_INFO_TX_BYTES | | |
2173 | STATION_INFO_RX_PACKETS | | |
2174 | STATION_INFO_TX_PACKETS | | |
2175 | STATION_INFO_RX_DROP_MISC | | |
2176 | STATION_INFO_TX_FAILED | | |
2177 | STATION_INFO_SIGNAL | | |
2178 | STATION_INFO_BSS_PARAM; | |
2179 | #endif | |
2180 | } | |
2181 | ||
2182 | void slsi_dump_stats(struct net_device *dev) | |
2183 | { | |
2184 | SLSI_UNUSED_PARAMETER(dev); | |
2185 | ||
2186 | SLSI_INFO_NODEV("slsi_hanged_event_count: %d\n", slsi_hanged_event_count); | |
2187 | } | |
2188 | ||
2189 | enum slsi_wlan_vendor_attr_hanged_event { | |
2190 | SLSI_WLAN_VENDOR_ATTR_HANGED_EVENT_PANIC_CODE = 1, | |
2191 | SLSI_WLAN_VENDOR_ATTR_HANGED_EVENT_MAX | |
2192 | }; | |
2193 | ||
2194 | int slsi_send_hanged_vendor_event(struct slsi_dev *sdev, u16 scsc_panic_code) | |
2195 | { | |
2196 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) | |
2197 | struct sk_buff *skb; | |
2198 | int length = sizeof(scsc_panic_code); | |
2199 | ||
2200 | slsi_hanged_event_count++; | |
2201 | SLSI_INFO(sdev, "Sending SLSI_NL80211_VENDOR_HANGED_EVENT , count: %d, reason =0x%2x\n", slsi_hanged_event_count, scsc_panic_code); | |
2202 | ||
2203 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) | |
2204 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, length, SLSI_NL80211_VENDOR_HANGED_EVENT, GFP_KERNEL); | |
2205 | #else | |
2206 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, length, SLSI_NL80211_VENDOR_HANGED_EVENT, GFP_KERNEL); | |
2207 | #endif | |
2208 | if (!skb) { | |
2209 | SLSI_ERR_NODEV("Failed to allocate SKB for vendor hanged event"); | |
2210 | return -ENOMEM; | |
2211 | } | |
2212 | ||
2213 | if (nla_put(skb, SLSI_WLAN_VENDOR_ATTR_HANGED_EVENT_PANIC_CODE, length, &scsc_panic_code)) { | |
2214 | SLSI_ERR_NODEV("Failed nla_put for panic code\n"); | |
2215 | slsi_kfree_skb(skb); | |
2216 | return -EINVAL; | |
2217 | } | |
2218 | cfg80211_vendor_event(skb, GFP_KERNEL); | |
2219 | ||
2220 | #endif | |
2221 | return 0; | |
2222 | } | |
2223 | ||
2224 | #ifdef CONFIG_SLSI_WLAN_STA_FWD_BEACON | |
2225 | int slsi_send_forward_beacon_vendor_event(struct slsi_dev *sdev, const u8 *ssid, const int ssid_len, const u8 *bssid, | |
2226 | u8 channel, const u16 beacon_int, const u64 timestamp, const u64 sys_time) | |
2227 | { | |
2228 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) | |
2229 | struct sk_buff *skb; | |
2230 | u8 err = 0; | |
2231 | struct net_device *dev; | |
2232 | struct netdev_vif *ndev_vif; | |
2233 | ||
2234 | dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN); | |
2235 | ndev_vif = netdev_priv(dev); | |
2236 | ||
2237 | SLSI_DBG2(sdev, SLSI_CFG80211, "Sending SLSI_NL80211_VENDOR_FORWARD_BEACON\n"); | |
2238 | ||
2239 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) | |
2240 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, &ndev_vif->wdev, NLMSG_DEFAULT_SIZE, | |
2241 | SLSI_NL80211_VENDOR_FORWARD_BEACON, GFP_KERNEL); | |
2242 | #else | |
2243 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, | |
2244 | SLSI_NL80211_VENDOR_FORWARD_BEACON, GFP_KERNEL); | |
2245 | #endif | |
2246 | if (!skb) { | |
2247 | SLSI_ERR_NODEV("Failed to allocate SKB for vendor forward_beacon event\n"); | |
2248 | return -ENOMEM; | |
2249 | } | |
2250 | ||
2251 | err |= nla_put(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_SSID, ssid_len, ssid); | |
2252 | err |= nla_put(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_BSSID, ETH_ALEN, bssid); | |
2253 | err |= nla_put_u8(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_CHANNEL, channel); | |
2254 | err |= nla_put_u16(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_BCN_INTERVAL, beacon_int); | |
2255 | err |= nla_put_u32(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_TIME_STAMP1, (timestamp & 0x00000000FFFFFFFF)); | |
2256 | err |= nla_put_u32(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_TIME_STAMP2, | |
2257 | ((timestamp >> 32) & 0x00000000FFFFFFFF)); | |
2258 | err |= nla_put_u64_64bit(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_SYS_TIME, sys_time, 0); | |
2259 | ||
2260 | if (err) { | |
2261 | SLSI_ERR_NODEV("Failed nla_put for forward_beacon\n"); | |
2262 | slsi_kfree_skb(skb); | |
2263 | return -EINVAL; | |
2264 | } | |
2265 | cfg80211_vendor_event(skb, GFP_KERNEL); | |
2266 | ||
2267 | #endif | |
2268 | return 0; | |
2269 | } | |
2270 | ||
2271 | int slsi_send_forward_beacon_abort_vendor_event(struct slsi_dev *sdev, u16 reason_code) | |
2272 | { | |
2273 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) | |
2274 | struct sk_buff *skb; | |
2275 | u8 err = 0; | |
2276 | struct net_device *dev; | |
2277 | struct netdev_vif *ndev_vif; | |
2278 | ||
2279 | dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN); | |
2280 | ndev_vif = netdev_priv(dev); | |
2281 | ||
2282 | SLSI_INFO(sdev, "Sending SLSI_NL80211_VENDOR_FORWARD_BEACON_ABORT\n"); | |
2283 | ||
2284 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) | |
2285 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, &ndev_vif->wdev, sizeof(reason_code), | |
2286 | SLSI_NL80211_VENDOR_FORWARD_BEACON_ABORT, GFP_KERNEL); | |
2287 | #else | |
2288 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, sizeof(reason_code), | |
2289 | SLSI_NL80211_VENDOR_FORWARD_BEACON_ABORT, GFP_KERNEL); | |
2290 | #endif | |
2291 | if (!skb) { | |
2292 | SLSI_ERR_NODEV("Failed to allocate SKB for vendor forward_beacon_abort event\n"); | |
2293 | return -ENOMEM; | |
2294 | } | |
2295 | ||
2296 | err = nla_put_u16(skb, SLSI_WLAN_VENDOR_ATTR_FORWARD_BEACON_ABORT, reason_code); | |
2297 | ||
2298 | if (err) { | |
2299 | SLSI_ERR_NODEV("Failed nla_put for beacon_recv_abort\n"); | |
2300 | slsi_kfree_skb(skb); | |
2301 | return -EINVAL; | |
2302 | } | |
2303 | cfg80211_vendor_event(skb, GFP_KERNEL); | |
2304 | ||
2305 | #endif | |
2306 | return 0; | |
2307 | } | |
2308 | #endif | |
2309 | ||
2310 | #ifdef CONFIG_SCSC_WLAN_HANG_TEST | |
2311 | int slsi_test_send_hanged_vendor_event(struct net_device *dev) | |
2312 | { | |
2313 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2314 | ||
2315 | SLSI_INFO(ndev_vif->sdev, "Test FORCE HANG\n"); | |
2316 | return slsi_send_hanged_vendor_event(ndev_vif->sdev, SCSC_PANIC_CODE_HOST << 15); | |
2317 | } | |
2318 | #endif | |
2319 | ||
2320 | static bool slsi_search_ies_for_qos_indicators(struct slsi_dev *sdev, u8 *ies, int ies_len) | |
2321 | { | |
2322 | SLSI_UNUSED_PARAMETER(sdev); | |
2323 | ||
2324 | if (cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len)) { | |
2325 | SLSI_DBG1(sdev, SLSI_CFG80211, "QOS enabled due to WLAN_EID_HT_CAPABILITY\n"); | |
2326 | return true; | |
2327 | } | |
2328 | if (cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len)) { | |
2329 | SLSI_DBG1(sdev, SLSI_CFG80211, "QOS enabled due to WLAN_EID_VHT_CAPABILITY\n"); | |
2330 | return true; | |
2331 | } | |
2332 | if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, ies, ies_len)) { | |
2333 | SLSI_DBG1(sdev, SLSI_CFG80211, "QOS enabled due to WLAN_OUI_TYPE_MICROSOFT_WMM\n"); | |
2334 | return true; | |
2335 | } | |
2336 | return false; | |
2337 | } | |
2338 | ||
2339 | void slsi_peer_update_assoc_req(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *peer, struct sk_buff *skb) | |
2340 | { | |
2341 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2342 | u16 id = fapi_get_u16(skb, id); | |
2343 | ||
2344 | /* MUST only be called from the control path that has acquired the lock */ | |
2345 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2346 | ||
2347 | switch (id) { | |
2348 | case MLME_CONNECTED_IND: | |
2349 | case MLME_PROCEDURE_STARTED_IND: | |
2350 | if (WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_AP && | |
2351 | ndev_vif->vif_type != FAPI_VIFTYPE_STATION)) { | |
2352 | slsi_kfree_skb(skb); | |
2353 | return; | |
2354 | } | |
2355 | break; | |
2356 | default: | |
2357 | slsi_kfree_skb(skb); | |
2358 | WARN_ON(1); | |
2359 | return; | |
2360 | } | |
2361 | ||
2362 | slsi_kfree_skb(peer->assoc_ie); | |
2363 | peer->assoc_ie = NULL; | |
2364 | peer->capabilities = 0; | |
2365 | peer->sinfo.assoc_req_ies = NULL; | |
2366 | peer->sinfo.assoc_req_ies_len = 0; | |
2367 | ||
2368 | if (fapi_get_datalen(skb)) { | |
2369 | int mgmt_hdr_len; | |
2370 | struct ieee80211_mgmt *mgmt = fapi_get_mgmt(skb); | |
2371 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2372 | ||
2373 | /* Update the skb to just point to the frame */ | |
2374 | skb_pull(skb, fapi_get_siglen(skb)); | |
2375 | ||
2376 | if (ieee80211_is_assoc_req(mgmt->frame_control)) { | |
2377 | mgmt_hdr_len = (mgmt->u.assoc_req.variable - (u8 *)mgmt); | |
2378 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) | |
2379 | peer->capabilities = le16_to_cpu(mgmt->u.assoc_req.capab_info); | |
2380 | } else if (ieee80211_is_reassoc_req(mgmt->frame_control)) { | |
2381 | mgmt_hdr_len = (mgmt->u.reassoc_req.variable - (u8 *)mgmt); | |
2382 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) | |
2383 | peer->capabilities = le16_to_cpu(mgmt->u.reassoc_req.capab_info); | |
2384 | } else { | |
2385 | WARN_ON(1); | |
2386 | slsi_kfree_skb(skb); | |
2387 | return; | |
2388 | } | |
2389 | ||
2390 | skb_pull(skb, mgmt_hdr_len); | |
2391 | ||
2392 | peer->assoc_ie = skb; | |
2393 | peer->sinfo.assoc_req_ies = skb->data; | |
2394 | peer->sinfo.assoc_req_ies_len = skb->len; | |
2395 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) | |
2396 | peer->sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; | |
2397 | #endif | |
2398 | peer->qos_enabled = slsi_search_ies_for_qos_indicators(sdev, skb->data, skb->len); | |
2399 | } | |
2400 | } | |
2401 | ||
2402 | void slsi_peer_update_assoc_rsp(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *peer, struct sk_buff *skb) | |
2403 | { | |
2404 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2405 | u16 id = fapi_get_u16(skb, id); | |
2406 | ||
2407 | SLSI_UNUSED_PARAMETER(sdev); | |
2408 | ||
2409 | /* MUST only be called from the control path that has acquired the lock */ | |
2410 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2411 | ||
2412 | if (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) | |
2413 | goto exit_with_warnon; | |
2414 | ||
2415 | if (id != MLME_CONNECT_IND && id != MLME_ROAMED_IND && id != MLME_REASSOCIATE_IND) { | |
2416 | SLSI_NET_ERR(dev, "Unexpected id =0x%4x\n", id); | |
2417 | goto exit_with_warnon; | |
2418 | } | |
2419 | ||
2420 | slsi_kfree_skb(peer->assoc_resp_ie); | |
2421 | peer->assoc_resp_ie = NULL; | |
2422 | peer->capabilities = 0; | |
2423 | if (fapi_get_datalen(skb)) { | |
2424 | int mgmt_hdr_len; | |
2425 | struct ieee80211_mgmt *mgmt = fapi_get_mgmt(skb); | |
2426 | ||
2427 | /* Update the skb to just point to the frame */ | |
2428 | skb_pull(skb, fapi_get_siglen(skb)); | |
2429 | ||
2430 | if (ieee80211_is_assoc_resp(mgmt->frame_control)) { | |
2431 | mgmt_hdr_len = (mgmt->u.assoc_resp.variable - (u8 *)mgmt); | |
2432 | peer->capabilities = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | |
2433 | } else if (ieee80211_is_reassoc_resp(mgmt->frame_control)) { | |
2434 | mgmt_hdr_len = (mgmt->u.reassoc_resp.variable - (u8 *)mgmt); | |
2435 | peer->capabilities = le16_to_cpu(mgmt->u.reassoc_resp.capab_info); | |
2436 | } else { | |
2437 | goto exit_with_warnon; | |
2438 | } | |
2439 | ||
2440 | skb_pull(skb, mgmt_hdr_len); | |
2441 | peer->assoc_resp_ie = skb; | |
2442 | } | |
2443 | return; | |
2444 | ||
2445 | exit_with_warnon: | |
2446 | WARN_ON(1); | |
2447 | slsi_kfree_skb(skb); | |
2448 | } | |
2449 | ||
2450 | int slsi_peer_remove(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *peer) | |
2451 | { | |
2452 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2453 | struct sk_buff *buff_frame; | |
2454 | ||
2455 | SLSI_UNUSED_PARAMETER(sdev); | |
2456 | ||
2457 | /* MUST only be called from the control path that has acquired the lock */ | |
2458 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2459 | ||
2460 | if (!peer) { | |
2461 | SLSI_NET_WARN(dev, "peer=NULL"); | |
2462 | return -EINVAL; | |
2463 | } | |
2464 | ||
2465 | SLSI_NET_DBG2(dev, SLSI_CFG80211, "%pM\n", peer->address); | |
2466 | ||
2467 | buff_frame = slsi_skb_dequeue(&peer->buffered_frames); | |
2468 | while (buff_frame) { | |
2469 | SLSI_NET_DBG3(dev, SLSI_MLME, "FLUSHING BUFFERED FRAMES\n"); | |
2470 | slsi_kfree_skb(buff_frame); | |
2471 | buff_frame = slsi_skb_dequeue(&peer->buffered_frames); | |
2472 | } | |
2473 | ||
2474 | slsi_rx_ba_stop_all(dev, peer); | |
2475 | ||
2476 | /* The information is no longer valid so first update the flag to ensure that | |
2477 | * another process doesn't try to use it any more. | |
2478 | */ | |
2479 | peer->valid = false; | |
2480 | peer->is_wps = false; | |
2481 | peer->connected_state = SLSI_STA_CONN_STATE_DISCONNECTED; | |
2482 | ||
2483 | if (slsi_is_tdls_peer(dev, peer)) | |
2484 | ndev_vif->sta.tdls_peer_sta_records--; | |
2485 | else | |
2486 | ndev_vif->peer_sta_records--; | |
2487 | ||
2488 | ndev_vif->cfg80211_sinfo_generation++; | |
2489 | ||
2490 | scsc_wifi_fcq_qset_deinit(dev, &peer->data_qs, sdev, ndev_vif->ifnum, peer); | |
2491 | scsc_wifi_fcq_ctrl_q_deinit(&peer->ctrl_q); | |
2492 | ||
2493 | slsi_kfree_skb(peer->assoc_ie); | |
2494 | slsi_kfree_skb(peer->assoc_resp_ie); | |
2495 | memset(peer, 0x00, sizeof(*peer)); | |
2496 | ||
2497 | return 0; | |
2498 | } | |
2499 | ||
2500 | int slsi_vif_activated(struct slsi_dev *sdev, struct net_device *dev) | |
2501 | { | |
2502 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2503 | ||
2504 | SLSI_UNUSED_PARAMETER(sdev); | |
2505 | ||
2506 | /* MUST only be called from the control path that has acquired the lock */ | |
2507 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2508 | ||
2509 | /* MUST have cleared any peer records previously */ | |
2510 | WARN_ON(ndev_vif->peer_sta_records); | |
2511 | ||
2512 | if (WARN_ON(ndev_vif->activated)) | |
2513 | return -EALREADY; | |
2514 | ||
2515 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) | |
2516 | /* Enable the Multicast queue set for AP mode */ | |
2517 | if (scsc_wifi_fcq_multicast_qset_init(dev, &ndev_vif->ap.group_data_qs, sdev, ndev_vif->ifnum) < 0) | |
2518 | return -EFAULT; | |
2519 | ||
2520 | if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION) { | |
2521 | /* MUST have cleared any tdls peer records previously */ | |
2522 | WARN_ON(ndev_vif->sta.tdls_peer_sta_records); | |
2523 | ||
2524 | ndev_vif->sta.tdls_peer_sta_records = 0; | |
2525 | ndev_vif->sta.tdls_enabled = false; | |
2526 | ndev_vif->sta.roam_in_progress = false; | |
2527 | ndev_vif->sta.nd_offload_enabled = true; | |
2528 | ||
2529 | memset(ndev_vif->sta.keepalive_host_tag, 0, sizeof(ndev_vif->sta.keepalive_host_tag)); | |
2530 | } | |
2531 | ||
2532 | ndev_vif->cfg80211_sinfo_generation = 0; | |
2533 | ndev_vif->peer_sta_records = 0; | |
2534 | ndev_vif->activated = true; | |
2535 | ndev_vif->mgmt_tx_data.exp_frame = SLSI_PA_INVALID; | |
2536 | return 0; | |
2537 | } | |
2538 | ||
2539 | void slsi_vif_deactivated(struct slsi_dev *sdev, struct net_device *dev) | |
2540 | { | |
2541 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2542 | int i; | |
2543 | ||
2544 | /* MUST only be called from the control path that has acquired the lock */ | |
2545 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2546 | ||
2547 | /* The station type VIF is deactivated when the AP connection is lost */ | |
2548 | if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION) { | |
2549 | ndev_vif->sta.group_key_set = false; | |
2550 | ndev_vif->sta.vif_status = SLSI_VIF_STATUS_UNSPECIFIED; | |
2551 | memset(ndev_vif->sta.keepalive_host_tag, 0, sizeof(ndev_vif->sta.keepalive_host_tag)); | |
2552 | ||
2553 | /* delete the TSPEC entries (if any) if it is a STA vif */ | |
2554 | if (ndev_vif->iftype == NL80211_IFTYPE_STATION) | |
2555 | cac_delete_tspec_list(sdev); | |
2556 | ||
2557 | if (ndev_vif->sta.tdls_enabled) | |
2558 | WARN(ndev_vif->sta.tdls_peer_sta_records, "vif:%d, tdls_peer_sta_records:%d", ndev_vif->ifnum, ndev_vif->sta.tdls_peer_sta_records); | |
2559 | ||
2560 | if (ndev_vif->sta.sta_bss) { | |
2561 | slsi_cfg80211_put_bss(sdev->wiphy, ndev_vif->sta.sta_bss); | |
2562 | ndev_vif->sta.sta_bss = NULL; | |
2563 | } | |
2564 | ndev_vif->sta.tdls_enabled = false; | |
2565 | #ifdef CONFIG_SLSI_WLAN_STA_FWD_BEACON | |
2566 | ndev_vif->is_wips_running = false; | |
2567 | #endif | |
2568 | #ifdef CONFIG_SCSC_WLAN_SAE_CONFIG | |
2569 | if (ndev_vif->sta.rsn_ie) { | |
2570 | kfree(ndev_vif->sta.rsn_ie); | |
2571 | ndev_vif->sta.rsn_ie = NULL; | |
2572 | } | |
2573 | #endif | |
2574 | } | |
2575 | ||
2576 | /* MUST be done first to ensure that other code doesn't treat the VIF as still active */ | |
2577 | ndev_vif->activated = false; | |
2578 | slsi_skb_queue_purge(&ndev_vif->rx_data.queue); | |
2579 | ||
2580 | for (i = 0; i < (SLSI_ADHOC_PEER_CONNECTIONS_MAX); i++) { | |
2581 | struct slsi_peer *peer = ndev_vif->peer_sta_record[i]; | |
2582 | ||
2583 | if (peer && peer->valid) { | |
2584 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP && peer->assoc_ie) | |
2585 | cfg80211_del_sta(dev, peer->address, GFP_KERNEL); | |
2586 | ||
2587 | slsi_spinlock_lock(&ndev_vif->peer_lock); | |
2588 | slsi_peer_remove(sdev, dev, peer); | |
2589 | slsi_spinlock_unlock(&ndev_vif->peer_lock); | |
2590 | } | |
2591 | } | |
2592 | ||
2593 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) { | |
2594 | memset(&ndev_vif->ap.last_disconnected_sta, 0, sizeof(ndev_vif->ap.last_disconnected_sta)); | |
2595 | scsc_wifi_fcq_qset_deinit(dev, &ndev_vif->ap.group_data_qs, sdev, ndev_vif->ifnum, NULL); | |
2596 | } | |
2597 | ||
2598 | if ((ndev_vif->iftype == NL80211_IFTYPE_P2P_CLIENT) || (ndev_vif->iftype == NL80211_IFTYPE_P2P_GO)) { | |
2599 | SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_NO_VIF); | |
2600 | sdev->p2p_group_exp_frame = SLSI_PA_INVALID; | |
2601 | } | |
2602 | ||
2603 | /* MUST be done last as lots of code is dependent on checking the vif_type */ | |
2604 | ndev_vif->vif_type = SLSI_VIFTYPE_UNSPECIFIED; | |
2605 | ndev_vif->set_power_mode = FAPI_POWERMANAGEMENTMODE_POWER_SAVE; | |
2606 | if (slsi_is_rf_test_mode_enabled()) { | |
2607 | SLSI_NET_ERR(dev, "*#rf# rf test mode set is enabled.\n"); | |
2608 | ndev_vif->set_power_mode = FAPI_POWERMANAGEMENTMODE_ACTIVE_MODE; | |
2609 | } else { | |
2610 | ndev_vif->set_power_mode = FAPI_POWERMANAGEMENTMODE_POWER_SAVE; | |
2611 | } | |
2612 | ndev_vif->mgmt_tx_data.exp_frame = SLSI_PA_INVALID; | |
2613 | ||
2614 | /* SHOULD have cleared any peer records */ | |
2615 | WARN(ndev_vif->peer_sta_records, "vif:%d, peer_sta_records:%d", ndev_vif->ifnum, ndev_vif->peer_sta_records); | |
2616 | ||
2617 | if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION) { | |
2618 | if (ndev_vif->sta.tdls_enabled) | |
2619 | WARN(ndev_vif->sta.tdls_peer_sta_records, "vif:%d, tdls_peer_sta_records:%d", | |
2620 | ndev_vif->ifnum, ndev_vif->sta.tdls_peer_sta_records); | |
2621 | ||
2622 | if (ndev_vif->sta.sta_bss) { | |
2623 | slsi_cfg80211_put_bss(sdev->wiphy, ndev_vif->sta.sta_bss); | |
2624 | ndev_vif->sta.sta_bss = NULL; | |
2625 | } | |
2626 | ndev_vif->sta.tdls_enabled = false; | |
2627 | } | |
2628 | } | |
2629 | ||
2630 | int slsi_sta_ieee80211_mode(struct net_device *dev, u16 current_bss_channel_frequency) | |
2631 | { | |
2632 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2633 | const u8 *ie; | |
2634 | ||
2635 | ie = cfg80211_find_ie(WLAN_EID_VHT_OPERATION, ndev_vif->sta.sta_bss->ies->data, | |
2636 | ndev_vif->sta.sta_bss->ies->len); | |
2637 | if (ie) | |
2638 | return SLSI_80211_MODE_11AC; | |
2639 | ||
2640 | ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ndev_vif->sta.sta_bss->ies->data, ndev_vif->sta.sta_bss->ies->len); | |
2641 | if (ie) | |
2642 | return SLSI_80211_MODE_11N; | |
2643 | ||
2644 | if (current_bss_channel_frequency > 5000) | |
2645 | return SLSI_80211_MODE_11A; | |
2646 | ||
2647 | ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ndev_vif->sta.sta_bss->ies->data, ndev_vif->sta.sta_bss->ies->len); | |
2648 | if (ie) | |
2649 | return slsi_get_supported_mode(ie); | |
2650 | return -EINVAL; | |
2651 | } | |
2652 | ||
2653 | static int slsi_get_sta_mode(struct net_device *dev, const u8 *last_peer_mac) | |
2654 | { | |
2655 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2656 | struct slsi_dev *sdev = ndev_vif->sdev; | |
2657 | struct slsi_peer *last_peer; | |
2658 | const u8 *peer_ie; | |
2659 | ||
2660 | last_peer = slsi_get_peer_from_mac(sdev, dev, last_peer_mac); | |
2661 | ||
2662 | if (!last_peer) { | |
2663 | SLSI_NET_ERR(dev, "Peer not found\n"); | |
2664 | return -EINVAL; | |
2665 | } | |
2666 | ||
2667 | ndev_vif->ap.last_disconnected_sta.support_mode = 0; | |
2668 | if (cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, last_peer->assoc_ie->data, | |
2669 | last_peer->assoc_ie->len)) | |
2670 | ndev_vif->ap.last_disconnected_sta.support_mode = 3; | |
2671 | else if (cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, last_peer->assoc_ie->data, | |
2672 | last_peer->assoc_ie->len)) | |
2673 | ndev_vif->ap.last_disconnected_sta.support_mode = 1; | |
2674 | ||
2675 | if (ndev_vif->ap.mode == SLSI_80211_MODE_11AC) { /*AP supports VHT*/ | |
2676 | peer_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, last_peer->assoc_ie->data, | |
2677 | last_peer->assoc_ie->len); | |
2678 | if (peer_ie) | |
2679 | return SLSI_80211_MODE_11AC; | |
2680 | ||
2681 | peer_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, last_peer->assoc_ie->data, | |
2682 | last_peer->assoc_ie->len); | |
2683 | if (peer_ie) | |
2684 | return SLSI_80211_MODE_11N; | |
2685 | return SLSI_80211_MODE_11A; | |
2686 | } | |
2687 | if (ndev_vif->ap.mode == SLSI_80211_MODE_11N) { /*AP supports HT*/ | |
2688 | peer_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, last_peer->assoc_ie->data, | |
2689 | last_peer->assoc_ie->len); | |
2690 | if (peer_ie) | |
2691 | return SLSI_80211_MODE_11N; | |
2692 | if (ndev_vif->ap.channel_freq > 5000) | |
2693 | return SLSI_80211_MODE_11A; | |
2694 | peer_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, last_peer->assoc_ie->data, | |
2695 | last_peer->assoc_ie->len); | |
2696 | if (peer_ie) | |
2697 | return slsi_get_supported_mode(peer_ie); | |
2698 | } | |
2699 | ||
2700 | if (ndev_vif->ap.channel_freq > 5000) | |
2701 | return SLSI_80211_MODE_11A; | |
2702 | ||
2703 | if (ndev_vif->ap.mode == SLSI_80211_MODE_11G) { /*AP supports 11g mode */ | |
2704 | peer_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, last_peer->assoc_ie->data, | |
2705 | last_peer->assoc_ie->len); | |
2706 | if (peer_ie) | |
2707 | return slsi_get_supported_mode(peer_ie); | |
2708 | } | |
2709 | ||
2710 | return SLSI_80211_MODE_11B; | |
2711 | } | |
2712 | ||
2713 | int slsi_populate_bss_record(struct net_device *dev) | |
2714 | { | |
2715 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2716 | struct slsi_dev *sdev = ndev_vif->sdev; | |
2717 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
2718 | struct slsi_mib_value *values = NULL; | |
2719 | const u8 *ie, *ext_capab, *rm_capab, *ext_data, *rm_data, *bss_load; | |
2720 | u8 ext_capab_ie_len, rm_capab_ie_len; | |
2721 | bool neighbor_report_bit = 0, btm = 0; | |
2722 | u16 fw_tx_rate; | |
2723 | struct slsi_mib_get_entry get_values[] = { { SLSI_PSID_UNIFI_CURRENT_BSS_CHANNEL_FREQUENCY, { 0, 0 } }, | |
2724 | { SLSI_PSID_UNIFI_CURRENT_BSS_BANDWIDTH, { 0, 0 } }, | |
2725 | { SLSI_PSID_UNIFI_CURRENT_BSS_NSS, {0, 0} }, | |
2726 | { SLSI_PSID_UNIFI_AP_MIMO_USED, {0, 0} }, | |
2727 | { SLSI_PSID_UNIFI_LAST_BSS_SNR, {0, 0} }, | |
2728 | { SLSI_PSID_UNIFI_LAST_BSS_RSSI, { 0, 0 } }, | |
2729 | { SLSI_PSID_UNIFI_ROAMING_COUNT, {0, 0} }, | |
2730 | { SLSI_PSID_UNIFI_LAST_BSS_TX_DATA_RATE, { 0, 0 } }, | |
2731 | { SLSI_PSID_UNIFI_ROAMING_AKM, {0, 0} } }; | |
2732 | ||
2733 | mibrsp.dataLength = 10 * ARRAY_SIZE(get_values); | |
2734 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
2735 | if (!mibrsp.data) { | |
2736 | SLSI_ERR(sdev, "Cannot kmalloc %d bytes for interface MIBs\n", mibrsp.dataLength); | |
2737 | return -ENOMEM; | |
2738 | } | |
2739 | ||
2740 | values = slsi_read_mibs(sdev, dev, get_values, ARRAY_SIZE(get_values), &mibrsp); | |
2741 | ||
2742 | memset(&ndev_vif->sta.last_connected_bss, 0, sizeof(ndev_vif->sta.last_connected_bss)); | |
2743 | ||
2744 | if (!values) { | |
2745 | SLSI_NET_DBG1(dev, SLSI_MLME, "mib decode list failed\n"); | |
2746 | kfree(values); | |
2747 | kfree(mibrsp.data); | |
2748 | return -EINVAL; | |
2749 | } | |
2750 | ||
2751 | /* The Below sequence of reading the BSS Info related Mibs is very important */ | |
2752 | if (values[0].type != SLSI_MIB_TYPE_NONE) { /* CURRENT_BSS_CHANNEL_FREQUENCY */ | |
2753 | SLSI_CHECK_TYPE(sdev, values[0].type, SLSI_MIB_TYPE_UINT); | |
2754 | ndev_vif->sta.last_connected_bss.channel_freq = ((values[0].u.uintValue) / 2); | |
2755 | } | |
2756 | ||
2757 | if (values[1].type != SLSI_MIB_TYPE_NONE) { /* CURRENT_BSS_BANDWIDTH */ | |
2758 | SLSI_CHECK_TYPE(sdev, values[1].type, SLSI_MIB_TYPE_UINT); | |
2759 | ndev_vif->sta.last_connected_bss.bandwidth = values[1].u.uintValue; | |
2760 | } | |
2761 | ||
2762 | if (values[2].type != SLSI_MIB_TYPE_NONE) { /* CURRENT_BSS_NSS */ | |
2763 | SLSI_CHECK_TYPE(sdev, values[2].type, SLSI_MIB_TYPE_UINT); | |
2764 | ndev_vif->sta.last_connected_bss.antenna_mode = values[2].u.uintValue; | |
2765 | } | |
2766 | ||
2767 | if (values[3].type != SLSI_MIB_TYPE_NONE) { /* AP_MIMO_USED */ | |
2768 | SLSI_CHECK_TYPE(sdev, values[3].type, SLSI_MIB_TYPE_UINT); | |
2769 | ndev_vif->sta.last_connected_bss.mimo_used = values[3].u.uintValue; | |
2770 | } | |
2771 | ||
2772 | if (values[4].type != SLSI_MIB_TYPE_NONE) { /* SNR */ | |
2773 | SLSI_CHECK_TYPE(sdev, values[4].type, SLSI_MIB_TYPE_UINT); | |
2774 | ndev_vif->sta.last_connected_bss.snr = values[4].u.uintValue; | |
2775 | } | |
2776 | ||
2777 | if (values[5].type != SLSI_MIB_TYPE_NONE) { /* RSSI */ | |
2778 | SLSI_CHECK_TYPE(sdev, values[5].type, SLSI_MIB_TYPE_INT); | |
2779 | ndev_vif->sta.last_connected_bss.rssi = values[5].u.intValue; | |
2780 | } | |
2781 | ||
2782 | if (values[6].type != SLSI_MIB_TYPE_NONE) { /* ROAMING_COUNT */ | |
2783 | SLSI_CHECK_TYPE(sdev, values[6].type, SLSI_MIB_TYPE_UINT); | |
2784 | ndev_vif->sta.last_connected_bss.roaming_count = values[6].u.uintValue; | |
2785 | } | |
2786 | ||
2787 | if (values[7].type != SLSI_MIB_TYPE_NONE) { /* TX_DATA_RATE */ | |
2788 | SLSI_CHECK_TYPE(sdev, values[7].type, SLSI_MIB_TYPE_UINT); | |
2789 | fw_tx_rate = values[7].u.uintValue; | |
2790 | slsi_decode_fw_rate(fw_tx_rate, NULL, | |
2791 | (unsigned long *)(&ndev_vif->sta.last_connected_bss.tx_data_rate)); | |
2792 | } | |
2793 | ||
2794 | if (values[8].type != SLSI_MIB_TYPE_NONE) { /* ROAMING_AKM */ | |
2795 | SLSI_CHECK_TYPE(sdev, values[8].type, SLSI_MIB_TYPE_UINT); | |
2796 | ndev_vif->sta.last_connected_bss.roaming_akm = values[8].u.uintValue; | |
2797 | } | |
2798 | ||
2799 | kfree(values); | |
2800 | kfree(mibrsp.data); | |
2801 | ||
2802 | if (!ndev_vif->sta.sta_bss) { | |
2803 | SLSI_WARN(sdev, "Bss missing due to out of order msg from firmware!! Cannot collect Big Data\n"); | |
2804 | return -EINVAL; | |
2805 | } | |
2806 | ||
2807 | SLSI_ETHER_COPY(ndev_vif->sta.last_connected_bss.address, ndev_vif->sta.sta_bss->bssid); | |
2808 | ||
2809 | ndev_vif->sta.last_connected_bss.mode = slsi_sta_ieee80211_mode(dev, | |
2810 | ndev_vif->sta.last_connected_bss.channel_freq); | |
2811 | if (ndev_vif->sta.last_connected_bss.mode == -EINVAL) { | |
2812 | SLSI_ERR(sdev, "slsi_get_bss_info : Supported Rates IE is null"); | |
2813 | return -EINVAL; | |
2814 | } | |
2815 | ||
2816 | ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, SLSI_WLAN_OUI_TYPE_WFA_HS20_IND, | |
2817 | ndev_vif->sta.sta_bss->ies->data, ndev_vif->sta.sta_bss->ies->len); | |
2818 | if (ie) { | |
2819 | if ((ie[6] >> 4) == 0) | |
2820 | ndev_vif->sta.last_connected_bss.passpoint_version = 1; | |
2821 | else | |
2822 | ndev_vif->sta.last_connected_bss.passpoint_version = 2; | |
2823 | } | |
2824 | ||
2825 | ndev_vif->sta.last_connected_bss.noise_level = (ndev_vif->sta.last_connected_bss.rssi - | |
2826 | ndev_vif->sta.last_connected_bss.snr); | |
2827 | ||
2828 | ext_capab = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, ndev_vif->sta.sta_bss->ies->data, | |
2829 | ndev_vif->sta.sta_bss->ies->len); | |
2830 | rm_capab = cfg80211_find_ie(WLAN_EID_RRM_ENABLED_CAPABILITIES, ndev_vif->sta.sta_bss->ies->data, | |
2831 | ndev_vif->sta.sta_bss->ies->len); | |
2832 | bss_load = cfg80211_find_ie(WLAN_EID_QBSS_LOAD, ndev_vif->sta.sta_bss->ies->data, | |
2833 | ndev_vif->sta.sta_bss->ies->len); | |
2834 | ||
2835 | if (ext_capab) { | |
2836 | ext_capab_ie_len = ext_capab[1]; | |
2837 | ext_data = &ext_capab[2]; | |
2838 | if ((ext_capab_ie_len >= 2) && (ext_data[1] & | |
2839 | SLSI_WLAN_EXT_CAPA1_PROXY_ARP_ENABLED)) /*check bit12 is set or not */ | |
2840 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 1; | |
2841 | if (ext_capab_ie_len >= 3) { | |
2842 | if (ext_data[2] & SLSI_WLAN_EXT_CAPA2_TFS_ENABLED) /*check bit16 is set or not */ | |
2843 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 2; | |
2844 | if (ext_data[2] & SLSI_WLAN_EXT_CAPA2_WNM_SLEEP_ENABLED) /*check bit17 is set or not */ | |
2845 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 3; | |
2846 | if (ext_data[2] & SLSI_WLAN_EXT_CAPA2_TIM_ENABLED) /*check bit18 is set or not */ | |
2847 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 4; | |
2848 | /*check bit19 is set or not */ | |
2849 | if (ext_data[2] & SLSI_WLAN_EXT_CAPA2_BSS_TRANSISITION_ENABLED) { | |
2850 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 5; | |
2851 | btm = 1; | |
2852 | } | |
2853 | if (ext_data[2] & SLSI_WLAN_EXT_CAPA2_DMS_ENABLED) /*check bit20 is set or not */ | |
2854 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 6; | |
2855 | } | |
2856 | } | |
2857 | if (bss_load) | |
2858 | ndev_vif->sta.last_connected_bss.kvie |= 1; | |
2859 | if (rm_capab) { | |
2860 | rm_capab_ie_len = rm_capab[1]; | |
2861 | rm_data = &rm_capab[2]; | |
2862 | if (rm_capab_ie_len >= 1) { | |
2863 | neighbor_report_bit = SLSI_WLAN_RM_CAPA0_NEIGHBOR_REPORT_ENABLED & rm_data[0]; | |
2864 | if (SLSI_WLAN_RM_CAPA0_LINK_MEASUREMENT_ENABLED & rm_data[0]) | |
2865 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 7; | |
2866 | if (neighbor_report_bit) | |
2867 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 8; | |
2868 | if (SLSI_WLAN_RM_CAPA0_PASSIVE_MODE_ENABLED & rm_data[0]) | |
2869 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 9; | |
2870 | if (SLSI_WLAN_RM_CAPA0_ACTIVE_MODE_ENABLED & rm_data[0]) | |
2871 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 10; | |
2872 | if (SLSI_WLAN_RM_CAPA0_TABLE_MODE_ENABLED & rm_data[0]) | |
2873 | ndev_vif->sta.last_connected_bss.kvie |= 1 << 11; | |
2874 | } | |
2875 | } | |
2876 | if (!neighbor_report_bit && !btm && !bss_load) | |
2877 | ndev_vif->sta.last_connected_bss.kv = 0; | |
2878 | else if (neighbor_report_bit != 0 && (!btm && !bss_load)) | |
2879 | ndev_vif->sta.last_connected_bss.kv = 1; /*11k support */ | |
2880 | else if (!neighbor_report_bit && (btm || bss_load)) | |
2881 | ndev_vif->sta.last_connected_bss.kv = 2; /*11v support */ | |
2882 | else | |
2883 | ndev_vif->sta.last_connected_bss.kv = 3; /*11kv support */ | |
2884 | ||
2885 | return 0; | |
2886 | } | |
2887 | ||
2888 | static int slsi_fill_last_disconnected_sta_info(struct slsi_dev *sdev, struct net_device *dev, | |
2889 | const u8 *last_peer_mac, const u16 reason_code) | |
2890 | { | |
2891 | int i; | |
2892 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2893 | struct slsi_peer *last_peer; | |
2894 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
2895 | struct slsi_mib_value *values = NULL; | |
2896 | u16 fw_tx_rate; | |
2897 | struct slsi_mib_get_entry get_values[] = { { SLSI_PSID_UNIFI_PEER_BANDWIDTH, { 0, 0 } }, | |
2898 | { SLSI_PSID_UNIFI_CURRENT_PEER_NSS, {0, 0} }, | |
2899 | { SLSI_PSID_UNIFI_PEER_RSSI, { 0, 0 } }, | |
2900 | { SLSI_PSID_UNIFI_PEER_TX_DATA_RATE, { 0, 0 } } }; | |
2901 | ||
2902 | SLSI_ETHER_COPY(ndev_vif->ap.last_disconnected_sta.address, | |
2903 | last_peer_mac); | |
2904 | ndev_vif->ap.last_disconnected_sta.reason = reason_code; | |
2905 | ndev_vif->ap.last_disconnected_sta.mode = slsi_get_sta_mode(dev, last_peer_mac); | |
2906 | last_peer = slsi_get_peer_from_mac(sdev, dev, last_peer_mac); | |
2907 | if (!last_peer) { | |
2908 | SLSI_NET_ERR(dev, "Peer not found\n"); | |
2909 | return -EINVAL; | |
2910 | } | |
2911 | for (i = 0; i < ARRAY_SIZE(get_values); i++) | |
2912 | get_values[i].index[0] = last_peer->aid; | |
2913 | ||
2914 | ndev_vif->ap.last_disconnected_sta.rx_retry_packets = SLSI_DEFAULT_UNIFI_PEER_RX_RETRY_PACKETS; | |
2915 | ndev_vif->ap.last_disconnected_sta.rx_bc_mc_packets = SLSI_DEFAULT_UNIFI_PEER_RX_BC_MC_PACKETS; | |
2916 | ndev_vif->ap.last_disconnected_sta.capabilities = last_peer->capabilities; | |
2917 | ndev_vif->ap.last_disconnected_sta.bandwidth = SLSI_DEFAULT_UNIFI_PEER_BANDWIDTH; | |
2918 | ndev_vif->ap.last_disconnected_sta.antenna_mode = SLSI_DEFAULT_UNIFI_PEER_NSS; | |
2919 | ndev_vif->ap.last_disconnected_sta.rssi = SLSI_DEFAULT_UNIFI_PEER_RSSI; | |
2920 | ndev_vif->ap.last_disconnected_sta.tx_data_rate = SLSI_DEFAULT_UNIFI_PEER_TX_DATA_RATE; | |
2921 | ||
2922 | mibrsp.dataLength = 15 * ARRAY_SIZE(get_values); | |
2923 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
2924 | ||
2925 | if (!mibrsp.data) { | |
2926 | SLSI_ERR(sdev, "Cannot kmalloc %d bytes for interface MIBs\n", mibrsp.dataLength); | |
2927 | return -ENOMEM; | |
2928 | } | |
2929 | ||
2930 | values = slsi_read_mibs(sdev, dev, get_values, ARRAY_SIZE(get_values), &mibrsp); | |
2931 | ||
2932 | if (!values) { | |
2933 | SLSI_NET_DBG1(dev, SLSI_MLME, "mib decode list failed\n"); | |
2934 | kfree(values); | |
2935 | kfree(mibrsp.data); | |
2936 | return -EINVAL; | |
2937 | } | |
2938 | if (values[0].type != SLSI_MIB_TYPE_NONE) { /* LAST_PEER_BANDWIDTH */ | |
2939 | SLSI_CHECK_TYPE(sdev, values[0].type, SLSI_MIB_TYPE_INT); | |
2940 | ndev_vif->ap.last_disconnected_sta.bandwidth = values[0].u.intValue; | |
2941 | } | |
2942 | ||
2943 | if (values[1].type != SLSI_MIB_TYPE_NONE) { /*LAST_PEER_NSS*/ | |
2944 | SLSI_CHECK_TYPE(sdev, values[1].type, SLSI_MIB_TYPE_INT); | |
2945 | ndev_vif->ap.last_disconnected_sta.antenna_mode = values[1].u.intValue; | |
2946 | } | |
2947 | ||
2948 | if (values[2].type != SLSI_MIB_TYPE_NONE) { /* LAST_PEER_RSSI*/ | |
2949 | SLSI_CHECK_TYPE(sdev, values[2].type, SLSI_MIB_TYPE_INT); | |
2950 | ndev_vif->ap.last_disconnected_sta.rssi = values[2].u.intValue; | |
2951 | } | |
2952 | ||
2953 | if (values[3].type != SLSI_MIB_TYPE_NONE) { /* LAST_PEER_TX_DATA_RATE */ | |
2954 | SLSI_CHECK_TYPE(sdev, values[3].type, SLSI_MIB_TYPE_UINT); | |
2955 | fw_tx_rate = values[3].u.uintValue; | |
2956 | slsi_decode_fw_rate(fw_tx_rate, NULL, | |
2957 | (unsigned long *)&ndev_vif->ap.last_disconnected_sta.tx_data_rate); | |
2958 | } | |
2959 | ||
2960 | kfree(values); | |
2961 | kfree(mibrsp.data); | |
2962 | ||
2963 | return 0; | |
2964 | } | |
2965 | ||
2966 | int slsi_handle_disconnect(struct slsi_dev *sdev, struct net_device *dev, u8 *peer_address, u16 reason, | |
2967 | u8 *disassoc_rsp_ie, u32 disassoc_rsp_ie_len) | |
2968 | { | |
2969 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
2970 | ||
2971 | if (WARN_ON(!dev)) | |
2972 | goto exit; | |
2973 | ||
2974 | SLSI_NET_DBG3(dev, SLSI_MLME, "slsi_handle_disconnect(vif:%d)\n", ndev_vif->ifnum); | |
2975 | ||
2976 | /* MUST only be called from somewhere that has acquired the lock */ | |
2977 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
2978 | ||
2979 | if (!ndev_vif->activated) { | |
2980 | SLSI_NET_DBG1(dev, SLSI_MLME, "VIF not activated\n"); | |
2981 | goto exit; | |
2982 | } | |
2983 | ||
2984 | switch (ndev_vif->vif_type) { | |
2985 | case FAPI_VIFTYPE_STATION: | |
2986 | { | |
2987 | netif_carrier_off(dev); | |
2988 | ||
2989 | /* MLME-DISCONNECT-IND could indicate the completion of a MLME-DISCONNECT-REQ or | |
2990 | * the connection with the AP has been lost | |
2991 | */ | |
2992 | if (ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTING) { | |
2993 | if (!peer_address) | |
2994 | SLSI_NET_WARN(dev, "Connection failure\n"); | |
2995 | } else if (ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED) { | |
2996 | if (reason == FAPI_REASONCODE_SYNCHRONISATION_LOSS) | |
2997 | reason = 0; /*reason code to recognise beacon loss */ | |
2998 | else if (reason == FAPI_REASONCODE_KEEP_ALIVE_FAILURE) | |
2999 | reason = WLAN_REASON_DEAUTH_LEAVING;/* Change to a standard reason code */ | |
3000 | else if (reason >= 0x8200 && reason <= 0x82FF) | |
3001 | reason = reason & 0x00FF; | |
3002 | ||
3003 | if (ndev_vif->sta.is_wps) /* Ignore sending deauth or disassoc event to cfg80211 during WPS session */ | |
3004 | SLSI_NET_INFO(dev, "Ignoring Deauth notification to cfg80211 from the peer during WPS procedure\n"); | |
3005 | else { | |
3006 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) | |
3007 | cfg80211_disconnected(dev, reason, disassoc_rsp_ie, disassoc_rsp_ie_len, | |
3008 | false, GFP_KERNEL); | |
3009 | #else | |
3010 | cfg80211_disconnected(dev, reason, disassoc_rsp_ie, disassoc_rsp_ie_len, | |
3011 | GFP_KERNEL); | |
3012 | #endif | |
3013 | SLSI_NET_DBG3(dev, SLSI_MLME, "Received disconnect from AP, reason = %d\n", reason); | |
3014 | } | |
3015 | } else if (ndev_vif->sta.vif_status == SLSI_VIF_STATUS_DISCONNECTING) { | |
3016 | /* Change keep alive and sync_loss reason code while sending to supplicant to a standard reason code */ | |
3017 | if (reason == FAPI_REASONCODE_KEEP_ALIVE_FAILURE || | |
3018 | reason == FAPI_REASONCODE_SYNCHRONISATION_LOSS) | |
3019 | reason = WLAN_REASON_DEAUTH_LEAVING; | |
3020 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) | |
3021 | cfg80211_disconnected(dev, reason, disassoc_rsp_ie, disassoc_rsp_ie_len, true, GFP_KERNEL); | |
3022 | #else | |
3023 | cfg80211_disconnected(dev, reason, disassoc_rsp_ie, disassoc_rsp_ie_len, GFP_KERNEL); | |
3024 | #endif | |
3025 | SLSI_NET_DBG3(dev, SLSI_MLME, "Completion of disconnect from AP\n"); | |
3026 | } else { | |
3027 | /* Vif status is in erronus state.*/ | |
3028 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) | |
3029 | cfg80211_disconnected(dev, reason, disassoc_rsp_ie, disassoc_rsp_ie_len, false, GFP_KERNEL); | |
3030 | #else | |
3031 | cfg80211_disconnected(dev, reason, disassoc_rsp_ie, disassoc_rsp_ie_len, GFP_KERNEL); | |
3032 | #endif | |
3033 | SLSI_NET_WARN(dev, "disconnect in wrong state vif_status(%d)\n", ndev_vif->sta.vif_status); | |
3034 | } | |
3035 | ||
3036 | ndev_vif->sta.is_wps = false; | |
3037 | ||
3038 | /* Populate bss records on incase of disconnection. | |
3039 | * For connection failure its not required. | |
3040 | */ | |
3041 | if (!(ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTING || | |
3042 | ndev_vif->sta.vif_status == SLSI_VIF_STATUS_UNSPECIFIED)) | |
3043 | slsi_populate_bss_record(dev); | |
3044 | ||
3045 | kfree(ndev_vif->sta.assoc_req_add_info_elem); | |
3046 | if (ndev_vif->sta.assoc_req_add_info_elem) { | |
3047 | ndev_vif->sta.assoc_req_add_info_elem = NULL; | |
3048 | ndev_vif->sta.assoc_req_add_info_elem_len = 0; | |
3049 | } | |
3050 | memset(ndev_vif->sta.ssid, 0, ndev_vif->sta.ssid_len); | |
3051 | memset(ndev_vif->sta.bssid, 0, ETH_ALEN); | |
3052 | ndev_vif->sta.ssid_len = 0; | |
3053 | #ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT | |
3054 | memset(&ndev_vif->enhanced_arp_stats, 0, sizeof(ndev_vif->enhanced_arp_stats)); | |
3055 | memset(ndev_vif->enhanced_arp_host_tag, 0, sizeof(ndev_vif->enhanced_arp_host_tag)); | |
3056 | ndev_vif->enhanced_arp_detect_enabled = false; | |
3057 | #endif | |
3058 | ||
3059 | #ifdef CONFIG_SCSC_WLAN_WES_NCHO | |
3060 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
3061 | sdev->device_config.ncho_mode = 0; | |
3062 | sdev->device_config.roam_scan_mode = 0; | |
3063 | sdev->device_config.dfs_scan_mode = 0; | |
3064 | sdev->device_config.dfs_scan_mode = 0; | |
3065 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
3066 | #endif | |
3067 | slsi_mlme_del_vif(sdev, dev); | |
3068 | slsi_vif_deactivated(sdev, dev); | |
3069 | break; | |
3070 | } | |
3071 | case FAPI_VIFTYPE_AP: | |
3072 | { | |
3073 | struct slsi_peer *peer = NULL; | |
3074 | ||
3075 | peer = slsi_get_peer_from_mac(sdev, dev, peer_address); | |
3076 | if (!peer) { | |
3077 | SLSI_NET_DBG1(dev, SLSI_MLME, "peer NOT found by MAC address\n"); | |
3078 | goto exit; | |
3079 | } | |
3080 | ||
3081 | SLSI_NET_DBG3(dev, SLSI_MLME, "MAC:%pM is_wps:%d Peer State = %d\n", peer_address, peer->is_wps, peer->connected_state); | |
3082 | slsi_fill_last_disconnected_sta_info(sdev, dev, peer_address, reason); | |
3083 | slsi_ps_port_control(sdev, dev, peer, SLSI_STA_CONN_STATE_DISCONNECTED); | |
3084 | if (((peer->connected_state == SLSI_STA_CONN_STATE_CONNECTED) || | |
3085 | (peer->connected_state == SLSI_STA_CONN_STATE_DOING_KEY_CONFIG)) && | |
3086 | !(peer->is_wps)) | |
3087 | cfg80211_del_sta(dev, peer->address, GFP_KERNEL); | |
3088 | ||
3089 | slsi_spinlock_lock(&ndev_vif->peer_lock); | |
3090 | slsi_peer_remove(sdev, dev, peer); | |
3091 | slsi_spinlock_unlock(&ndev_vif->peer_lock); | |
3092 | ||
3093 | /* If last client disconnects (after WPA2 handshake) then take wakelock till group is removed | |
3094 | * to avoid possibility of delay in group removal if platform suspends at this point. | |
3095 | */ | |
3096 | if (ndev_vif->ap.p2p_gc_keys_set && (ndev_vif->peer_sta_records == 0)) { | |
3097 | SLSI_NET_DBG2(dev, SLSI_MLME, "P2PGO - Acquire wakelock after last client disconnection\n"); | |
3098 | slsi_wake_lock(&sdev->wlan_wl); | |
3099 | } | |
3100 | break; | |
3101 | } | |
3102 | default: | |
3103 | SLSI_NET_WARN(dev, "mlme_disconnect_ind(vif:%d, unexpected vif type:%d)\n", ndev_vif->ifnum, ndev_vif->vif_type); | |
3104 | break; | |
3105 | } | |
3106 | exit: | |
3107 | return 0; | |
3108 | } | |
3109 | ||
3110 | int slsi_ps_port_control(struct slsi_dev *sdev, struct net_device *dev, struct slsi_peer *peer, enum slsi_sta_conn_state s) | |
3111 | { | |
3112 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3113 | ||
3114 | SLSI_UNUSED_PARAMETER(sdev); | |
3115 | ||
3116 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
3117 | ||
3118 | switch (s) { | |
3119 | case SLSI_STA_CONN_STATE_DISCONNECTED: | |
3120 | SLSI_NET_DBG1(dev, SLSI_TX, "STA disconnected, SET : FCQ - Disabled\n"); | |
3121 | peer->authorized = false; | |
3122 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP && !ndev_vif->peer_sta_records) | |
3123 | (void)scsc_wifi_fcq_8021x_port_state(dev, &ndev_vif->ap.group_data_qs, SCSC_WIFI_FCQ_8021x_STATE_BLOCKED); | |
3124 | return scsc_wifi_fcq_8021x_port_state(dev, &peer->data_qs, SCSC_WIFI_FCQ_8021x_STATE_BLOCKED); | |
3125 | ||
3126 | case SLSI_STA_CONN_STATE_DOING_KEY_CONFIG: | |
3127 | SLSI_NET_DBG1(dev, SLSI_TX, "STA doing KEY config, SET : FCQ - Disabled\n"); | |
3128 | peer->authorized = false; | |
3129 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP && !ndev_vif->peer_sta_records) | |
3130 | (void)scsc_wifi_fcq_8021x_port_state(dev, &ndev_vif->ap.group_data_qs, SCSC_WIFI_FCQ_8021x_STATE_BLOCKED); | |
3131 | return scsc_wifi_fcq_8021x_port_state(dev, &peer->data_qs, SCSC_WIFI_FCQ_8021x_STATE_BLOCKED); | |
3132 | ||
3133 | case SLSI_STA_CONN_STATE_CONNECTED: | |
3134 | SLSI_NET_DBG1(dev, SLSI_TX, "STA connected, SET : FCQ - Enabled\n"); | |
3135 | peer->authorized = true; | |
3136 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) | |
3137 | (void)scsc_wifi_fcq_8021x_port_state(dev, &ndev_vif->ap.group_data_qs, SCSC_WIFI_FCQ_8021x_STATE_OPEN); | |
3138 | return scsc_wifi_fcq_8021x_port_state(dev, &peer->data_qs, SCSC_WIFI_FCQ_8021x_STATE_OPEN); | |
3139 | ||
3140 | default: | |
3141 | SLSI_NET_DBG1(dev, SLSI_TX, "SET : FCQ - Disabled\n"); | |
3142 | peer->authorized = false; | |
3143 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP && !ndev_vif->peer_sta_records) | |
3144 | (void)scsc_wifi_fcq_8021x_port_state(dev, &ndev_vif->ap.group_data_qs, SCSC_WIFI_FCQ_8021x_STATE_BLOCKED); | |
3145 | return scsc_wifi_fcq_8021x_port_state(dev, &peer->data_qs, SCSC_WIFI_FCQ_8021x_STATE_BLOCKED); | |
3146 | } | |
3147 | ||
3148 | return 0; | |
3149 | } | |
3150 | ||
3151 | int slsi_set_uint_mib(struct slsi_dev *sdev, struct net_device *dev, u16 psid, int value) | |
3152 | { | |
3153 | struct slsi_mib_data mib_data = { 0, NULL }; | |
3154 | int r = 0; | |
3155 | ||
3156 | SLSI_DBG2(sdev, SLSI_MLME, "UINT MIB Set Request (PSID = 0x%04X, Value = %d)\n", psid, value); | |
3157 | ||
3158 | r = slsi_mib_encode_uint(&mib_data, psid, value, 0); | |
3159 | if (r == SLSI_MIB_STATUS_SUCCESS) { | |
3160 | if (mib_data.dataLength) { | |
3161 | r = slsi_mlme_set(sdev, dev, mib_data.data, mib_data.dataLength); | |
3162 | if (r != 0) | |
3163 | SLSI_ERR(sdev, "MIB (PSID = 0x%04X) set error = %d\n", psid, r); | |
3164 | kfree(mib_data.data); | |
3165 | } | |
3166 | } | |
3167 | return r; | |
3168 | } | |
3169 | ||
3170 | int slsi_send_max_transmit_msdu_lifetime(struct slsi_dev *dev, struct net_device *ndev, u32 msdu_lifetime) | |
3171 | { | |
3172 | #ifdef CCX_MSDU_LIFETIME_MIB_NA | |
3173 | struct slsi_mib_data mib_data = { 0, NULL }; | |
3174 | int error = 0; | |
3175 | ||
3176 | if (slsi_mib_encode_uint(&mib_data, SLSI_PSID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME, msdu_lifetime, 0) == SLSI_MIB_STATUS_SUCCESS) | |
3177 | if (mib_data.dataLength) { | |
3178 | error = slsi_mlme_set(dev, ndev, mib_data.data, mib_data.dataLength); | |
3179 | if (error) | |
3180 | SLSI_ERR(dev, "Err Sending max msdu lifetime failed. error = %d\n", error); | |
3181 | kfree(mib_data.data); | |
3182 | } | |
3183 | return error; | |
3184 | #endif | |
3185 | /* TODO: current firmware do not have this MIB yet */ | |
3186 | return 0; | |
3187 | } | |
3188 | ||
3189 | int slsi_read_max_transmit_msdu_lifetime(struct slsi_dev *dev, struct net_device *ndev, u32 *msdu_lifetime) | |
3190 | { | |
3191 | #ifdef CCX_MSDU_LIFETIME_MIB_NA | |
3192 | struct slsi_mib_data mib_data = { 0, NULL }; | |
3193 | struct slsi_mib_data mib_res = { 0, NULL }; | |
3194 | struct slsi_mib_entry mib_val; | |
3195 | int error = 0; | |
3196 | int mib_rx_len = 0; | |
3197 | size_t len; | |
3198 | ||
3199 | SLSI_UNUSED_PARAMETER(ndev); | |
3200 | ||
3201 | mib_res.dataLength = 10; /* PSID header(5) + dot11MaxReceiveLifetime 4 bytes + status(1) */ | |
3202 | mib_res.data = kmalloc(mib_res.dataLength, GFP_KERNEL); | |
3203 | ||
3204 | if (!mib_res.data) | |
3205 | return -ENOMEM; | |
3206 | ||
3207 | slsi_mib_encode_get(&mib_data, SLSI_PSID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME, 0); | |
3208 | error = slsi_mlme_get(dev, NULL, mib_data.data, mib_data.dataLength, | |
3209 | mib_res.data, mib_res.dataLength, &mib_rx_len); | |
3210 | kfree(mib_data.data); | |
3211 | ||
3212 | if (error) { | |
3213 | SLSI_ERR(dev, "Err Reading max msdu lifetime failed. error = %d\n", error); | |
3214 | kfree(mib_res.data); | |
3215 | return error; | |
3216 | } | |
3217 | ||
3218 | len = slsi_mib_decode(&mib_res, &mib_val); | |
3219 | ||
3220 | if (len != 8) { | |
3221 | kfree(mib_res.data); | |
3222 | return -EINVAL; | |
3223 | } | |
3224 | *msdu_lifetime = mib_val.value.u.uintValue; | |
3225 | ||
3226 | kfree(mib_res.data); | |
3227 | ||
3228 | return error; | |
3229 | #endif | |
3230 | /* TODO: current firmware do not have this MIB yet */ | |
3231 | return 0; | |
3232 | } | |
3233 | ||
3234 | void slsi_band_cfg_update(struct slsi_dev *sdev, int band) | |
3235 | { | |
3236 | /* TODO: lock scan_mutex*/ | |
3237 | switch (band) { | |
3238 | case SLSI_FREQ_BAND_AUTO: | |
3239 | sdev->wiphy->bands[0] = sdev->device_config.band_2G; | |
3240 | sdev->wiphy->bands[1] = sdev->device_config.band_5G; | |
3241 | break; | |
3242 | case SLSI_FREQ_BAND_5GHZ: | |
3243 | sdev->wiphy->bands[0] = NULL; | |
3244 | sdev->wiphy->bands[1] = sdev->device_config.band_5G; | |
3245 | break; | |
3246 | case SLSI_FREQ_BAND_2GHZ: | |
3247 | sdev->wiphy->bands[0] = sdev->device_config.band_2G; | |
3248 | sdev->wiphy->bands[1] = NULL; | |
3249 | break; | |
3250 | default: | |
3251 | break; | |
3252 | } | |
3253 | wiphy_apply_custom_regulatory(sdev->wiphy, sdev->device_config.domain_info.regdomain); | |
3254 | slsi_update_supported_channels_regd_flags(sdev); | |
3255 | } | |
3256 | ||
3257 | int slsi_band_update(struct slsi_dev *sdev, int band) | |
3258 | { | |
3259 | int i; | |
3260 | struct net_device *dev; | |
3261 | struct netdev_vif *ndev_vif; | |
3262 | ||
3263 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
3264 | ||
3265 | SLSI_DBG3(sdev, SLSI_CFG80211, "supported_band:%d\n", band); | |
3266 | ||
3267 | if (band == sdev->device_config.supported_band) { | |
3268 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
3269 | return 0; | |
3270 | } | |
3271 | ||
3272 | sdev->device_config.supported_band = band; | |
3273 | ||
3274 | slsi_band_cfg_update(sdev, band); | |
3275 | ||
3276 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
3277 | ||
3278 | /* If new band is auto(2.4GHz + 5GHz, no need to check for station connection.*/ | |
3279 | if (band == 0) | |
3280 | return 0; | |
3281 | ||
3282 | /* If station is connected on any rejected band, disconnect the station. */ | |
3283 | SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex); | |
3284 | for (i = 1; i < (CONFIG_SCSC_WLAN_MAX_INTERFACES + 1); i++) { | |
3285 | dev = slsi_get_netdev_locked(sdev, i); | |
3286 | if (!dev) | |
3287 | break; | |
3288 | ndev_vif = netdev_priv(dev); | |
3289 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
3290 | /** | |
3291 | * 1. vif should be activated and vif type should be station. | |
3292 | * 2. Station should be either in connecting or connected state. | |
3293 | * 3. if (new band is 5G and connection is on 2.4) or (new band is 2.4 and connection is 5) | |
3294 | * when all the above conditions are true drop the connection | |
3295 | * Do not wait for disconnect ind. | |
3296 | */ | |
3297 | if ((ndev_vif->activated) && (ndev_vif->vif_type == FAPI_VIFTYPE_STATION) && | |
3298 | (ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTING || ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED) && | |
3299 | (ndev_vif->chan->hw_value <= 14 ? band == SLSI_FREQ_BAND_5GHZ : band == SLSI_FREQ_BAND_2GHZ)) { | |
3300 | int r; | |
3301 | ||
3302 | if (!ndev_vif->sta.sta_bss) { | |
3303 | SLSI_ERR(sdev, "slsi_mlme_disconnect failed, sta_bss is not available\n"); | |
3304 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
3305 | SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); | |
3306 | return -EINVAL; | |
3307 | } | |
3308 | ||
3309 | r = slsi_mlme_disconnect(sdev, dev, ndev_vif->sta.sta_bss->bssid, WLAN_REASON_DEAUTH_LEAVING, true); | |
3310 | LOG_CONDITIONALLY(r != 0, SLSI_ERR(sdev, "slsi_mlme_disconnect(%pM) failed with %d\n", ndev_vif->sta.sta_bss->bssid, r)); | |
3311 | ||
3312 | r = slsi_handle_disconnect(sdev, dev, ndev_vif->sta.sta_bss->bssid, 0, NULL, 0); | |
3313 | LOG_CONDITIONALLY(r != 0, SLSI_ERR(sdev, "slsi_handle_disconnect(%pM) failed with %d\n", ndev_vif->sta.sta_bss->bssid, r)); | |
3314 | } | |
3315 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
3316 | } | |
3317 | SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex); | |
3318 | ||
3319 | return 0; | |
3320 | } | |
3321 | ||
3322 | /* This takes care to free the SKB on failure */ | |
3323 | int slsi_send_gratuitous_arp(struct slsi_dev *sdev, struct net_device *dev) | |
3324 | { | |
3325 | int ret = 0; | |
3326 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3327 | struct sk_buff *arp; | |
3328 | struct ethhdr *ehdr; | |
3329 | static const u8 arp_hdr[] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01 }; | |
3330 | int arp_size = sizeof(arp_hdr) + ETH_ALEN + sizeof(ndev_vif->ipaddress) + ETH_ALEN + sizeof(ndev_vif->ipaddress); | |
3331 | ||
3332 | SLSI_NET_DBG2(dev, SLSI_CFG80211, "\n"); | |
3333 | ||
3334 | if (!ndev_vif->ipaddress) | |
3335 | return 0; | |
3336 | ||
3337 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
3338 | ||
3339 | if (WARN_ON(!ndev_vif->activated)) | |
3340 | return -EINVAL; | |
3341 | if (WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION)) | |
3342 | return -EINVAL; | |
3343 | if (WARN_ON(ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) | |
3344 | return -EINVAL; | |
3345 | ||
3346 | SLSI_NET_DBG2(dev, SLSI_CFG80211, "IP:%pI4\n", &ndev_vif->ipaddress); | |
3347 | ||
3348 | arp = slsi_alloc_skb_headroom(sizeof(struct ethhdr) + arp_size, GFP_KERNEL); | |
3349 | if (WARN_ON(!arp)) | |
3350 | return -ENOMEM; | |
3351 | ||
3352 | /* The Ethernet header is accessed in the stack. */ | |
3353 | skb_reset_mac_header(arp); | |
3354 | ||
3355 | /* Ethernet Header */ | |
3356 | ehdr = (struct ethhdr *)skb_put(arp, sizeof(struct ethhdr)); | |
3357 | memset(ehdr->h_dest, 0xFF, ETH_ALEN); | |
3358 | SLSI_ETHER_COPY(ehdr->h_source, dev->dev_addr); | |
3359 | ehdr->h_proto = cpu_to_be16(ETH_P_ARP); | |
3360 | ||
3361 | /* Arp Data */ | |
3362 | memcpy(skb_put(arp, sizeof(arp_hdr)), arp_hdr, sizeof(arp_hdr)); | |
3363 | SLSI_ETHER_COPY(skb_put(arp, ETH_ALEN), dev->dev_addr); | |
3364 | memcpy(skb_put(arp, sizeof(ndev_vif->ipaddress)), &ndev_vif->ipaddress, sizeof(ndev_vif->ipaddress)); | |
3365 | memset(skb_put(arp, ETH_ALEN), 0xFF, ETH_ALEN); | |
3366 | memcpy(skb_put(arp, sizeof(ndev_vif->ipaddress)), &ndev_vif->ipaddress, sizeof(ndev_vif->ipaddress)); | |
3367 | ||
3368 | arp->dev = dev; | |
3369 | arp->protocol = ETH_P_ARP; | |
3370 | arp->ip_summed = CHECKSUM_UNNECESSARY; | |
3371 | arp->queue_mapping = slsi_netif_get_peer_queue(0, 0); /* Queueset 0 AC 0 */ | |
3372 | ||
3373 | ret = slsi_tx_data(sdev, dev, arp); | |
3374 | if (ret) | |
3375 | slsi_kfree_skb(arp); | |
3376 | ||
3377 | return ret; | |
3378 | } | |
3379 | ||
3380 | const u8 addr_mask[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | |
3381 | const u8 solicited_node_addr_mask[6] = { 0x33, 0x33, 0xff, 0x00, 0x00, 0x01 }; | |
3382 | ||
3383 | static void slsi_create_packet_filter_element(u8 filterid, | |
3384 | u8 pkt_filter_mode, | |
3385 | u8 num_pattern_desc, | |
3386 | struct slsi_mlme_pattern_desc *pattern_desc, | |
3387 | struct slsi_mlme_pkt_filter_elem *pkt_filter_elem, | |
3388 | u8 *pkt_filters_len) | |
3389 | { | |
3390 | u8 pkt_filter_hdr[SLSI_PKT_FILTER_ELEM_HDR_LEN] = { 0xdd, /* vendor ie*/ | |
3391 | 0x00, /*Length to be filled*/ | |
3392 | 0x00, 0x16, 0x32, /*oui*/ | |
3393 | 0x02, | |
3394 | filterid, /*filter id to be filled*/ | |
3395 | pkt_filter_mode /* pkt filter mode to be filled */ | |
3396 | }; | |
3397 | u8 i, pattern_desc_len = 0; | |
3398 | ||
3399 | WARN_ON(num_pattern_desc > SLSI_MAX_PATTERN_DESC); | |
3400 | ||
3401 | memcpy(pkt_filter_elem->header, pkt_filter_hdr, SLSI_PKT_FILTER_ELEM_HDR_LEN); | |
3402 | pkt_filter_elem->num_pattern_desc = num_pattern_desc; | |
3403 | ||
3404 | for (i = 0; i < num_pattern_desc; i++) { | |
3405 | memcpy(&pkt_filter_elem->pattern_desc[i], &pattern_desc[i], sizeof(struct slsi_mlme_pattern_desc)); | |
3406 | pattern_desc_len += SLSI_PKT_DESC_FIXED_LEN + (2 * pattern_desc[i].mask_length); | |
3407 | } | |
3408 | ||
3409 | /*Update the length in the header*/ | |
3410 | pkt_filter_elem->header[1] = SLSI_PKT_FILTER_ELEM_FIXED_LEN + pattern_desc_len; | |
3411 | *pkt_filters_len += (SLSI_PKT_FILTER_ELEM_HDR_LEN + pattern_desc_len); | |
3412 | ||
3413 | SLSI_DBG3_NODEV(SLSI_MLME, "filterid=0x%x,pkt_filter_mode=0x%x,num_pattern_desc=0x%x\n", | |
3414 | filterid, pkt_filter_mode, num_pattern_desc); | |
3415 | } | |
3416 | ||
3417 | #define SLSI_SCREEN_OFF_FILTERS_COUNT 1 | |
3418 | ||
3419 | static int slsi_set_common_packet_filters(struct slsi_dev *sdev, struct net_device *dev) | |
3420 | { | |
3421 | struct slsi_mlme_pattern_desc pattern_desc; | |
3422 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem[1]; | |
3423 | u8 pkt_filters_len = 0, num_filters = 0; | |
3424 | ||
3425 | /*Opt out all broadcast and multicast packets (filter on I/G bit)*/ | |
3426 | pattern_desc.offset = 0; | |
3427 | pattern_desc.mask_length = 1; | |
3428 | pattern_desc.mask[0] = 0x01; | |
3429 | pattern_desc.pattern[0] = 0x01; | |
3430 | ||
3431 | slsi_create_packet_filter_element(SLSI_ALL_BC_MC_FILTER_ID, | |
3432 | FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP | FAPI_PACKETFILTERMODE_OPT_OUT, | |
3433 | 1, &pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3434 | num_filters++; | |
3435 | return slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
3436 | } | |
3437 | ||
3438 | int slsi_set_arp_packet_filter(struct slsi_dev *sdev, struct net_device *dev) | |
3439 | { | |
3440 | struct slsi_mlme_pattern_desc pattern_desc[SLSI_MAX_PATTERN_DESC]; | |
3441 | int num_pattern_desc = 0; | |
3442 | u8 pkt_filters_len = 0, num_filters = 0; | |
3443 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem[2]; | |
3444 | int ret; | |
3445 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3446 | struct slsi_peer *peer = slsi_get_peer_from_qs(sdev, dev, SLSI_STA_PEER_QUEUESET); | |
3447 | ||
3448 | if (WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION)) | |
3449 | return -EINVAL; | |
3450 | ||
3451 | if (WARN_ON(!peer)) | |
3452 | return -EINVAL; | |
3453 | ||
3454 | if (slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) | |
3455 | return 0; | |
3456 | ||
3457 | /*Set the IP address while suspending as this will be used by firmware for ARP/NDP offloading*/ | |
3458 | slsi_mlme_set_ip_address(sdev, dev); | |
3459 | #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
3460 | slsi_mlme_set_ipv6_address(sdev, dev); | |
3461 | #endif | |
3462 | ||
3463 | SLSI_NET_DBG2(dev, SLSI_MLME, "Set ARP filter\n"); | |
3464 | ||
3465 | /* Opt out all ARP requests*/ | |
3466 | num_pattern_desc = 0; | |
3467 | SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], ETH_P_ARP); | |
3468 | num_pattern_desc++; | |
3469 | ||
3470 | /* ARP - Request */ | |
3471 | pattern_desc[num_pattern_desc].offset = 0x14; /*sizeof(struct ethhdr) + offsetof(ar_op)*/ | |
3472 | pattern_desc[num_pattern_desc].mask_length = 2; | |
3473 | pattern_desc[num_pattern_desc].mask[0] = 0xff; | |
3474 | pattern_desc[num_pattern_desc].mask[1] = 0xff; | |
3475 | pattern_desc[num_pattern_desc].pattern[0] = 0x00; | |
3476 | pattern_desc[num_pattern_desc].pattern[1] = 0x01; | |
3477 | num_pattern_desc++; | |
3478 | ||
3479 | slsi_create_packet_filter_element(SLSI_ALL_ARP_FILTER_ID, | |
3480 | FAPI_PACKETFILTERMODE_OPT_OUT | FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, | |
3481 | num_pattern_desc, pattern_desc, | |
3482 | &pkt_filter_elem[num_filters], | |
3483 | &pkt_filters_len); | |
3484 | num_filters++; | |
3485 | ||
3486 | /*Opt-in arp packet for device IP address*/ | |
3487 | num_pattern_desc = 0; | |
3488 | SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], ETH_P_ARP); | |
3489 | num_pattern_desc++; | |
3490 | ||
3491 | pattern_desc[num_pattern_desc].offset = 0x26; /*filtering on Target IP Address*/ | |
3492 | pattern_desc[num_pattern_desc].mask_length = 4; | |
3493 | memcpy(pattern_desc[num_pattern_desc].mask, addr_mask, pattern_desc[num_pattern_desc].mask_length); | |
3494 | memcpy(pattern_desc[num_pattern_desc].pattern, &ndev_vif->ipaddress, pattern_desc[num_pattern_desc].mask_length); | |
3495 | num_pattern_desc++; | |
3496 | ||
3497 | slsi_create_packet_filter_element(SLSI_LOCAL_ARP_FILTER_ID, | |
3498 | FAPI_PACKETFILTERMODE_OPT_IN | FAPI_PACKETFILTERMODE_OPT_IN_SLEEP, | |
3499 | num_pattern_desc, pattern_desc, | |
3500 | &pkt_filter_elem[num_filters], | |
3501 | &pkt_filters_len); | |
3502 | num_filters++; | |
3503 | ||
3504 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
3505 | if (ret) | |
3506 | return ret; | |
3507 | ||
3508 | #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
3509 | pkt_filters_len = 0; | |
3510 | num_filters = 0; | |
3511 | /*Opt in the multicast NS packets for Local IP address in active mode*/ | |
3512 | num_pattern_desc = 0; | |
3513 | pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ | |
3514 | pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; | |
3515 | SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); | |
3516 | memcpy(pattern_desc[num_pattern_desc].pattern, solicited_node_addr_mask, 3); | |
3517 | memcpy(&pattern_desc[num_pattern_desc].pattern[3], &ndev_vif->ipv6address.s6_addr[13], 3); /* last 3 bytes of IPv6 address*/ | |
3518 | num_pattern_desc++; | |
3519 | ||
3520 | /*filter on ethertype ARP*/ | |
3521 | SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], 0x86DD); | |
3522 | num_pattern_desc++; | |
3523 | ||
3524 | pattern_desc[num_pattern_desc].offset = 0x14; /*filtering on next header*/ | |
3525 | pattern_desc[num_pattern_desc].mask_length = 1; | |
3526 | pattern_desc[num_pattern_desc].mask[0] = 0xff; | |
3527 | pattern_desc[num_pattern_desc].pattern[0] = 0x3a; | |
3528 | num_pattern_desc++; | |
3529 | ||
3530 | pattern_desc[num_pattern_desc].offset = 0x36; /*filtering on ICMP6 packet type*/ | |
3531 | pattern_desc[num_pattern_desc].mask_length = 1; | |
3532 | pattern_desc[num_pattern_desc].mask[0] = 0xff; | |
3533 | pattern_desc[num_pattern_desc].pattern[0] = 0x87; /* Neighbor Solicitation type in ICMPv6 */ | |
3534 | num_pattern_desc++; | |
3535 | ||
3536 | slsi_create_packet_filter_element(SLSI_LOCAL_NS_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_IN, | |
3537 | num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3538 | num_filters++; | |
3539 | ||
3540 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
3541 | if (ret) | |
3542 | return ret; | |
3543 | #endif | |
3544 | ||
3545 | return ret; | |
3546 | } | |
3547 | ||
3548 | #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER | |
3549 | int slsi_set_enhanced_pkt_filter(struct net_device *dev, u8 pkt_filter_enable) | |
3550 | { | |
3551 | struct netdev_vif *netdev_vif = netdev_priv(dev); | |
3552 | struct slsi_dev *sdev = netdev_vif->sdev; | |
3553 | int ret = 0; | |
3554 | int is_suspend = 0; | |
3555 | ||
3556 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
3557 | is_suspend = sdev->device_config.user_suspend_mode; | |
3558 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
3559 | ||
3560 | if (is_suspend) { | |
3561 | SLSI_ERR(sdev, "Host is in early suspend state.\n"); | |
3562 | return -EPERM; /* set_enhanced_pkt_filter should not be called after suspend */ | |
3563 | } | |
3564 | ||
3565 | sdev->enhanced_pkt_filter_enabled = pkt_filter_enable; | |
3566 | SLSI_INFO(sdev, "Enhanced packet filter is %s", (pkt_filter_enable ? "enabled" : "disabled")); | |
3567 | return ret; | |
3568 | } | |
3569 | ||
3570 | static int slsi_set_opt_out_unicast_packet_filter(struct slsi_dev *sdev, struct net_device *dev) | |
3571 | { | |
3572 | struct slsi_mlme_pattern_desc pattern_desc; | |
3573 | u8 pkt_filters_len = 0; | |
3574 | int ret = 0; | |
3575 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem; | |
3576 | ||
3577 | /* IPv4 packet */ | |
3578 | pattern_desc.offset = 0; /* destination mac address*/ | |
3579 | pattern_desc.mask_length = ETH_ALEN; | |
3580 | memset(pattern_desc.mask, 0xff, ETH_ALEN); | |
3581 | memcpy(pattern_desc.pattern, sdev->hw_addr, ETH_ALEN); | |
3582 | ||
3583 | slsi_create_packet_filter_element(SLSI_OPT_OUT_ALL_FILTER_ID, | |
3584 | FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, | |
3585 | 1, &pattern_desc, | |
3586 | &pkt_filter_elem, &pkt_filters_len); | |
3587 | ||
3588 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, 1, &pkt_filter_elem); | |
3589 | ||
3590 | return ret; | |
3591 | } | |
3592 | ||
3593 | static int slsi_set_opt_in_tcp4_packet_filter(struct slsi_dev *sdev, struct net_device *dev) | |
3594 | { | |
3595 | struct slsi_mlme_pattern_desc pattern_desc[2]; | |
3596 | u8 pkt_filters_len = 0; | |
3597 | int ret = 0; | |
3598 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem; | |
3599 | ||
3600 | /* IPv4 packet */ | |
3601 | pattern_desc[0].offset = ETH_ALEN + ETH_ALEN; /* ethhdr->h_proto */ | |
3602 | pattern_desc[0].mask_length = 2; | |
3603 | pattern_desc[0].mask[0] = 0xff; /* Big endian 0xffff */ | |
3604 | pattern_desc[0].mask[1] = 0xff; | |
3605 | pattern_desc[0].pattern[0] = 0x08; /* Big endian 0x0800 */ | |
3606 | pattern_desc[0].pattern[1] = 0x00; | |
3607 | ||
3608 | /* dest.addr(6) + src.addr(6) + Protocol(2) = sizeof(struct ethhdr) = 14 */ | |
3609 | /* VER(1) + Svc(1) + TotalLen(2) + ID(2) + Flag&Fragmentation(2) + TTL(1) = 9 */ | |
3610 | pattern_desc[1].offset = 23; /* iphdr->protocol */ | |
3611 | pattern_desc[1].mask_length = 1; | |
3612 | pattern_desc[1].mask[0] = 0xff; | |
3613 | pattern_desc[1].pattern[0] = IPPROTO_TCP; /* 0x11 */ | |
3614 | slsi_create_packet_filter_element(SLSI_OPT_IN_TCP4_FILTER_ID, | |
3615 | FAPI_PACKETFILTERMODE_OPT_IN_SLEEP, | |
3616 | 2, | |
3617 | pattern_desc, | |
3618 | &pkt_filter_elem, | |
3619 | &pkt_filters_len); | |
3620 | ||
3621 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, 1, &pkt_filter_elem); | |
3622 | ||
3623 | return ret; | |
3624 | } | |
3625 | ||
3626 | static int slsi_set_opt_in_tcp6_packet_filter(struct slsi_dev *sdev, struct net_device *dev) | |
3627 | { | |
3628 | struct slsi_mlme_pattern_desc pattern_desc[2]; | |
3629 | u8 pkt_filters_len = 0; | |
3630 | int ret = 0; | |
3631 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem; | |
3632 | ||
3633 | /* IPv6 packet */ | |
3634 | pattern_desc[0].offset = ETH_ALEN + ETH_ALEN; /* ethhdr->h_proto */ | |
3635 | pattern_desc[0].mask_length = 2; | |
3636 | pattern_desc[0].mask[0] = 0xff; /* Big endian 0xffff */ | |
3637 | pattern_desc[0].mask[1] = 0xff; | |
3638 | pattern_desc[0].pattern[0] = 0x86; /* Big endian 0x86DD */ | |
3639 | pattern_desc[0].pattern[1] = 0xdd; | |
3640 | ||
3641 | pattern_desc[1].offset = sizeof(struct ethhdr) + 6; /*filtering on ipv6->next header*/ | |
3642 | pattern_desc[1].mask_length = 1; | |
3643 | pattern_desc[1].mask[0] = 0xff; | |
3644 | pattern_desc[1].pattern[0] = IPPROTO_TCP; | |
3645 | ||
3646 | slsi_create_packet_filter_element(SLSI_OPT_IN_TCP6_FILTER_ID, | |
3647 | FAPI_PACKETFILTERMODE_OPT_IN_SLEEP, | |
3648 | 2, | |
3649 | pattern_desc, | |
3650 | &pkt_filter_elem, | |
3651 | &pkt_filters_len); | |
3652 | ||
3653 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, 1, &pkt_filter_elem); | |
3654 | ||
3655 | return ret; | |
3656 | } | |
3657 | #endif | |
3658 | ||
3659 | static int slsi_set_multicast_packet_filters(struct slsi_dev *sdev, struct net_device *dev) | |
3660 | { | |
3661 | struct slsi_mlme_pattern_desc pattern_desc[3]; | |
3662 | u8 pkt_filters_len = 0, i, num_filters = 0; | |
3663 | u8 num_pattern_desc = 0; | |
3664 | int ret = 0; | |
3665 | struct slsi_mlme_pkt_filter_elem *pkt_filter_elem = NULL; | |
3666 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3667 | u8 mc_filter_id, mc_filter_count; | |
3668 | ||
3669 | /* Multicast packets for registered multicast addresses to be opted in on screen off*/ | |
3670 | SLSI_NET_DBG2(dev, SLSI_MLME, "Set mc filters ,regd mc addr count =%d\n", ndev_vif->sta.regd_mc_addr_count); | |
3671 | ||
3672 | mc_filter_count = ndev_vif->sta.regd_mc_addr_count; | |
3673 | pkt_filter_elem = kmalloc(((mc_filter_count + 1) * sizeof(struct slsi_mlme_pkt_filter_elem)), GFP_KERNEL); | |
3674 | if (!pkt_filter_elem) { | |
3675 | SLSI_NET_ERR(dev, "ERROR Memory allocation failure\n"); | |
3676 | return -ENOMEM; | |
3677 | } | |
3678 | ||
3679 | /* Abnormal multicast filter */ | |
3680 | pattern_desc[num_pattern_desc].offset = 0; /* destination mac address*/ | |
3681 | pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; | |
3682 | memset(pattern_desc[num_pattern_desc].mask, 0xff, ETH_ALEN); | |
3683 | memcpy(pattern_desc[num_pattern_desc].pattern, dev->dev_addr, ETH_ALEN); | |
3684 | num_pattern_desc++; | |
3685 | ||
3686 | pattern_desc[num_pattern_desc].offset = ETH_ALEN + ETH_ALEN; /* ethhdr->h_proto == IPv4 */ | |
3687 | pattern_desc[num_pattern_desc].mask_length = 2; | |
3688 | pattern_desc[num_pattern_desc].mask[0] = 0xff; /* Big endian 0xffff */ | |
3689 | pattern_desc[num_pattern_desc].mask[1] = 0xff; | |
3690 | pattern_desc[num_pattern_desc].pattern[0] = 0x08; /* Big endian 0x0800 */ | |
3691 | pattern_desc[num_pattern_desc].pattern[1] = 0x00; | |
3692 | num_pattern_desc++; | |
3693 | ||
3694 | pattern_desc[num_pattern_desc].offset = sizeof(struct ethhdr) + offsetof(struct iphdr, daddr); /* iphdr->daddr starts with 1110 */ | |
3695 | pattern_desc[num_pattern_desc].mask_length = 1; | |
3696 | pattern_desc[num_pattern_desc].mask[0] = 0xf0; | |
3697 | pattern_desc[num_pattern_desc].pattern[0] = 0xe0; /* 224 */ | |
3698 | num_pattern_desc++; | |
3699 | slsi_create_packet_filter_element(SLSI_ABNORMAL_MULTICAST_ID, | |
3700 | FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, | |
3701 | num_pattern_desc, pattern_desc, | |
3702 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3703 | num_filters++; | |
3704 | ||
3705 | /*Regd multicast addresses filter*/ | |
3706 | pattern_desc[0].offset = 0; | |
3707 | pattern_desc[0].mask_length = ETH_ALEN; | |
3708 | SLSI_ETHER_COPY(pattern_desc[0].mask, addr_mask); | |
3709 | ||
3710 | for (i = 0; i < mc_filter_count; i++) { | |
3711 | SLSI_ETHER_COPY(pattern_desc[0].pattern, ndev_vif->sta.regd_mc_addr[i]); | |
3712 | mc_filter_id = SLSI_REGD_MC_FILTER_ID + i; | |
3713 | #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER | |
3714 | if (sdev->enhanced_pkt_filter_enabled) | |
3715 | slsi_create_packet_filter_element(mc_filter_id, | |
3716 | FAPI_PACKETFILTERMODE_OPT_IN, | |
3717 | 1, &pattern_desc[0], | |
3718 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3719 | else | |
3720 | #endif | |
3721 | slsi_create_packet_filter_element(mc_filter_id, | |
3722 | FAPI_PACKETFILTERMODE_OPT_IN | | |
3723 | FAPI_PACKETFILTERMODE_OPT_IN_SLEEP, | |
3724 | 1, &pattern_desc[0], | |
3725 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3726 | num_filters++; | |
3727 | } | |
3728 | ||
3729 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
3730 | kfree(pkt_filter_elem); | |
3731 | ||
3732 | return ret; | |
3733 | } | |
3734 | ||
3735 | int slsi_clear_packet_filters(struct slsi_dev *sdev, struct net_device *dev) | |
3736 | { | |
3737 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3738 | struct slsi_peer *peer = slsi_get_peer_from_qs(sdev, dev, SLSI_STA_PEER_QUEUESET); | |
3739 | ||
3740 | u8 i, pkt_filters_len = 0; | |
3741 | int num_filters = 0; | |
3742 | int ret = 0; | |
3743 | struct slsi_mlme_pkt_filter_elem *pkt_filter_elem; | |
3744 | u8 mc_filter_id; | |
3745 | ||
3746 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
3747 | ||
3748 | if (WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION)) | |
3749 | return -EINVAL; | |
3750 | ||
3751 | if (WARN_ON(!peer)) | |
3752 | return -EINVAL; | |
3753 | ||
3754 | SLSI_NET_DBG2(dev, SLSI_MLME, "Clear filters on Screen on"); | |
3755 | ||
3756 | /* calculate number of filters (regd_mc_addr_count + abnormal_multicast filter + SLSI_SCREEN_OFF_FILTERS_COUNT) */ | |
3757 | num_filters = ndev_vif->sta.regd_mc_addr_count + 1 + SLSI_SCREEN_OFF_FILTERS_COUNT; | |
3758 | if ((slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) == false) { | |
3759 | num_filters++; | |
3760 | num_filters++; | |
3761 | #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
3762 | num_filters++; | |
3763 | #endif | |
3764 | } | |
3765 | ||
3766 | #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER | |
3767 | if (sdev->enhanced_pkt_filter_enabled) { | |
3768 | num_filters++; /*All OPT OUT*/ | |
3769 | num_filters++; /*TCP IPv4 OPT IN*/ | |
3770 | num_filters++; /*TCP IPv6 OPT IN*/ | |
3771 | } | |
3772 | #endif | |
3773 | pkt_filter_elem = kmalloc((num_filters * sizeof(struct slsi_mlme_pkt_filter_elem)), GFP_KERNEL); | |
3774 | if (!pkt_filter_elem) { | |
3775 | SLSI_NET_ERR(dev, "ERROR Memory allocation failure"); | |
3776 | return -ENOMEM; | |
3777 | } | |
3778 | ||
3779 | num_filters = 0; | |
3780 | for (i = 0; i < ndev_vif->sta.regd_mc_addr_count; i++) { | |
3781 | mc_filter_id = SLSI_REGD_MC_FILTER_ID + i; | |
3782 | slsi_create_packet_filter_element(mc_filter_id, 0, 0, NULL, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3783 | num_filters++; | |
3784 | } | |
3785 | if ((slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) == false) { | |
3786 | slsi_create_packet_filter_element(SLSI_LOCAL_ARP_FILTER_ID, 0, 0, NULL, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3787 | num_filters++; | |
3788 | slsi_create_packet_filter_element(SLSI_ALL_ARP_FILTER_ID, 0, 0, NULL, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3789 | num_filters++; | |
3790 | #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
3791 | slsi_create_packet_filter_element(SLSI_LOCAL_NS_FILTER_ID, 0, 0, NULL, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3792 | num_filters++; | |
3793 | #endif | |
3794 | } | |
3795 | ||
3796 | slsi_create_packet_filter_element(SLSI_ALL_BC_MC_FILTER_ID, 0, 0, NULL, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3797 | num_filters++; | |
3798 | ||
3799 | #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER | |
3800 | if (sdev->enhanced_pkt_filter_enabled) { | |
3801 | slsi_create_packet_filter_element(SLSI_OPT_OUT_ALL_FILTER_ID, 0, 0, NULL, | |
3802 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3803 | num_filters++; | |
3804 | slsi_create_packet_filter_element(SLSI_OPT_IN_TCP4_FILTER_ID, 0, 0, NULL, | |
3805 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3806 | num_filters++; | |
3807 | slsi_create_packet_filter_element(SLSI_OPT_IN_TCP6_FILTER_ID, 0, 0, NULL, | |
3808 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3809 | num_filters++; | |
3810 | } | |
3811 | #endif | |
3812 | slsi_create_packet_filter_element(SLSI_ABNORMAL_MULTICAST_ID, 0, 0, NULL, | |
3813 | &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3814 | num_filters++; | |
3815 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
3816 | kfree(pkt_filter_elem); | |
3817 | return ret; | |
3818 | } | |
3819 | ||
3820 | int slsi_update_packet_filters(struct slsi_dev *sdev, struct net_device *dev) | |
3821 | { | |
3822 | int ret = 0; | |
3823 | ||
3824 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3825 | ||
3826 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
3827 | WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION); | |
3828 | ||
3829 | ret = slsi_set_multicast_packet_filters(sdev, dev); | |
3830 | if (ret) | |
3831 | return ret; | |
3832 | ||
3833 | ret = slsi_set_arp_packet_filter(sdev, dev); | |
3834 | if (ret) | |
3835 | return ret; | |
3836 | ||
3837 | #ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER | |
3838 | if (sdev->enhanced_pkt_filter_enabled) { | |
3839 | ret = slsi_set_opt_out_unicast_packet_filter(sdev, dev); | |
3840 | if (ret) | |
3841 | return ret; | |
3842 | ret = slsi_set_opt_in_tcp4_packet_filter(sdev, dev); | |
3843 | if (ret) | |
3844 | return ret; | |
3845 | ret = slsi_set_opt_in_tcp6_packet_filter(sdev, dev); | |
3846 | if (ret) | |
3847 | return ret; | |
3848 | } | |
3849 | #endif | |
3850 | return slsi_set_common_packet_filters(sdev, dev); | |
3851 | } | |
3852 | ||
3853 | #define IPV6_PF_PATTERN_MASK 0xf0 | |
3854 | #define IPV6_PF_PATTERN 0x60 | |
3855 | ||
3856 | #ifdef CONFIG_SCSC_WLAN_DISABLE_NAT_KA | |
3857 | #define SLSI_ON_CONNECT_FILTERS_COUNT 2 | |
3858 | #else | |
3859 | #define SLSI_ON_CONNECT_FILTERS_COUNT 3 | |
3860 | #endif | |
3861 | ||
3862 | void slsi_set_packet_filters(struct slsi_dev *sdev, struct net_device *dev) | |
3863 | { | |
3864 | struct slsi_mlme_pattern_desc pattern_desc[SLSI_MAX_PATTERN_DESC]; | |
3865 | int num_pattern_desc = 0; | |
3866 | u8 pkt_filters_len = 0; | |
3867 | int num_filters = 0; | |
3868 | ||
3869 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem[SLSI_ON_CONNECT_FILTERS_COUNT]; | |
3870 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3871 | struct slsi_peer *peer = slsi_get_peer_from_qs(sdev, dev, SLSI_STA_PEER_QUEUESET); | |
3872 | const u8 *ie; | |
3873 | ||
3874 | if (WARN_ON(!ndev_vif->activated)) | |
3875 | return; | |
3876 | ||
3877 | if (WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION)) | |
3878 | return; | |
3879 | ||
3880 | if (WARN_ON(!peer)) | |
3881 | return; | |
3882 | ||
3883 | if (WARN_ON(!peer->assoc_resp_ie)) | |
3884 | return; | |
3885 | ||
3886 | #ifdef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
3887 | ||
3888 | /*Opt out all IPv6 packets in active and suspended mode (ipv6 filtering)*/ | |
3889 | num_pattern_desc = 0; | |
3890 | pattern_desc[num_pattern_desc].offset = 0x0E; /*filtering on IP Protocol version*/ | |
3891 | pattern_desc[num_pattern_desc].mask_length = 1; | |
3892 | pattern_desc[num_pattern_desc].mask[0] = IPV6_PF_PATTERN_MASK; | |
3893 | pattern_desc[num_pattern_desc].pattern[0] = IPV6_PF_PATTERN; | |
3894 | num_pattern_desc++; | |
3895 | ||
3896 | slsi_create_packet_filter_element(SLSI_ALL_IPV6_PKTS_FILTER_ID, | |
3897 | FAPI_PACKETFILTERMODE_OPT_OUT | FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, | |
3898 | num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3899 | num_filters++; | |
3900 | ||
3901 | #endif | |
3902 | ||
3903 | ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, SLSI_WLAN_OUI_TYPE_WFA_HS20_IND, | |
3904 | ndev_vif->sta.sta_bss->ies->data, ndev_vif->sta.sta_bss->ies->len); | |
3905 | ||
3906 | if (ie) { | |
3907 | SLSI_NET_DBG1(dev, SLSI_CFG80211, "Connected to HS2 AP "); | |
3908 | ||
3909 | if (slsi_is_proxy_arp_supported_on_ap(peer->assoc_resp_ie)) { | |
3910 | SLSI_NET_DBG1(dev, SLSI_CFG80211, "Proxy ARP service supported on HS2 AP "); | |
3911 | ||
3912 | /* Opt out Gratuitous ARP packets (ARP Announcement) in active and suspended mode. | |
3913 | * For suspended mode, gratituous ARP is dropped by "opt out all broadcast" that will be | |
3914 | * set in slsi_set_common_packet_filters on screen off | |
3915 | */ | |
3916 | num_pattern_desc = 0; | |
3917 | pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ | |
3918 | pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; | |
3919 | SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); | |
3920 | SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].pattern, addr_mask); | |
3921 | num_pattern_desc++; | |
3922 | ||
3923 | SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], ETH_P_ARP); | |
3924 | num_pattern_desc++; | |
3925 | ||
3926 | slsi_create_packet_filter_element(SLSI_PROXY_ARP_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT, | |
3927 | num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], | |
3928 | &pkt_filters_len); | |
3929 | num_filters++; | |
3930 | ||
3931 | #ifndef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
3932 | /* Opt out unsolicited Neighbor Advertisement packets .For suspended mode, NA is dropped by | |
3933 | * "opt out all IPv6 multicast" already set in slsi_create_common_packet_filters | |
3934 | */ | |
3935 | ||
3936 | num_pattern_desc = 0; | |
3937 | ||
3938 | pattern_desc[num_pattern_desc].offset = 0; /*filtering on MAC destination Address*/ | |
3939 | pattern_desc[num_pattern_desc].mask_length = ETH_ALEN; | |
3940 | SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].mask, addr_mask); | |
3941 | SLSI_ETHER_COPY(pattern_desc[num_pattern_desc].pattern, solicited_node_addr_mask); | |
3942 | num_pattern_desc++; | |
3943 | ||
3944 | SET_ETHERTYPE_PATTERN_DESC(pattern_desc[num_pattern_desc], 0x86DD); | |
3945 | num_pattern_desc++; | |
3946 | ||
3947 | pattern_desc[num_pattern_desc].offset = 0x14; /*filtering on next header*/ | |
3948 | pattern_desc[num_pattern_desc].mask_length = 1; | |
3949 | pattern_desc[num_pattern_desc].mask[0] = 0xff; | |
3950 | pattern_desc[num_pattern_desc].pattern[0] = 0x3a; | |
3951 | num_pattern_desc++; | |
3952 | ||
3953 | pattern_desc[num_pattern_desc].offset = 0x36; /*filtering on ICMP6 packet type*/ | |
3954 | pattern_desc[num_pattern_desc].mask_length = 1; | |
3955 | pattern_desc[num_pattern_desc].mask[0] = 0xff; | |
3956 | pattern_desc[num_pattern_desc].pattern[0] = 0x88; /* Neighbor Advertisement type in ICMPv6 */ | |
3957 | num_pattern_desc++; | |
3958 | ||
3959 | slsi_create_packet_filter_element(SLSI_PROXY_ARP_NA_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT, | |
3960 | num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], | |
3961 | &pkt_filters_len); | |
3962 | num_filters++; | |
3963 | #endif | |
3964 | } | |
3965 | } | |
3966 | ||
3967 | #ifndef CONFIG_SCSC_WLAN_DISABLE_NAT_KA | |
3968 | { | |
3969 | const u8 nat_ka_pattern[4] = { 0x11, 0x94, 0x00, 0x09 }; | |
3970 | /*Opt out the NAT T for IPsec*/ | |
3971 | num_pattern_desc = 0; | |
3972 | pattern_desc[num_pattern_desc].offset = 0x24; /*filtering on destination port number*/ | |
3973 | pattern_desc[num_pattern_desc].mask_length = 4; | |
3974 | memcpy(pattern_desc[num_pattern_desc].mask, addr_mask, 4); | |
3975 | memcpy(pattern_desc[num_pattern_desc].pattern, nat_ka_pattern, 4); | |
3976 | num_pattern_desc++; | |
3977 | ||
3978 | slsi_create_packet_filter_element(SLSI_NAT_IPSEC_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, | |
3979 | num_pattern_desc, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
3980 | num_filters++; | |
3981 | } | |
3982 | #endif | |
3983 | ||
3984 | if (num_filters) | |
3985 | slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
3986 | } | |
3987 | ||
3988 | int slsi_ip_address_changed(struct slsi_dev *sdev, struct net_device *dev, __be32 ipaddress) | |
3989 | { | |
3990 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
3991 | int ret = 0; | |
3992 | ||
3993 | /* Store the IP address outside the check for vif being active | |
3994 | * as we get the same notification in case of static IP | |
3995 | */ | |
3996 | if (ndev_vif->ipaddress != ipaddress) | |
3997 | ndev_vif->ipaddress = ipaddress; | |
3998 | ||
3999 | if (ndev_vif->activated && (ndev_vif->vif_type == FAPI_VIFTYPE_AP)) { | |
4000 | #ifdef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
4001 | struct slsi_mlme_pattern_desc pattern_desc[1]; | |
4002 | u8 num_patterns = 0; | |
4003 | struct slsi_mlme_pkt_filter_elem pkt_filter_elem[1]; | |
4004 | u8 pkt_filters_len = 0; | |
4005 | u8 num_filters = 0; | |
4006 | #endif | |
4007 | ||
4008 | ndev_vif->ipaddress = ipaddress; | |
4009 | ret = slsi_mlme_set_ip_address(sdev, dev); | |
4010 | if (ret != 0) | |
4011 | SLSI_NET_ERR(dev, "slsi_mlme_set_ip_address ERROR. ret=%d", ret); | |
4012 | ||
4013 | #ifdef CONFIG_SCSC_WLAN_BLOCK_IPV6 | |
4014 | /* Opt out IPv6 packets in platform suspended mode */ | |
4015 | pattern_desc[num_patterns].offset = 0x0E; | |
4016 | pattern_desc[num_patterns].mask_length = 0x01; | |
4017 | pattern_desc[num_patterns].mask[0] = IPV6_PF_PATTERN_MASK; | |
4018 | pattern_desc[num_patterns++].pattern[0] = IPV6_PF_PATTERN; | |
4019 | ||
4020 | slsi_create_packet_filter_element(SLSI_AP_ALL_IPV6_PKTS_FILTER_ID, FAPI_PACKETFILTERMODE_OPT_OUT_SLEEP, | |
4021 | num_patterns, pattern_desc, &pkt_filter_elem[num_filters], &pkt_filters_len); | |
4022 | num_filters++; | |
4023 | ret = slsi_mlme_set_packet_filter(sdev, dev, pkt_filters_len, num_filters, pkt_filter_elem); | |
4024 | if (ret != 0) | |
4025 | SLSI_NET_ERR(dev, "slsi_mlme_set_packet_filter (return :%d) ERROR\n", ret); | |
4026 | #endif | |
4027 | } else if ((ndev_vif->activated) && | |
4028 | (ndev_vif->vif_type == FAPI_VIFTYPE_STATION) && | |
4029 | (ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED)) { | |
4030 | struct slsi_peer *peer = slsi_get_peer_from_qs(sdev, dev, SLSI_STA_PEER_QUEUESET); | |
4031 | ||
4032 | if (WARN_ON(!peer)) | |
4033 | return -EINVAL; | |
4034 | ||
4035 | if (!(peer->capabilities & WLAN_CAPABILITY_PRIVACY) || | |
4036 | (ndev_vif->sta.group_key_set && peer->pairwise_key_set)) | |
4037 | slsi_send_gratuitous_arp(sdev, dev); | |
4038 | else | |
4039 | ndev_vif->sta.gratuitous_arp_needed = true; | |
4040 | ||
4041 | slsi_mlme_powermgt(sdev, dev, ndev_vif->set_power_mode); | |
4042 | } | |
4043 | ||
4044 | return ret; | |
4045 | } | |
4046 | ||
4047 | #define SLSI_AP_AUTO_CHANLS_LIST_FROM_HOSTAPD_MAX 3 | |
4048 | ||
4049 | int slsi_auto_chan_select_scan(struct slsi_dev *sdev, int n_channels, struct ieee80211_channel *channels[]) | |
4050 | { | |
4051 | struct net_device *dev; | |
4052 | struct netdev_vif *ndev_vif; | |
4053 | struct sk_buff_head unique_scan_results; | |
4054 | int scan_result_count[SLSI_AP_AUTO_CHANLS_LIST_FROM_HOSTAPD_MAX] = { 0, 0, 0 }; | |
4055 | int i, j; | |
4056 | int r = 0; | |
4057 | int selected_index = 0; | |
4058 | int min_index = 0; | |
4059 | u32 freqdiff = 0; | |
4060 | ||
4061 | if (slsi_is_test_mode_enabled()) { | |
4062 | SLSI_WARN(sdev, "not supported in WlanLite mode\n"); | |
4063 | return -EOPNOTSUPP; | |
4064 | } | |
4065 | ||
4066 | skb_queue_head_init(&unique_scan_results); | |
4067 | ||
4068 | dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN); /* use the main VIF */ | |
4069 | if (!dev) { | |
4070 | r = -EINVAL; | |
4071 | return r; | |
4072 | } | |
4073 | ||
4074 | ndev_vif = netdev_priv(dev); | |
4075 | SLSI_MUTEX_LOCK(ndev_vif->scan_mutex); | |
4076 | ||
4077 | if (ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req) { | |
4078 | r = -EBUSY; | |
4079 | goto exit_with_vif; | |
4080 | } | |
4081 | ndev_vif->scan[SLSI_SCAN_HW_ID].is_blocking_scan = true; | |
4082 | r = slsi_mlme_add_scan(sdev, | |
4083 | dev, | |
4084 | FAPI_SCANTYPE_AP_AUTO_CHANNEL_SELECTION, | |
4085 | FAPI_REPORTMODE_REAL_TIME, | |
4086 | 0, /* n_ssids */ | |
4087 | NULL, /* ssids */ | |
4088 | n_channels, | |
4089 | channels, | |
4090 | NULL, | |
4091 | NULL, /* ie */ | |
4092 | 0, /* ie_len */ | |
4093 | ndev_vif->scan[SLSI_SCAN_HW_ID].is_blocking_scan); | |
4094 | ||
4095 | if (r == 0) { | |
4096 | struct sk_buff *unique_scan; | |
4097 | struct sk_buff *scan; | |
4098 | ||
4099 | SLSI_MUTEX_LOCK(ndev_vif->scan_result_mutex); | |
4100 | scan = slsi_dequeue_cached_scan_result(&ndev_vif->scan[SLSI_SCAN_HW_ID], NULL); | |
4101 | while (scan) { | |
4102 | struct ieee80211_mgmt *mgmt = fapi_get_mgmt(scan); | |
4103 | struct ieee80211_channel *channel; | |
4104 | ||
4105 | /* make sure this BSSID has not already been used */ | |
4106 | skb_queue_walk(&unique_scan_results, unique_scan) { | |
4107 | struct ieee80211_mgmt *unique_mgmt = fapi_get_mgmt(unique_scan); | |
4108 | ||
4109 | if (compare_ether_addr(mgmt->bssid, unique_mgmt->bssid) == 0) { | |
4110 | slsi_kfree_skb(scan); | |
4111 | goto next_scan; | |
4112 | } | |
4113 | } | |
4114 | ||
4115 | slsi_skb_queue_head(&unique_scan_results, scan); | |
4116 | ||
4117 | channel = slsi_find_scan_channel(sdev, mgmt, fapi_get_mgmtlen(scan), fapi_get_u16(scan, u.mlme_scan_ind.channel_frequency) / 2); | |
4118 | if (!channel) | |
4119 | goto next_scan; | |
4120 | ||
4121 | /* check for interfering channels for 1, 6 and 11 */ | |
4122 | for (i = 0, j = 0; i < SLSI_AP_AUTO_CHANLS_LIST_FROM_HOSTAPD_MAX && channels[j]; i++, j = j + 5) { | |
4123 | if (channel->center_freq == channels[j]->center_freq) { | |
4124 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "exact match:%d\n", i); | |
4125 | scan_result_count[i] += 5; | |
4126 | goto next_scan; | |
4127 | } | |
4128 | freqdiff = abs((int)channel->center_freq - (channels[j]->center_freq)); | |
4129 | if (freqdiff <= 20) { | |
4130 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "overlapping:%d, freqdiff:%d\n", i, freqdiff); | |
4131 | scan_result_count[i] += (5 - (freqdiff / 5)); | |
4132 | } | |
4133 | } | |
4134 | ||
4135 | next_scan: | |
4136 | scan = slsi_dequeue_cached_scan_result(&ndev_vif->scan[SLSI_SCAN_HW_ID], NULL); | |
4137 | } | |
4138 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_result_mutex); | |
4139 | ||
4140 | /* Select the channel to use */ | |
4141 | for (i = 0, j = 0; i < SLSI_AP_AUTO_CHANLS_LIST_FROM_HOSTAPD_MAX; i++, j = j + 5) { | |
4142 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "score[%d]:%d\n", i, scan_result_count[i]); | |
4143 | if (scan_result_count[i] <= scan_result_count[min_index]) { | |
4144 | min_index = i; | |
4145 | selected_index = j; | |
4146 | } | |
4147 | } | |
4148 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "selected:%d with score:%d\n", selected_index, scan_result_count[min_index]); | |
4149 | ||
4150 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
4151 | sdev->device_config.ap_auto_chan = channels[selected_index]->hw_value & 0xFF; | |
4152 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
4153 | ||
4154 | SLSI_INFO(sdev, "Channel selected = %d", sdev->device_config.ap_auto_chan); | |
4155 | } | |
4156 | slsi_skb_queue_purge(&unique_scan_results); | |
4157 | ndev_vif->scan[SLSI_SCAN_HW_ID].is_blocking_scan = false; | |
4158 | ||
4159 | exit_with_vif: | |
4160 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_mutex); | |
4161 | return r; | |
4162 | } | |
4163 | ||
4164 | int slsi_set_boost(struct slsi_dev *sdev, struct net_device *dev) | |
4165 | { | |
4166 | int error = 0; | |
4167 | ||
4168 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
4169 | error = slsi_set_mib_rssi_boost(sdev, dev, SLSI_PSID_UNIFI_ROAM_RSSI_BOOST, 1, | |
4170 | sdev->device_config.rssi_boost_2g); | |
4171 | if (error) | |
4172 | SLSI_ERR(sdev, "Err setting boost value For 2g after adding vif. error = %d\n", error); | |
4173 | error = slsi_set_mib_rssi_boost(sdev, dev, SLSI_PSID_UNIFI_ROAM_RSSI_BOOST, 2, | |
4174 | sdev->device_config.rssi_boost_5g); | |
4175 | if (error) | |
4176 | SLSI_ERR(sdev, "Err setting boost value for 5g after adding vif . error = %d\n", error); | |
4177 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
4178 | return error; | |
4179 | } | |
4180 | ||
4181 | /** | |
4182 | * Work to be done when ROC retention duration expires: | |
4183 | * Send ROC expired event to cfg80211 and queue work to delete unsync vif after retention timeout. | |
4184 | */ | |
4185 | static void slsi_p2p_roc_duration_expiry_work(struct work_struct *work) | |
4186 | { | |
4187 | struct netdev_vif *ndev_vif = container_of((struct delayed_work *)work, struct netdev_vif, unsync.roc_expiry_work); | |
4188 | ||
4189 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4190 | ||
4191 | /* There can be a race condition of this work function waiting for ndev_vif->vif_mutex and meanwhile the vif is deleted (due to net_stop). | |
4192 | * In such cases ndev_vif->chan would have been cleared. | |
4193 | */ | |
4194 | if (ndev_vif->sdev->p2p_state == P2P_IDLE_NO_VIF) { | |
4195 | SLSI_NET_DBG1(ndev_vif->wdev.netdev, SLSI_CFG80211, "P2P unsync vif is not present\n"); | |
4196 | goto exit; | |
4197 | } | |
4198 | ||
4199 | SLSI_NET_DBG3(ndev_vif->wdev.netdev, SLSI_CFG80211, "Send ROC expired event\n"); | |
4200 | ||
4201 | /* If action frame tx is in progress don't schedule work to delete vif */ | |
4202 | if (ndev_vif->sdev->p2p_state != P2P_ACTION_FRAME_TX_RX) { | |
4203 | /* After sucessful frame transmission, we will move to LISTENING or VIF ACTIVE state. | |
4204 | * Unset channel should not be sent down during p2p procedure. | |
4205 | */ | |
4206 | if (!ndev_vif->drv_in_p2p_procedure) { | |
4207 | if (delayed_work_pending(&ndev_vif->unsync.unset_channel_expiry_work)) | |
4208 | cancel_delayed_work(&ndev_vif->unsync.unset_channel_expiry_work); | |
4209 | queue_delayed_work(ndev_vif->sdev->device_wq, &ndev_vif->unsync.unset_channel_expiry_work, | |
4210 | msecs_to_jiffies(SLSI_P2P_UNSET_CHANNEL_EXTRA_MSEC)); | |
4211 | } | |
4212 | slsi_p2p_queue_unsync_vif_del_work(ndev_vif, SLSI_P2P_UNSYNC_VIF_EXTRA_MSEC); | |
4213 | SLSI_P2P_STATE_CHANGE(ndev_vif->sdev, P2P_IDLE_VIF_ACTIVE); | |
4214 | } | |
4215 | ||
4216 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
4217 | cfg80211_remain_on_channel_expired(&ndev_vif->wdev, ndev_vif->unsync.roc_cookie, ndev_vif->chan, GFP_KERNEL); | |
4218 | #else | |
4219 | cfg80211_remain_on_channel_expired(ndev_vif->wdev.netdev, ndev_vif->unsync.roc_cookie, | |
4220 | ndev_vif->chan, ndev_vif->channel_type, GFP_KERNEL); | |
4221 | #endif | |
4222 | ||
4223 | exit: | |
4224 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4225 | } | |
4226 | ||
4227 | /** | |
4228 | * Work to be done when unsync vif retention duration expires: | |
4229 | * Delete the unsync vif. | |
4230 | */ | |
4231 | static void slsi_p2p_unsync_vif_delete_work(struct work_struct *work) | |
4232 | { | |
4233 | struct netdev_vif *ndev_vif = container_of((struct delayed_work *)work, struct netdev_vif, unsync.del_vif_work); | |
4234 | ||
4235 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4236 | SLSI_NET_DBG1(ndev_vif->wdev.netdev, SLSI_CFG80211, "Delete vif duration expired - Deactivate unsync vif\n"); | |
4237 | slsi_p2p_vif_deactivate(ndev_vif->sdev, ndev_vif->wdev.netdev, true); | |
4238 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4239 | } | |
4240 | ||
4241 | /** | |
4242 | * Work to be done after roc expiry or cancel remain on channel: | |
4243 | * Unset channel to be sent to Fw. | |
4244 | */ | |
4245 | static void slsi_p2p_unset_channel_expiry_work(struct work_struct *work) | |
4246 | { | |
4247 | struct netdev_vif *ndev_vif = container_of((struct delayed_work *)work, struct netdev_vif, | |
4248 | unsync.unset_channel_expiry_work); | |
4249 | struct slsi_dev *sdev = ndev_vif->sdev; | |
4250 | struct net_device *dev = ndev_vif->wdev.netdev; | |
4251 | ||
4252 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4253 | if (ndev_vif->activated) { | |
4254 | SLSI_NET_DBG1(ndev_vif->wdev.netdev, SLSI_CFG80211, "Unset channel expiry work-Send Unset Channel\n"); | |
4255 | if (!ndev_vif->drv_in_p2p_procedure) { | |
4256 | /* Supplicant has stopped FIND/LISTEN. Clear Probe Response IEs in firmware and driver */ | |
4257 | if (slsi_mlme_add_info_elements(sdev, dev, FAPI_PURPOSE_PROBE_RESPONSE, NULL, 0) != 0) | |
4258 | SLSI_NET_ERR(dev, "Clearing Probe Response IEs failed for unsync vif\n"); | |
4259 | slsi_unsync_vif_set_probe_rsp_ie(ndev_vif, NULL, 0); | |
4260 | ||
4261 | /* Send Unset Channel */ | |
4262 | if (ndev_vif->driver_channel != 0) { | |
4263 | slsi_mlme_unset_channel_req(sdev, dev); | |
4264 | ndev_vif->driver_channel = 0; | |
4265 | } | |
4266 | } | |
4267 | } else { | |
4268 | SLSI_NET_ERR(dev, "P2P vif is not activated\n"); | |
4269 | } | |
4270 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4271 | } | |
4272 | ||
4273 | /* Initializations for P2P - Change vif type to unsync, create workqueue and init work */ | |
4274 | int slsi_p2p_init(struct slsi_dev *sdev, struct netdev_vif *ndev_vif) | |
4275 | { | |
4276 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "Initialize P2P - Init P2P state to P2P_IDLE_NO_VIF\n"); | |
4277 | sdev->p2p_state = P2P_IDLE_NO_VIF; | |
4278 | sdev->p2p_group_exp_frame = SLSI_PA_INVALID; | |
4279 | ||
4280 | ndev_vif->vif_type = FAPI_VIFTYPE_UNSYNCHRONISED; | |
4281 | ndev_vif->unsync.slsi_p2p_continuous_fullscan = false; | |
4282 | ||
4283 | ||
4284 | INIT_DELAYED_WORK(&ndev_vif->unsync.roc_expiry_work, slsi_p2p_roc_duration_expiry_work); | |
4285 | INIT_DELAYED_WORK(&ndev_vif->unsync.del_vif_work, slsi_p2p_unsync_vif_delete_work); | |
4286 | INIT_DELAYED_WORK(&ndev_vif->unsync.unset_channel_expiry_work, slsi_p2p_unset_channel_expiry_work); | |
4287 | return 0; | |
4288 | } | |
4289 | ||
4290 | /* De-initializations for P2P - Reset vif type, cancel work and destroy workqueue */ | |
4291 | void slsi_p2p_deinit(struct slsi_dev *sdev, struct netdev_vif *ndev_vif) | |
4292 | { | |
4293 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "De-initialize P2P\n"); | |
4294 | ||
4295 | ndev_vif->vif_type = SLSI_VIFTYPE_UNSPECIFIED; | |
4296 | ||
4297 | /* Work should have been cleaned up by now */ | |
4298 | if (WARN_ON(delayed_work_pending(&ndev_vif->unsync.del_vif_work))) | |
4299 | cancel_delayed_work(&ndev_vif->unsync.del_vif_work); | |
4300 | ||
4301 | if (WARN_ON(delayed_work_pending(&ndev_vif->unsync.roc_expiry_work))) | |
4302 | cancel_delayed_work(&ndev_vif->unsync.roc_expiry_work); | |
4303 | } | |
4304 | ||
4305 | /** | |
4306 | * P2P vif activation: | |
4307 | * Add unsync vif, register for action frames, configure Probe Rsp IEs if required and set channel | |
4308 | */ | |
4309 | int slsi_p2p_vif_activate(struct slsi_dev *sdev, struct net_device *dev, struct ieee80211_channel *chan, u16 duration, bool set_probe_rsp_ies) | |
4310 | { | |
4311 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
4312 | u32 af_bmap_active = SLSI_ACTION_FRAME_PUBLIC; | |
4313 | u32 af_bmap_suspended = SLSI_ACTION_FRAME_PUBLIC; | |
4314 | int r = 0; | |
4315 | ||
4316 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "Activate P2P unsync vif\n"); | |
4317 | ||
4318 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
4319 | ||
4320 | /* Interface address and device address are same for P2P unsync vif */ | |
4321 | if (slsi_mlme_add_vif(sdev, dev, dev->dev_addr, dev->dev_addr) != 0) { | |
4322 | SLSI_NET_ERR(dev, "slsi_mlme_add_vif failed for unsync vif\n"); | |
4323 | goto exit_with_error; | |
4324 | } | |
4325 | ||
4326 | ndev_vif->activated = true; | |
4327 | SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_VIF_ACTIVE); | |
4328 | ||
4329 | if (slsi_mlme_register_action_frame(sdev, dev, af_bmap_active, af_bmap_suspended) != 0) { | |
4330 | SLSI_NET_ERR(dev, "Action frame registration failed for unsync vif\n"); | |
4331 | goto exit_with_vif; | |
4332 | } | |
4333 | ||
4334 | if (set_probe_rsp_ies) { | |
4335 | u16 purpose = FAPI_PURPOSE_PROBE_RESPONSE; | |
4336 | ||
4337 | if (!ndev_vif->unsync.probe_rsp_ies) { | |
4338 | SLSI_NET_ERR(dev, "Probe Response IEs not available for ROC\n"); | |
4339 | goto exit_with_vif; | |
4340 | } | |
4341 | ||
4342 | if (slsi_mlme_add_info_elements(sdev, dev, purpose, ndev_vif->unsync.probe_rsp_ies, ndev_vif->unsync.probe_rsp_ies_len) != 0) { | |
4343 | SLSI_NET_ERR(dev, "Setting Probe Response IEs for unsync vif failed\n"); | |
4344 | goto exit_with_vif; | |
4345 | } | |
4346 | ndev_vif->unsync.ies_changed = false; | |
4347 | } | |
4348 | ||
4349 | if (slsi_mlme_set_channel(sdev, dev, chan, SLSI_FW_CHANNEL_DURATION_UNSPECIFIED, 0, 0) != 0) { | |
4350 | SLSI_NET_ERR(dev, "Set channel failed for unsync vif\n"); | |
4351 | goto exit_with_vif; | |
4352 | } else { | |
4353 | ndev_vif->chan = chan; | |
4354 | ndev_vif->driver_channel = chan->hw_value; | |
4355 | } | |
4356 | ||
4357 | ndev_vif->mgmt_tx_data.exp_frame = SLSI_PA_INVALID; | |
4358 | goto exit; | |
4359 | ||
4360 | exit_with_vif: | |
4361 | slsi_p2p_vif_deactivate(sdev, dev, true); | |
4362 | exit_with_error: | |
4363 | r = -EINVAL; | |
4364 | exit: | |
4365 | return r; | |
4366 | } | |
4367 | ||
4368 | /* Delete unsync vif - DON'T update the vif type */ | |
4369 | void slsi_p2p_vif_deactivate(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) | |
4370 | { | |
4371 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
4372 | ||
4373 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "De-activate P2P unsync vif\n"); | |
4374 | ||
4375 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
4376 | ||
4377 | if (sdev->p2p_state == P2P_IDLE_NO_VIF) { | |
4378 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "P2P unsync vif already deactivated\n"); | |
4379 | return; | |
4380 | } | |
4381 | ||
4382 | /* Indicate failure using cfg80211_mgmt_tx_status() if frame TX is not completed during VIF delete */ | |
4383 | if (ndev_vif->mgmt_tx_data.exp_frame != SLSI_PA_INVALID) { | |
4384 | ndev_vif->mgmt_tx_data.exp_frame = SLSI_PA_INVALID; | |
4385 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) | |
4386 | cfg80211_mgmt_tx_status(&ndev_vif->wdev, ndev_vif->mgmt_tx_data.cookie, ndev_vif->mgmt_tx_data.buf, ndev_vif->mgmt_tx_data.buf_len, false, GFP_KERNEL); | |
4387 | #else | |
4388 | cfg80211_mgmt_tx_status(dev, ndev_vif->mgmt_tx_data.cookie, ndev_vif->mgmt_tx_data.buf, ndev_vif->mgmt_tx_data.buf_len, false, GFP_KERNEL); | |
4389 | #endif | |
4390 | } | |
4391 | ||
4392 | cancel_delayed_work(&ndev_vif->unsync.del_vif_work); | |
4393 | if (delayed_work_pending(&ndev_vif->unsync.roc_expiry_work) && sdev->recovery_status) { | |
4394 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
4395 | cfg80211_remain_on_channel_expired(&ndev_vif->wdev, ndev_vif->unsync.roc_cookie, ndev_vif->chan, | |
4396 | GFP_KERNEL); | |
4397 | #else | |
4398 | cfg80211_remain_on_channel_expired(ndev_vif->wdev.netdev, ndev_vif->unsync.roc_cookie, | |
4399 | ndev_vif->chan, ndev_vif->channel_type, GFP_KERNEL); | |
4400 | #endif | |
4401 | } | |
4402 | cancel_delayed_work(&ndev_vif->unsync.roc_expiry_work); | |
4403 | ||
4404 | if (hw_available) | |
4405 | slsi_mlme_del_vif(sdev, dev); | |
4406 | ||
4407 | SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_NO_VIF); | |
4408 | ||
4409 | /* slsi_vif_deactivated is not used here after del_vif as it modifies vif type as well */ | |
4410 | ||
4411 | ndev_vif->activated = false; | |
4412 | ndev_vif->chan = NULL; | |
4413 | ||
4414 | if (WARN_ON(ndev_vif->unsync.listen_offload)) | |
4415 | ndev_vif->unsync.listen_offload = false; | |
4416 | ||
4417 | slsi_unsync_vif_set_probe_rsp_ie(ndev_vif, NULL, 0); | |
4418 | (void)slsi_set_mgmt_tx_data(ndev_vif, 0, 0, NULL, 0); | |
4419 | ||
4420 | SLSI_NET_DBG2(dev, SLSI_INIT_DEINIT, "P2P unsync vif deactivated\n"); | |
4421 | } | |
4422 | ||
4423 | /** | |
4424 | * Delete unsync vif when group role is being started. | |
4425 | * For such cases the net_device during the call would be of the group interface (called from ap_start/connect). | |
4426 | * Hence get the net_device using P2P Index. Take the mutex lock and call slsi_p2p_vif_deactivate. | |
4427 | */ | |
4428 | void slsi_p2p_group_start_remove_unsync_vif(struct slsi_dev *sdev) | |
4429 | { | |
4430 | struct net_device *dev = NULL; | |
4431 | struct netdev_vif *ndev_vif = NULL; | |
4432 | ||
4433 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "Starting P2P Group - Remove unsync vif\n"); | |
4434 | ||
4435 | dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2P); | |
4436 | if (!dev) { | |
4437 | SLSI_ERR(sdev, "Failed to deactivate p2p vif as dev is not found\n"); | |
4438 | return; | |
4439 | } | |
4440 | ||
4441 | ndev_vif = netdev_priv(dev); | |
4442 | ||
4443 | if (WARN_ON(!(SLSI_IS_P2P_UNSYNC_VIF(ndev_vif)))) | |
4444 | return; | |
4445 | ||
4446 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4447 | slsi_p2p_vif_deactivate(sdev, dev, true); | |
4448 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4449 | } | |
4450 | ||
4451 | /** | |
4452 | * Called only for P2P Device mode (p2p0 interface) to store the Probe Response IEs | |
4453 | * which would be used in Listen (ROC) state. | |
4454 | * If the IEs are received in Listen Offload mode, then configure the IEs in firmware. | |
4455 | */ | |
4456 | int slsi_p2p_dev_probe_rsp_ie(struct slsi_dev *sdev, struct net_device *dev, u8 *probe_rsp_ie, size_t probe_rsp_ie_len) | |
4457 | { | |
4458 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
4459 | int ret = 0; | |
4460 | ||
4461 | SLSI_UNUSED_PARAMETER(sdev); | |
4462 | ||
4463 | if (!SLSI_IS_P2P_UNSYNC_VIF(ndev_vif)) { | |
4464 | SLSI_NET_ERR(dev, "Incorrect vif type - Not unsync vif\n"); | |
4465 | kfree(probe_rsp_ie); | |
4466 | return -EINVAL; | |
4467 | } | |
4468 | ||
4469 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4470 | ||
4471 | SLSI_NET_DBG2(dev, SLSI_CFG80211, "Received Probe Rsp IE len = %zu, Current IE len = %zu\n", probe_rsp_ie_len, ndev_vif->unsync.probe_rsp_ies_len); | |
4472 | ||
4473 | if (!ndev_vif->unsync.listen_offload) { /* ROC */ | |
4474 | /* Store the IEs. Upon receiving it on subsequent occassions, store only if IEs have changed */ | |
4475 | if (ndev_vif->unsync.probe_rsp_ies_len != probe_rsp_ie_len) /* Check if IE length changed */ | |
4476 | ndev_vif->unsync.ies_changed = true; | |
4477 | else if (memcmp(ndev_vif->unsync.probe_rsp_ies, probe_rsp_ie, probe_rsp_ie_len) != 0) /* Check if IEs changed */ | |
4478 | ndev_vif->unsync.ies_changed = true; | |
4479 | else { /* No change in IEs */ | |
4480 | kfree(probe_rsp_ie); | |
4481 | goto exit; | |
4482 | } | |
4483 | ||
4484 | slsi_unsync_vif_set_probe_rsp_ie(ndev_vif, probe_rsp_ie, probe_rsp_ie_len); | |
4485 | } else { /* P2P Listen Offloading */ | |
4486 | if (sdev->p2p_state == P2P_LISTENING) { | |
4487 | ret = slsi_mlme_add_info_elements(sdev, dev, FAPI_PURPOSE_PROBE_RESPONSE, probe_rsp_ie, probe_rsp_ie_len); | |
4488 | if (ret != 0) { | |
4489 | SLSI_NET_ERR(dev, "Listen Offloading: Setting Probe Response IEs for unsync vif failed\n"); | |
4490 | ndev_vif->unsync.listen_offload = false; | |
4491 | slsi_p2p_vif_deactivate(sdev, dev, true); | |
4492 | } | |
4493 | } | |
4494 | } | |
4495 | ||
4496 | exit: | |
4497 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4498 | return ret; | |
4499 | } | |
4500 | ||
4501 | /** | |
4502 | * This should be called only for P2P Device mode (p2p0 interface). NULL IEs to clear Probe Response IEs are not updated | |
4503 | * in driver to avoid configuring the Probe Response IEs to firmware on every ROC. | |
4504 | * Use this call as a cue to stop any ongoing P2P scan as there is no API from user space for cancelling scan. | |
4505 | * If ROC was in progress as part of P2P_FIND then Cancel ROC will be received. | |
4506 | */ | |
4507 | int slsi_p2p_dev_null_ies(struct slsi_dev *sdev, struct net_device *dev) | |
4508 | { | |
4509 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
4510 | struct cfg80211_scan_info info = {.aborted = true}; | |
4511 | ||
4512 | if (!SLSI_IS_P2P_UNSYNC_VIF(ndev_vif)) { | |
4513 | SLSI_NET_ERR(dev, "Incorrect vif type - Not unsync vif\n"); | |
4514 | return -EINVAL; | |
4515 | } | |
4516 | ||
4517 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4518 | ||
4519 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "Probe Rsp NULL IEs\n"); | |
4520 | ||
4521 | if (sdev->p2p_state == P2P_SCANNING) { | |
4522 | struct sk_buff *scan_result; | |
4523 | ||
4524 | SLSI_MUTEX_LOCK(ndev_vif->scan_mutex); | |
4525 | ||
4526 | SLSI_NET_DBG1(dev, SLSI_CFG80211, "Stop Find - Abort ongoing P2P scan\n"); | |
4527 | ||
4528 | (void)slsi_mlme_del_scan(sdev, dev, ((ndev_vif->ifnum << 8) | SLSI_SCAN_HW_ID), false); | |
4529 | ||
4530 | SLSI_MUTEX_LOCK(ndev_vif->scan_result_mutex); | |
4531 | scan_result = slsi_dequeue_cached_scan_result(&ndev_vif->scan[SLSI_SCAN_HW_ID], NULL); | |
4532 | while (scan_result) { | |
4533 | slsi_rx_scan_pass_to_cfg80211(sdev, dev, scan_result); | |
4534 | scan_result = slsi_dequeue_cached_scan_result(&ndev_vif->scan[SLSI_SCAN_HW_ID], NULL); | |
4535 | } | |
4536 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_result_mutex); | |
4537 | ||
4538 | WARN_ON(!ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req); | |
4539 | ||
4540 | if (ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req) | |
4541 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) | |
4542 | cfg80211_scan_done(ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req, &info); | |
4543 | #else | |
4544 | cfg80211_scan_done(ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req, true); | |
4545 | #endif | |
4546 | ||
4547 | ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req = NULL; | |
4548 | ||
4549 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_mutex); | |
4550 | ||
4551 | if (ndev_vif->activated) { | |
4552 | /* Supplicant has stopped FIND. Also clear Probe Response IEs in firmware and driver | |
4553 | * as Cancel ROC will not be sent as driver was not in Listen | |
4554 | */ | |
4555 | SLSI_NET_DBG1(dev, SLSI_CFG80211, "Stop Find - Clear Probe Response IEs in firmware\n"); | |
4556 | if (slsi_mlme_add_info_elements(sdev, dev, FAPI_PURPOSE_PROBE_RESPONSE, NULL, 0) != 0) | |
4557 | SLSI_NET_ERR(dev, "Clearing Probe Response IEs failed for unsync vif\n"); | |
4558 | slsi_unsync_vif_set_probe_rsp_ie(ndev_vif, NULL, 0); | |
4559 | ||
4560 | SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_VIF_ACTIVE); | |
4561 | } else { | |
4562 | SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_NO_VIF); | |
4563 | } | |
4564 | } | |
4565 | ||
4566 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4567 | return 0; | |
4568 | } | |
4569 | ||
4570 | /** | |
4571 | * Returns the public action frame subtype. | |
4572 | * Returns SLSI_PA_INVALID if it is not a public action frame. | |
4573 | */ | |
4574 | int slsi_get_public_action_subtype(const struct ieee80211_mgmt *mgmt) | |
4575 | { | |
4576 | int subtype = SLSI_PA_INVALID; | |
4577 | /* Vendor specific Public Action (0x09), P2P OUI (0x50, 0x6f, 0x9a), P2P Subtype (0x09) */ | |
4578 | u8 p2p_pa_frame[5] = { 0x09, 0x50, 0x6f, 0x9a, 0x09 }; | |
4579 | u8 *action = (u8 *)&mgmt->u.action.u; | |
4580 | ||
4581 | if (memcmp(&action[0], p2p_pa_frame, 5) == 0) { | |
4582 | subtype = action[5]; | |
4583 | } else { | |
4584 | /* For service discovery action frames dummy subtype is used */ | |
4585 | switch (action[0]) { | |
4586 | case SLSI_PA_GAS_INITIAL_REQ: | |
4587 | case SLSI_PA_GAS_INITIAL_RSP: | |
4588 | case SLSI_PA_GAS_COMEBACK_REQ: | |
4589 | case SLSI_PA_GAS_COMEBACK_RSP: | |
4590 | subtype = (action[0] | SLSI_PA_GAS_DUMMY_SUBTYPE_MASK); | |
4591 | break; | |
4592 | } | |
4593 | } | |
4594 | ||
4595 | return subtype; | |
4596 | } | |
4597 | ||
4598 | /** | |
4599 | * Returns the P2P status code of Status attribute of the GO Neg Rsp frame. | |
4600 | * Returns -1 if status attribute is NOT found. | |
4601 | */ | |
4602 | int slsi_p2p_get_go_neg_rsp_status(struct net_device *dev, const struct ieee80211_mgmt *mgmt) | |
4603 | { | |
4604 | int status = -1; | |
4605 | u8 p2p_oui_type[4] = { 0x50, 0x6f, 0x9a, 0x09 }; | |
4606 | u8 *action = (u8 *)&mgmt->u.action.u; | |
4607 | u8 *vendor_ie = &action[7]; /* 1 (0x09), 4 (0x50, 0x6f, 0x9a, 0x09), 1 (0x01), 1 (Dialog Token) */ | |
4608 | u8 ie_length, elem_idx; | |
4609 | u16 attr_length; | |
4610 | ||
4611 | while (vendor_ie && (*vendor_ie == SLSI_WLAN_EID_VENDOR_SPECIFIC)) { | |
4612 | ie_length = vendor_ie[1]; | |
4613 | ||
4614 | if (memcmp(&vendor_ie[2], p2p_oui_type, 4) == 0) { | |
4615 | elem_idx = 6; /* 1 (Id - 0xdd) + 1 (Length) + 4 (OUI and Type) */ | |
4616 | ||
4617 | while (ie_length > elem_idx) { | |
4618 | attr_length = ((vendor_ie[elem_idx + 1]) | (vendor_ie[elem_idx + 2] << 8)); | |
4619 | ||
4620 | if (vendor_ie[elem_idx] == SLSI_P2P_STATUS_ATTR_ID) { | |
4621 | SLSI_NET_DBG3(dev, SLSI_CFG80211, "Status Attribute Found, attr_length = %d, value (%u %u %u %u)\n", | |
4622 | attr_length, vendor_ie[elem_idx], vendor_ie[elem_idx + 1], vendor_ie[elem_idx + 2], vendor_ie[elem_idx + 3]); | |
4623 | status = vendor_ie[elem_idx + 3]; | |
4624 | break; | |
4625 | } | |
4626 | elem_idx += 3 + attr_length; | |
4627 | } | |
4628 | ||
4629 | break; | |
4630 | } | |
4631 | vendor_ie += 2 + ie_length; | |
4632 | } | |
4633 | ||
4634 | SLSI_UNUSED_PARAMETER(dev); | |
4635 | ||
4636 | return status; | |
4637 | } | |
4638 | ||
4639 | /** | |
4640 | * Returns the next expected public action frame subtype for input subtype. | |
4641 | * Returns SLSI_PA_INVALID if no frame is expected. | |
4642 | */ | |
4643 | u8 slsi_get_exp_peer_frame_subtype(u8 subtype) | |
4644 | { | |
4645 | switch (subtype) { | |
4646 | /* Peer response is expected for following frames */ | |
4647 | case SLSI_P2P_PA_GO_NEG_REQ: | |
4648 | case SLSI_P2P_PA_GO_NEG_RSP: | |
4649 | case SLSI_P2P_PA_INV_REQ: | |
4650 | case SLSI_P2P_PA_DEV_DISC_REQ: | |
4651 | case SLSI_P2P_PA_PROV_DISC_REQ: | |
4652 | case SLSI_PA_GAS_INITIAL_REQ_SUBTYPE: | |
4653 | case SLSI_PA_GAS_COMEBACK_REQ_SUBTYPE: | |
4654 | return subtype + 1; | |
4655 | default: | |
4656 | return SLSI_PA_INVALID; | |
4657 | } | |
4658 | } | |
4659 | ||
4660 | void slsi_wlan_dump_public_action_subtype(struct slsi_dev *sdev, struct ieee80211_mgmt *mgmt, bool tx) | |
4661 | { | |
bd5e44ae | 4662 | u8 action_code = ((u8 *)&mgmt->u.action.u)[0]; |
cc6398c8 TK |
4663 | u8 action_category = mgmt->u.action.category; |
4664 | char *tx_rx_string = "Received"; | |
4665 | char wnm_action_fields[28][35] = { "Event Request", "Event Report", "Diagnostic Request", | |
4666 | "Diagnostic Report", "Location Configuration Request", | |
4667 | "Location Configuration Response", "BSS Transition Management Query", | |
4668 | "BSS Transition Management Request", | |
4669 | "BSS Transition Management Response", "FMS Request", "FMS Response", | |
4670 | "Collocated Interference Request", "Collocated Interference Report", | |
4671 | "TFS Request", "TFS Response", "TFS Notify", "WNM Sleep Mode Request", | |
4672 | "WNM Sleep Mode Response", "TIM Broadcast Request", | |
4673 | "TIM Broadcast Response", "QoS Traffic Capability Update", | |
4674 | "Channel Usage Request", "Channel Usage Response", "DMS Request", | |
4675 | "DMS Response", "Timing Measurement Request", | |
4676 | "WNM Notification Request", "WNM Notification Response" }; | |
4677 | ||
4678 | if (tx) | |
4679 | tx_rx_string = "Send"; | |
4680 | ||
4681 | switch (action_category) { | |
4682 | case WLAN_CATEGORY_RADIO_MEASUREMENT: | |
4683 | switch (action_code) { | |
4684 | case SLSI_RM_RADIO_MEASUREMENT_REQ: | |
4685 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Radio Measurement Req)\n", tx_rx_string); | |
4686 | break; | |
4687 | case SLSI_RM_RADIO_MEASUREMENT_REP: | |
4688 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Radio Measurement Rep)\n", tx_rx_string); | |
4689 | break; | |
4690 | case SLSI_RM_LINK_MEASUREMENT_REQ: | |
4691 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Link Measurement Req)\n", tx_rx_string); | |
4692 | break; | |
4693 | case SLSI_RM_LINK_MEASUREMENT_REP: | |
4694 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Link Measurement Rep)\n", tx_rx_string); | |
4695 | break; | |
4696 | case SLSI_RM_NEIGH_REP_REQ: | |
4697 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Neighbor Report Req)\n", tx_rx_string); | |
4698 | break; | |
4699 | case SLSI_RM_NEIGH_REP_RSP: | |
4700 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Neighbor Report Resp)\n", tx_rx_string); | |
4701 | break; | |
4702 | default: | |
4703 | SLSI_INFO(sdev, "%s Radio Measurement Frame (Reserved)\n", tx_rx_string); | |
4704 | } | |
4705 | break; | |
4706 | case WLAN_CATEGORY_PUBLIC: | |
4707 | switch (action_code) { | |
4708 | case SLSI_PA_GAS_INITIAL_REQ: | |
4709 | SLSI_DBG1_NODEV(SLSI_CFG80211, "%s: GAS Initial Request\n", tx ? "TX" : "RX"); | |
4710 | break; | |
4711 | case SLSI_PA_GAS_INITIAL_RSP: | |
4712 | SLSI_DBG1_NODEV(SLSI_CFG80211, "%s: GAS Initial Response\n", tx ? "TX" : "RX"); | |
4713 | break; | |
4714 | case SLSI_PA_GAS_COMEBACK_REQ: | |
4715 | SLSI_DBG1_NODEV(SLSI_CFG80211, "%s: GAS Comeback Request\n", tx ? "TX" : "RX"); | |
4716 | break; | |
4717 | case SLSI_PA_GAS_COMEBACK_RSP: | |
4718 | SLSI_DBG1_NODEV(SLSI_CFG80211, "%s: GAS Comeback Response\n", tx ? "TX" : "RX"); | |
4719 | break; | |
4720 | default: | |
bd5e44ae | 4721 | SLSI_DBG1_NODEV(SLSI_CFG80211, "Unknown Public Action Frame : %d\n", action_code); |
cc6398c8 TK |
4722 | } |
4723 | break; | |
4724 | case WLAN_CATEGORY_WNM: | |
4725 | if (action_code >= SLSI_WNM_ACTION_FIELD_MIN && action_code <= SLSI_WNM_ACTION_FIELD_MAX) | |
4726 | SLSI_INFO(sdev, "%s WNM Frame (%s)\n", tx_rx_string, wnm_action_fields[action_code]); | |
4727 | else | |
4728 | SLSI_INFO(sdev, "%s WNM Frame (Reserved)\n", tx_rx_string); | |
4729 | break; | |
4730 | } | |
4731 | } | |
4732 | ||
4733 | void slsi_abort_sta_scan(struct slsi_dev *sdev) | |
4734 | { | |
4735 | struct net_device *wlan_net_dev = NULL; | |
4736 | struct netdev_vif *ndev_vif; | |
4737 | struct cfg80211_scan_info info = {.aborted = true}; | |
4738 | ||
4739 | wlan_net_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN); | |
4740 | ||
4741 | if (!wlan_net_dev) { | |
4742 | SLSI_ERR(sdev, "Dev not found\n"); | |
4743 | return; | |
4744 | } | |
4745 | ||
4746 | ndev_vif = netdev_priv(wlan_net_dev); | |
4747 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
4748 | SLSI_MUTEX_LOCK(ndev_vif->scan_mutex); | |
4749 | ||
4750 | if (ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req) { | |
4751 | struct sk_buff *scan_result; | |
4752 | ||
4753 | SLSI_DBG2(sdev, SLSI_CFG80211, "Abort ongoing WLAN scan\n"); | |
4754 | (void)slsi_mlme_del_scan(sdev, wlan_net_dev, ((ndev_vif->ifnum << 8) | SLSI_SCAN_HW_ID), false); | |
4755 | SLSI_MUTEX_LOCK(ndev_vif->scan_result_mutex); | |
4756 | scan_result = slsi_dequeue_cached_scan_result(&ndev_vif->scan[SLSI_SCAN_HW_ID], NULL); | |
4757 | while (scan_result) { | |
4758 | slsi_rx_scan_pass_to_cfg80211(sdev, wlan_net_dev, scan_result); | |
4759 | scan_result = slsi_dequeue_cached_scan_result(&ndev_vif->scan[SLSI_SCAN_HW_ID], NULL); | |
4760 | } | |
4761 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_result_mutex); | |
4762 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) | |
4763 | cfg80211_scan_done(ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req, &info); | |
4764 | #else | |
4765 | cfg80211_scan_done(ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req, true); | |
4766 | #endif | |
4767 | ||
4768 | ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req = NULL; | |
4769 | ndev_vif->scan[SLSI_SCAN_HW_ID].requeue_timeout_work = false; | |
4770 | } | |
4771 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_mutex); | |
4772 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
4773 | } | |
4774 | ||
4775 | /** | |
4776 | * Returns a slsi_dhcp_tx enum value after verifying whether the 802.11 packet in skb | |
4777 | * is a DHCP packet (identified by UDP port numbers) | |
4778 | */ | |
4779 | int slsi_is_dhcp_packet(u8 *data) | |
4780 | { | |
4781 | u8 *p; | |
4782 | int ret = SLSI_TX_IS_NOT_DHCP; | |
4783 | ||
4784 | p = data + SLSI_IP_TYPE_OFFSET; | |
4785 | ||
4786 | if (*p == SLSI_IP_TYPE_UDP) { | |
4787 | u16 source_port, dest_port; | |
4788 | ||
4789 | p = data + SLSI_IP_SOURCE_PORT_OFFSET; | |
4790 | source_port = p[0] << 8 | p[1]; | |
4791 | p = data + SLSI_IP_DEST_PORT_OFFSET; | |
4792 | dest_port = p[0] << 8 | p[1]; | |
4793 | if ((source_port == SLSI_DHCP_CLIENT_PORT) && (dest_port == SLSI_DHCP_SERVER_PORT)) | |
4794 | ret = SLSI_TX_IS_DHCP_CLIENT; | |
4795 | else if ((source_port == SLSI_DHCP_SERVER_PORT) && (dest_port == SLSI_DHCP_CLIENT_PORT)) | |
4796 | ret = SLSI_TX_IS_DHCP_SERVER; | |
4797 | } | |
4798 | ||
4799 | return ret; | |
4800 | } | |
4801 | ||
4802 | #ifdef CONFIG_SCSC_WLAN_PRIORITISE_IMP_FRAMES | |
4803 | int slsi_is_tcp_sync_packet(struct net_device *dev, struct sk_buff *skb) | |
4804 | { | |
4805 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
4806 | ||
4807 | /* for AP type (AP or P2P Go) check if the packet is local or intra BSS. If intra BSS then | |
4808 | * the IP header and TCP header are not set; so return 0 | |
4809 | */ | |
4810 | if ((ndev_vif->vif_type == FAPI_VIFTYPE_AP) && (compare_ether_addr(eth_hdr(skb)->h_source, dev->dev_addr) != 0)) | |
4811 | return 0; | |
4812 | if (be16_to_cpu(eth_hdr(skb)->h_proto) != ETH_P_IP) | |
4813 | return 0; | |
4814 | if (ip_hdr(skb)->protocol != IPPROTO_TCP) | |
4815 | return 0; | |
4816 | if (!skb_transport_header_was_set(skb)) | |
4817 | return 0; | |
4818 | if (tcp_hdr(skb)->syn) | |
4819 | return 1; | |
4820 | ||
4821 | return 0; | |
4822 | } | |
4823 | ||
4824 | int slsi_is_dns_packet(u8 *data) | |
4825 | { | |
4826 | u8 *p; | |
4827 | ||
4828 | p = data + SLSI_IP_TYPE_OFFSET; | |
4829 | ||
4830 | if (*p == SLSI_IP_TYPE_UDP) { | |
4831 | u16 dest_port; | |
4832 | ||
4833 | p = data + SLSI_IP_DEST_PORT_OFFSET; | |
4834 | dest_port = p[0] << 8 | p[1]; | |
4835 | if (dest_port == SLSI_DNS_DEST_PORT) /* 0x0035 */ | |
4836 | return 1; | |
4837 | } | |
4838 | ||
4839 | return 0; | |
4840 | } | |
4841 | ||
4842 | int slsi_is_mdns_packet(u8 *data) | |
4843 | { | |
4844 | u8 *p; | |
4845 | ||
4846 | p = data + SLSI_IP_TYPE_OFFSET; | |
4847 | ||
4848 | if (*p == SLSI_IP_TYPE_UDP) { | |
4849 | u16 dest_port; | |
4850 | ||
4851 | p = data + SLSI_IP_DEST_PORT_OFFSET; | |
4852 | dest_port = p[0] << 8 | p[1]; | |
4853 | if (dest_port == SLSI_MDNS_DEST_PORT) | |
4854 | return 1; | |
4855 | } | |
4856 | return 0; | |
4857 | } | |
4858 | #endif | |
4859 | ||
4860 | int slsi_ap_prepare_add_info_ies(struct netdev_vif *ndev_vif, const u8 *ies, size_t ies_len) | |
4861 | { | |
4862 | const u8 *wps_p2p_ies = NULL; | |
4863 | size_t wps_p2p_ie_len = 0; | |
4864 | ||
4865 | /* The ies may contain Extended Capability followed by WPS IE. The Extended capability IE needs to be excluded. */ | |
4866 | wps_p2p_ies = cfg80211_find_ie(SLSI_WLAN_EID_VENDOR_SPECIFIC, ies, ies_len); | |
4867 | if (wps_p2p_ies) { | |
4868 | size_t temp_len = wps_p2p_ies - ies; | |
4869 | ||
4870 | wps_p2p_ie_len = ies_len - temp_len; | |
4871 | } | |
4872 | ||
4873 | SLSI_NET_DBG2(ndev_vif->wdev.netdev, SLSI_MLME, "WPA IE len = %zu, WMM IE len = %zu, IEs len = %zu, WPS_P2P IEs len = %zu\n", | |
4874 | ndev_vif->ap.wpa_ie_len, ndev_vif->ap.wmm_ie_len, ies_len, wps_p2p_ie_len); | |
4875 | ||
4876 | ndev_vif->ap.add_info_ies_len = ndev_vif->ap.wpa_ie_len + ndev_vif->ap.wmm_ie_len + wps_p2p_ie_len; | |
4877 | ndev_vif->ap.add_info_ies = kmalloc(ndev_vif->ap.add_info_ies_len, GFP_KERNEL); /* Caller needs to free this */ | |
4878 | ||
4879 | if (!ndev_vif->ap.add_info_ies) { | |
4880 | SLSI_NET_DBG1(ndev_vif->wdev.netdev, SLSI_MLME, "Failed to allocate memory for IEs\n"); | |
4881 | ndev_vif->ap.add_info_ies_len = 0; | |
4882 | return -ENOMEM; | |
4883 | } | |
4884 | ||
4885 | if (ndev_vif->ap.cache_wpa_ie) { | |
4886 | memcpy(ndev_vif->ap.add_info_ies, ndev_vif->ap.cache_wpa_ie, ndev_vif->ap.wpa_ie_len); | |
4887 | ndev_vif->ap.add_info_ies += ndev_vif->ap.wpa_ie_len; | |
4888 | } | |
4889 | ||
4890 | if (ndev_vif->ap.cache_wmm_ie) { | |
4891 | memcpy(ndev_vif->ap.add_info_ies, ndev_vif->ap.cache_wmm_ie, ndev_vif->ap.wmm_ie_len); | |
4892 | ndev_vif->ap.add_info_ies += ndev_vif->ap.wmm_ie_len; | |
4893 | } | |
4894 | ||
4895 | if (wps_p2p_ies) { | |
4896 | memcpy(ndev_vif->ap.add_info_ies, wps_p2p_ies, wps_p2p_ie_len); | |
4897 | ndev_vif->ap.add_info_ies += wps_p2p_ie_len; | |
4898 | } | |
4899 | ||
4900 | ndev_vif->ap.add_info_ies -= ndev_vif->ap.add_info_ies_len; | |
4901 | ||
4902 | return 0; | |
4903 | } | |
4904 | ||
4905 | /* Set the correct bit in the channel sets */ | |
4906 | static void slsi_roam_channel_cache_add_channel(struct slsi_roaming_network_map_entry *network_map, u8 channel) | |
4907 | { | |
4908 | if (channel <= 14) | |
4909 | network_map->channels_24_ghz |= (1 << channel); | |
4910 | else if (channel >= 36 && channel <= 64) /* Uni1 */ | |
4911 | network_map->channels_5_ghz |= (1 << ((channel - 36) / 4)); | |
4912 | else if (channel >= 100 && channel <= 140) /* Uni2 */ | |
4913 | network_map->channels_5_ghz |= (1 << (8 + ((channel - 100) / 4))); | |
4914 | else if (channel >= 149 && channel <= 165) /* Uni3 */ | |
4915 | network_map->channels_5_ghz |= (1 << (24 + ((channel - 149) / 4))); | |
4916 | } | |
4917 | ||
4918 | void slsi_roam_channel_cache_add_entry(struct slsi_dev *sdev, struct net_device *dev, const u8 *ssid, const u8 *bssid, u8 channel) | |
4919 | { | |
4920 | struct list_head *pos; | |
4921 | int found = 0; | |
4922 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
4923 | ||
4924 | list_for_each(pos, &ndev_vif->sta.network_map) { | |
4925 | struct slsi_roaming_network_map_entry *network_map = list_entry(pos, struct slsi_roaming_network_map_entry, list); | |
4926 | ||
4927 | if (network_map->ssid.ssid_len == ssid[1] && | |
4928 | memcmp(network_map->ssid.ssid, &ssid[2], ssid[1]) == 0) { | |
4929 | found = 1; | |
4930 | network_map->last_seen_jiffies = jiffies; | |
4931 | if (network_map->only_one_ap_seen && memcmp(network_map->initial_bssid, bssid, ETH_ALEN) != 0) | |
4932 | network_map->only_one_ap_seen = false; | |
4933 | slsi_roam_channel_cache_add_channel(network_map, channel); | |
4934 | break; | |
4935 | } | |
4936 | } | |
4937 | if (!found) { | |
4938 | struct slsi_roaming_network_map_entry *network_map; | |
4939 | ||
4940 | SLSI_NET_DBG3(dev, SLSI_MLME, "New Entry : Channel: %d : %.*s\n", channel, ssid[1], &ssid[2]); | |
4941 | network_map = kmalloc(sizeof(*network_map), GFP_ATOMIC); | |
4942 | if (network_map) { | |
4943 | network_map->ssid.ssid_len = ssid[1]; | |
4944 | memcpy(network_map->ssid.ssid, &ssid[2], ssid[1]); | |
4945 | network_map->channels_24_ghz = 0; | |
4946 | network_map->channels_5_ghz = 0; | |
4947 | network_map->last_seen_jiffies = jiffies; | |
4948 | SLSI_ETHER_COPY(network_map->initial_bssid, bssid); | |
4949 | network_map->only_one_ap_seen = true; | |
4950 | slsi_roam_channel_cache_add_channel(network_map, channel); | |
4951 | list_add(&network_map->list, &ndev_vif->sta.network_map); | |
4952 | } else { | |
4953 | SLSI_ERR(sdev, "New Entry : %.*s kmalloc() failed\n", ssid[1], &ssid[2]); | |
4954 | } | |
4955 | } | |
4956 | } | |
4957 | ||
4958 | void slsi_roam_channel_cache_add(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *skb) | |
4959 | { | |
4960 | struct ieee80211_mgmt *mgmt = fapi_get_mgmt(skb); | |
4961 | size_t mgmt_len = fapi_get_mgmtlen(skb); | |
4962 | int ielen = mgmt_len - (mgmt->u.beacon.variable - (u8 *)mgmt); | |
4963 | u32 freq = fapi_get_u16(skb, u.mlme_scan_ind.channel_frequency) / 2; | |
4964 | const u8 *scan_ds = cfg80211_find_ie(WLAN_EID_DS_PARAMS, mgmt->u.beacon.variable, ielen); | |
4965 | const u8 *scan_ht = cfg80211_find_ie(WLAN_EID_HT_OPERATION, mgmt->u.beacon.variable, ielen); | |
4966 | const u8 *scan_ssid = cfg80211_find_ie(WLAN_EID_SSID, mgmt->u.beacon.variable, ielen); | |
4967 | u8 chan = 0; | |
4968 | ||
4969 | /* Use the DS or HT channel as the Offchannel results mean the RX freq is not reliable */ | |
4970 | if (scan_ds) | |
4971 | chan = scan_ds[2]; | |
4972 | else if (scan_ht) | |
4973 | chan = scan_ht[2]; | |
4974 | else | |
4975 | chan = ieee80211_frequency_to_channel(freq); | |
4976 | ||
4977 | if (chan) { | |
4978 | enum nl80211_band band = NL80211_BAND_2GHZ; | |
4979 | ||
4980 | if (chan > 14) | |
4981 | band = NL80211_BAND_5GHZ; | |
4982 | ||
4983 | #ifdef CONFIG_SCSC_WLAN_DEBUG | |
4984 | if (freq != (u32)ieee80211_channel_to_frequency(chan, band)) { | |
4985 | if (band == NL80211_BAND_5GHZ && freq < 3000) | |
4986 | SLSI_NET_DBG2(dev, SLSI_MLME, "Off Band Result : mlme_scan_ind(freq:%d) != DS(freq:%d)\n", freq, ieee80211_channel_to_frequency(chan, band)); | |
4987 | ||
4988 | if (band == NL80211_BAND_2GHZ && freq > 3000) | |
4989 | SLSI_NET_DBG2(dev, SLSI_MLME, "Off Band Result : mlme_scan_ind(freq:%d) != DS(freq:%d)\n", freq, ieee80211_channel_to_frequency(chan, band)); | |
4990 | } | |
4991 | #endif | |
4992 | } | |
4993 | ||
4994 | if (!scan_ssid || !scan_ssid[1] || scan_ssid[1] > 32) { | |
4995 | SLSI_NET_DBG3(dev, SLSI_MLME, "SSID not defined : Could not find SSID ie or Hidden\n"); | |
4996 | return; | |
4997 | } | |
4998 | ||
4999 | slsi_roam_channel_cache_add_entry(sdev, dev, scan_ssid, mgmt->bssid, chan); | |
5000 | } | |
5001 | ||
5002 | void slsi_roam_channel_cache_prune(struct net_device *dev, int seconds) | |
5003 | { | |
5004 | struct slsi_roaming_network_map_entry *network_map; | |
5005 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
5006 | struct list_head *pos, *q; | |
5007 | unsigned long now = jiffies; | |
5008 | unsigned long age; | |
5009 | ||
5010 | list_for_each_safe(pos, q, &ndev_vif->sta.network_map) { | |
5011 | network_map = list_entry(pos, struct slsi_roaming_network_map_entry, list); | |
5012 | age = (now - network_map->last_seen_jiffies) / HZ; | |
5013 | ||
5014 | if (time_after_eq(now, network_map->last_seen_jiffies + (seconds * HZ))) { | |
5015 | list_del(pos); | |
5016 | kfree(network_map); | |
5017 | } | |
5018 | } | |
5019 | } | |
5020 | ||
5021 | int slsi_roam_channel_cache_get_channels_int(struct net_device *dev, struct slsi_roaming_network_map_entry *network_map, u8 *channels) | |
5022 | { | |
5023 | int index = 0; | |
5024 | int i; | |
5025 | ||
5026 | SLSI_UNUSED_PARAMETER(dev); | |
5027 | ||
5028 | /* 2.4 Ghz Channels */ | |
5029 | for (i = 1; i <= 14; i++) | |
5030 | if (network_map->channels_24_ghz & (1 << i)) { | |
5031 | channels[index] = i; | |
5032 | index++; | |
5033 | } | |
5034 | ||
5035 | /* 5 Ghz Uni1 Channels */ | |
5036 | for (i = 36; i <= 64; i += 4) | |
5037 | if (network_map->channels_5_ghz & (1 << ((i - 36) / 4))) { | |
5038 | channels[index] = i; | |
5039 | index++; | |
5040 | } | |
5041 | ||
5042 | /* 5 Ghz Uni2 Channels */ | |
5043 | for (i = 100; i <= 140; i += 4) | |
5044 | if (network_map->channels_5_ghz & (1 << (8 + ((i - 100) / 4)))) { | |
5045 | channels[index] = i; | |
5046 | index++; | |
5047 | } | |
5048 | ||
5049 | /* 5 Ghz Uni3 Channels */ | |
5050 | for (i = 149; i <= 165; i += 4) | |
5051 | if (network_map->channels_5_ghz & (1 << (24 + ((i - 149) / 4)))) { | |
5052 | channels[index] = i; | |
5053 | index++; | |
5054 | } | |
5055 | return index; | |
5056 | } | |
5057 | ||
5058 | struct slsi_roaming_network_map_entry *slsi_roam_channel_cache_get(struct net_device *dev, const u8 *ssid) | |
5059 | { | |
5060 | struct slsi_roaming_network_map_entry *network_map = NULL; | |
5061 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
5062 | struct list_head *pos; | |
5063 | ||
5064 | if (WARN_ON(!ssid)) | |
5065 | return NULL; | |
5066 | ||
5067 | list_for_each(pos, &ndev_vif->sta.network_map) { | |
5068 | network_map = list_entry(pos, struct slsi_roaming_network_map_entry, list); | |
5069 | if (network_map->ssid.ssid_len == ssid[1] && | |
5070 | memcmp(network_map->ssid.ssid, &ssid[2], ssid[1]) == 0) | |
5071 | break; | |
5072 | } | |
5073 | return network_map; | |
5074 | } | |
5075 | ||
5076 | u32 slsi_roam_channel_cache_get_channels(struct net_device *dev, const u8 *ssid, u8 *channels) | |
5077 | { | |
5078 | u32 channels_count = 0; | |
5079 | struct slsi_roaming_network_map_entry *network_map; | |
5080 | ||
5081 | network_map = slsi_roam_channel_cache_get(dev, ssid); | |
5082 | if (network_map) | |
5083 | channels_count = slsi_roam_channel_cache_get_channels_int(dev, network_map, channels); | |
5084 | ||
5085 | return channels_count; | |
5086 | } | |
5087 | ||
5088 | int slsi_roaming_scan_configure_channels(struct slsi_dev *sdev, struct net_device *dev, const u8 *ssid, u8 *channels) | |
5089 | { | |
5090 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
5091 | u32 cached_channels_count; | |
5092 | ||
5093 | SLSI_UNUSED_PARAMETER(sdev); | |
5094 | ||
5095 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
5096 | WARN_ON(!ndev_vif->activated); | |
5097 | WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION); | |
5098 | ||
5099 | cached_channels_count = slsi_roam_channel_cache_get_channels(dev, ssid, channels); | |
5100 | SLSI_NET_DBG3(dev, SLSI_MLME, "Roaming Scan Channels. %d cached\n", cached_channels_count); | |
5101 | ||
5102 | return cached_channels_count; | |
5103 | } | |
5104 | ||
5105 | int slsi_send_acs_event(struct slsi_dev *sdev, struct slsi_acs_selected_channels acs_selected_channels) | |
5106 | { | |
5107 | struct sk_buff *skb = NULL; | |
5108 | u8 err = 0; | |
5109 | ||
5110 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) | |
5111 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, NULL, NLMSG_DEFAULT_SIZE, | |
5112 | SLSI_NL80211_VENDOR_ACS_EVENT, GFP_KERNEL); | |
5113 | #else | |
5114 | skb = cfg80211_vendor_event_alloc(sdev->wiphy, NLMSG_DEFAULT_SIZE, | |
5115 | SLSI_NL80211_VENDOR_ACS_EVENT, GFP_KERNEL); | |
5116 | #endif | |
5117 | if (!skb) { | |
5118 | SLSI_ERR_NODEV("Failed to allocate skb for VENDOR ACS event\n"); | |
5119 | return -ENOMEM; | |
5120 | } | |
5121 | err |= nla_put_u8(skb, SLSI_ACS_ATTR_PRIMARY_CHANNEL, acs_selected_channels.pri_channel); | |
5122 | err |= nla_put_u8(skb, SLSI_ACS_ATTR_SECONDARY_CHANNEL, acs_selected_channels.sec_channel); | |
5123 | err |= nla_put_u8(skb, SLSI_ACS_ATTR_VHT_SEG0_CENTER_CHANNEL, acs_selected_channels.vht_seg0_center_ch); | |
5124 | err |= nla_put_u8(skb, SLSI_ACS_ATTR_VHT_SEG1_CENTER_CHANNEL, acs_selected_channels.vht_seg1_center_ch); | |
5125 | err |= nla_put_u16(skb, SLSI_ACS_ATTR_CHWIDTH, acs_selected_channels.ch_width); | |
5126 | err |= nla_put_u8(skb, SLSI_ACS_ATTR_HW_MODE, acs_selected_channels.hw_mode); | |
5127 | SLSI_DBG3(sdev, SLSI_MLME, "pri_channel=%d,sec_channel=%d,vht_seg0_center_ch=%d," | |
5128 | "vht_seg1_center_ch=%d, ch_width=%d, hw_mode=%d\n", | |
5129 | acs_selected_channels.pri_channel, acs_selected_channels.sec_channel, | |
5130 | acs_selected_channels.vht_seg0_center_ch, acs_selected_channels.vht_seg1_center_ch, | |
5131 | acs_selected_channels.ch_width, acs_selected_channels.hw_mode); | |
5132 | if (err) { | |
5133 | SLSI_ERR_NODEV("Failed nla_put err=%d\n", err); | |
5134 | slsi_kfree_skb(skb); | |
5135 | return -EINVAL; | |
5136 | } | |
5137 | SLSI_INFO(sdev, "Event: SLSI_NL80211_VENDOR_ACS_EVENT(%d)\n", SLSI_NL80211_VENDOR_ACS_EVENT); | |
5138 | cfg80211_vendor_event(skb, GFP_KERNEL); | |
5139 | return 0; | |
5140 | } | |
5141 | ||
5142 | #ifdef CONFIG_SCSC_WLAN_WES_NCHO | |
5143 | int slsi_is_wes_action_frame(const struct ieee80211_mgmt *mgmt) | |
5144 | { | |
5145 | int r = 0; | |
5146 | /* Vendor specific Action (0x7f), SAMSUNG OUI (0x00, 0x00, 0xf0) */ | |
5147 | u8 wes_vs_action_frame[4] = { 0x7f, 0x00, 0x00, 0xf0 }; | |
5148 | u8 *action = (u8 *)&mgmt->u.action; | |
5149 | ||
5150 | if (memcmp(action, wes_vs_action_frame, 4) == 0) | |
5151 | r = 1; | |
5152 | ||
5153 | return r; | |
5154 | } | |
5155 | #endif | |
5156 | ||
5157 | static u32 slsi_remap_reg_rule_flags(u8 flags) | |
5158 | { | |
5159 | u32 remapped_flags = 0; | |
5160 | ||
5161 | if (flags & SLSI_REGULATORY_DFS) | |
5162 | remapped_flags |= NL80211_RRF_DFS; | |
5163 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
5164 | if (flags & SLSI_REGULATORY_NO_OFDM) | |
5165 | remapped_flags |= NL80211_RRF_NO_OFDM; | |
5166 | #endif | |
5167 | #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 13, 0)) | |
5168 | if (flags & SLSI_REGULATORY_NO_IR) | |
5169 | remapped_flags |= NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS; | |
5170 | #endif | |
5171 | if (flags & SLSI_REGULATORY_NO_INDOOR) | |
5172 | remapped_flags |= NL80211_RRF_NO_INDOOR; | |
5173 | if (flags & SLSI_REGULATORY_NO_OUTDOOR) | |
5174 | remapped_flags |= NL80211_RRF_NO_OUTDOOR; | |
5175 | ||
5176 | return remapped_flags; | |
5177 | } | |
5178 | ||
5179 | static void slsi_reg_mib_to_regd(struct slsi_mib_data *mib, struct slsi_802_11d_reg_domain *domain_info) | |
5180 | { | |
5181 | int i = 0; | |
5182 | int num_rules = 0; | |
5183 | u16 freq; | |
5184 | u8 byte_val; | |
5185 | struct ieee80211_reg_rule *reg_rule; | |
5186 | ||
5187 | domain_info->regdomain->alpha2[0] = *(u8 *)(&mib->data[i]); | |
5188 | i++; | |
5189 | ||
5190 | domain_info->regdomain->alpha2[1] = *(u8 *)(&mib->data[i]); | |
5191 | i++; | |
5192 | ||
5193 | domain_info->regdomain->dfs_region = *(u8 *)(&mib->data[i]); | |
5194 | i++; | |
5195 | ||
5196 | while (i < mib->dataLength) { | |
5197 | reg_rule = &domain_info->regdomain->reg_rules[num_rules]; | |
5198 | ||
5199 | /* start freq 2 bytes */ | |
5200 | freq = __le16_to_cpu(*(u16 *)(&mib->data[i])); | |
5201 | reg_rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq); | |
5202 | ||
5203 | /* end freq 2 bytes */ | |
5204 | freq = __le16_to_cpu(*(u16 *)(&mib->data[i + 2])); | |
5205 | reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq); | |
5206 | ||
5207 | /* Max Bandwidth 1 byte */ | |
5208 | byte_val = *(u8 *)(&mib->data[i + 4]); | |
5209 | reg_rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(byte_val); | |
5210 | ||
5211 | /* max_antenna_gain is obsolute now.*/ | |
5212 | reg_rule->power_rule.max_antenna_gain = 0; | |
5213 | ||
5214 | /* Max Power 1 byte */ | |
5215 | byte_val = *(u8 *)(&mib->data[i + 5]); | |
5216 | reg_rule->power_rule.max_eirp = DBM_TO_MBM(byte_val); | |
5217 | ||
5218 | /* Flags 1 byte */ | |
5219 | reg_rule->flags = slsi_remap_reg_rule_flags(*(u8 *)(&mib->data[i + 6])); | |
5220 | ||
5221 | i += 7; | |
5222 | ||
5223 | num_rules++; /* Num of reg rules */ | |
5224 | } | |
5225 | ||
5226 | domain_info->regdomain->n_reg_rules = num_rules; | |
5227 | } | |
5228 | ||
5229 | void slsi_reset_channel_flags(struct slsi_dev *sdev) | |
5230 | { | |
5231 | enum nl80211_band band; | |
5232 | struct ieee80211_channel *chan; | |
5233 | int i; | |
5234 | struct wiphy *wiphy = sdev->wiphy; | |
5235 | ||
5236 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) | |
5237 | for (band = 0; band < NUM_NL80211_BANDS; band++) { | |
5238 | #else | |
5239 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | |
5240 | #endif | |
5241 | if (!wiphy->bands[band]) | |
5242 | continue; | |
5243 | for (i = 0; i < wiphy->bands[band]->n_channels; i++) { | |
5244 | chan = &wiphy->bands[band]->channels[i]; | |
5245 | chan->flags = 0; | |
5246 | } | |
5247 | } | |
5248 | } | |
5249 | ||
5250 | int slsi_read_regulatory_rules(struct slsi_dev *sdev, struct slsi_802_11d_reg_domain *domain_info, const char *alpha2) | |
5251 | { | |
5252 | int i = 0; | |
5253 | int country_index = 0; | |
5254 | struct ieee80211_reg_rule *reg_rule = NULL; | |
5255 | ||
5256 | if ((sdev->regdb.regdb_state == SLSI_REG_DB_NOT_SET) || (sdev->regdb.regdb_state == SLSI_REG_DB_ERROR)) { | |
5257 | SLSI_ERR(sdev, "Regulatory is not set!\n"); | |
5258 | return slsi_read_regulatory_rules_fw(sdev, domain_info, alpha2); | |
5259 | } | |
5260 | ||
5261 | for (i = 0; i < sdev->regdb.num_countries; i++) { | |
5262 | if ((sdev->regdb.country[i].alpha2[0] == alpha2[0]) && (sdev->regdb.country[i].alpha2[1] == alpha2[1])) { | |
5263 | country_index = i; | |
5264 | break; | |
5265 | } | |
5266 | } | |
5267 | ||
5268 | domain_info->regdomain->alpha2[0] = sdev->regdb.country[country_index].alpha2[0]; | |
5269 | domain_info->regdomain->alpha2[1] = sdev->regdb.country[country_index].alpha2[1]; | |
5270 | domain_info->regdomain->dfs_region = sdev->regdb.country[country_index].dfs_region; | |
5271 | ||
5272 | for (i = 0; i < sdev->regdb.country[country_index].collection->reg_rule_num; i++) { | |
5273 | reg_rule = &domain_info->regdomain->reg_rules[i]; | |
5274 | ||
5275 | /* start freq 2 bytes */ | |
5276 | reg_rule->freq_range.start_freq_khz = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->start_freq * 1000); | |
5277 | ||
5278 | /* end freq 2 bytes */ | |
5279 | reg_rule->freq_range.end_freq_khz = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->end_freq * 1000); | |
5280 | ||
5281 | /* Max Bandwidth 1 byte */ | |
5282 | reg_rule->freq_range.max_bandwidth_khz = (sdev->regdb.country[country_index].collection->reg_rule[i]->freq_range->max_bandwidth * 1000); | |
5283 | ||
5284 | /* max_antenna_gain is obsolete now. */ | |
5285 | reg_rule->power_rule.max_antenna_gain = 0; | |
5286 | ||
5287 | /* Max Power 1 byte */ | |
5288 | reg_rule->power_rule.max_eirp = (sdev->regdb.country[country_index].collection->reg_rule[i]->max_eirp * 100); | |
5289 | ||
5290 | /* Flags 1 byte */ | |
5291 | reg_rule->flags = slsi_remap_reg_rule_flags(sdev->regdb.country[country_index].collection->reg_rule[i]->flags); | |
5292 | } | |
5293 | ||
5294 | domain_info->regdomain->n_reg_rules = sdev->regdb.country[country_index].collection->reg_rule_num; | |
5295 | ||
5296 | return 0; | |
5297 | } | |
5298 | ||
5299 | int slsi_read_regulatory_rules_fw(struct slsi_dev *sdev, struct slsi_802_11d_reg_domain *domain_info, const char *alpha2) | |
5300 | { | |
5301 | struct slsi_mib_data mibreq = { 0, NULL }; | |
5302 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
5303 | struct slsi_mib_entry mib_val; | |
5304 | int r = 0; | |
5305 | int rx_len = 0; | |
5306 | int len = 0; | |
5307 | int index; | |
5308 | ||
5309 | index = slsi_country_to_index(domain_info, alpha2); | |
5310 | ||
5311 | if (index == -1) { | |
5312 | SLSI_ERR(sdev, "Unsupported index\n"); | |
5313 | return -EINVAL; | |
5314 | } | |
5315 | ||
5316 | slsi_mib_encode_get(&mibreq, SLSI_PSID_UNIFI_REGULATORY_PARAMETERS, index); | |
5317 | ||
5318 | /* Max of 6 regulatory constraints. | |
5319 | * each constraint start_freq(2 byte), end_freq(2 byte), Band width(1 byte), Max power(1 byte), | |
5320 | * rules flag (1 byte) | |
5321 | * firmware can have a max of 6 rules for a country. | |
5322 | */ | |
5323 | /* PSID header (5 bytes) + ((3 bytes) alpha2 code + dfs) + (max of 50 regulatory rules * 7 bytes each row) + MIB status(1) */ | |
5324 | mibrsp.dataLength = 5 + 3 + (SLSI_MIB_REG_RULES_MAX * 7) + 1; | |
5325 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
5326 | ||
5327 | if (!mibrsp.data) { | |
5328 | SLSI_ERR(sdev, "Failed to alloc for Mib response\n"); | |
5329 | kfree(mibreq.data); | |
5330 | return -ENOMEM; | |
5331 | } | |
5332 | ||
5333 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, | |
5334 | mibrsp.data, mibrsp.dataLength, &rx_len); | |
5335 | kfree(mibreq.data); | |
5336 | ||
5337 | if (r == 0) { | |
5338 | mibrsp.dataLength = rx_len; | |
5339 | ||
5340 | len = slsi_mib_decode(&mibrsp, &mib_val); | |
5341 | ||
5342 | if (len == 0) { | |
5343 | kfree(mibrsp.data); | |
5344 | SLSI_ERR(sdev, "Mib decode error\n"); | |
5345 | return -EINVAL; | |
5346 | } | |
5347 | slsi_reg_mib_to_regd(&mib_val.value.u.octetValue, domain_info); | |
5348 | } else { | |
5349 | SLSI_ERR(sdev, "Mib read failed (error: %d)\n", r); | |
5350 | } | |
5351 | ||
5352 | kfree(mibrsp.data); | |
5353 | return r; | |
5354 | } | |
5355 | ||
5356 | static int slsi_country_to_index(struct slsi_802_11d_reg_domain *domain_info, const char *alpha2) | |
5357 | { | |
5358 | int index = 0; | |
5359 | bool index_found = false; | |
5360 | ||
5361 | SLSI_DBG3_NODEV(SLSI_MLME, "\n"); | |
5362 | if (domain_info->countrylist) { | |
5363 | for (index = 0; index < domain_info->country_len; index += 2) { | |
5364 | if (memcmp(&domain_info->countrylist[index], alpha2, 2) == 0) { | |
5365 | index_found = true; | |
5366 | break; | |
5367 | } | |
5368 | } | |
5369 | ||
5370 | /* If the set country is not present in the country list, fall back to | |
5371 | * world domain i.e. regulatory rules index = 1 | |
5372 | */ | |
5373 | if (index_found) | |
5374 | return (index / 2) + 1; | |
5375 | else | |
5376 | return 1; | |
5377 | } | |
5378 | ||
5379 | return -1; | |
5380 | } | |
5381 | ||
5382 | ||
5383 | /* Set the rssi boost value of a particular band as set in the SETJOINPREFER command*/ | |
5384 | int slsi_set_mib_rssi_boost(struct slsi_dev *sdev, struct net_device *dev, u16 psid, int index, int boost) | |
5385 | { | |
5386 | struct slsi_mib_data mib_data = { 0, NULL }; | |
5387 | int error = SLSI_MIB_STATUS_FAILURE; | |
5388 | ||
5389 | SLSI_DBG2(sdev, SLSI_MLME, "Set rssi boost: %d\n", boost); | |
5390 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(sdev->device_config_mutex)); | |
5391 | if (slsi_mib_encode_int(&mib_data, psid, boost, index) == SLSI_MIB_STATUS_SUCCESS) | |
5392 | if (mib_data.dataLength) { | |
5393 | error = slsi_mlme_set(sdev, NULL, mib_data.data, mib_data.dataLength); | |
5394 | if (error) | |
5395 | SLSI_ERR(sdev, "Err Setting MIB failed. error = %d\n", error); | |
5396 | kfree(mib_data.data); | |
5397 | } | |
5398 | ||
5399 | return error; | |
5400 | } | |
5401 | ||
5402 | #ifdef CONFIG_SCSC_WLAN_LOW_LATENCY_MODE | |
5403 | int slsi_set_mib_soft_roaming_enabled(struct slsi_dev *sdev, struct net_device *dev, bool enable) | |
5404 | { | |
5405 | struct slsi_mib_data mib_data = { 0, NULL }; | |
5406 | int error = SLSI_MIB_STATUS_FAILURE; | |
5407 | ||
5408 | if (slsi_mib_encode_bool(&mib_data, SLSI_PSID_UNIFI_ROAM_SOFT_ROAMING_ENABLED, | |
5409 | enable, 0) == SLSI_MIB_STATUS_SUCCESS) | |
5410 | if (mib_data.dataLength) { | |
5411 | error = slsi_mlme_set(sdev, dev, mib_data.data, mib_data.dataLength); | |
5412 | if (error) | |
5413 | SLSI_ERR(sdev, "Err Setting MIB failed. error = %d\n", error); | |
5414 | kfree(mib_data.data); | |
5415 | } | |
5416 | ||
5417 | return error; | |
5418 | } | |
5419 | #endif | |
5420 | ||
5421 | #ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT | |
5422 | int slsi_read_enhanced_arp_rx_count_by_lower_mac(struct slsi_dev *sdev, struct net_device *dev, u16 psid) | |
5423 | { | |
5424 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
5425 | struct slsi_mib_data mibreq = { 0, NULL }; | |
5426 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
5427 | struct slsi_mib_entry mib_val; | |
5428 | int r = 0; | |
5429 | int rx_len = 0; | |
5430 | int len = 0; | |
5431 | ||
5432 | SLSI_DBG3(sdev, SLSI_MLME, "\n"); | |
5433 | ||
5434 | slsi_mib_encode_get(&mibreq, psid, 0); | |
5435 | ||
5436 | mibrsp.dataLength = 10; /* PSID header(5) + uint 4 bytes + status(1) */ | |
5437 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
5438 | ||
5439 | if (!mibrsp.data) { | |
5440 | SLSI_ERR(sdev, "Failed to alloc for Mib response\n"); | |
5441 | kfree(mibreq.data); | |
5442 | return -ENOMEM; | |
5443 | } | |
5444 | ||
5445 | r = slsi_mlme_get(sdev, dev, mibreq.data, mibreq.dataLength, mibrsp.data, | |
5446 | mibrsp.dataLength, &rx_len); | |
5447 | kfree(mibreq.data); | |
5448 | ||
5449 | if (r == 0) { | |
5450 | mibrsp.dataLength = rx_len; | |
5451 | len = slsi_mib_decode(&mibrsp, &mib_val); | |
5452 | ||
5453 | if (len == 0) { | |
5454 | kfree(mibrsp.data); | |
5455 | SLSI_ERR(sdev, "Mib decode error\n"); | |
5456 | return -EINVAL; | |
5457 | } | |
5458 | ndev_vif->enhanced_arp_stats.arp_rsp_rx_count_by_lower_mac = mib_val.value.u.uintValue; | |
5459 | } else { | |
5460 | SLSI_ERR(sdev, "Mib read failed (error: %d)\n", r); | |
5461 | } | |
5462 | ||
5463 | kfree(mibrsp.data); | |
5464 | return r; | |
5465 | } | |
5466 | ||
5467 | void slsi_fill_enhanced_arp_out_of_order_drop_counter(struct netdev_vif *ndev_vif, | |
5468 | struct sk_buff *skb) | |
5469 | { | |
5470 | struct ethhdr *eth_hdr; | |
5471 | u8 *frame; | |
5472 | u16 arp_opcode; | |
5473 | ||
5474 | #ifdef CONFIG_SCSC_SMAPPER | |
5475 | /* Check if the payload is in the SMAPPER entry */ | |
5476 | if (fapi_get_u16(skb, u.ma_unitdata_ind.bulk_data_descriptor) == FAPI_BULKDATADESCRIPTOR_SMAPPER) { | |
5477 | frame = slsi_hip_get_skb_data_from_smapper(ndev_vif->sdev, skb); | |
5478 | eth_hdr = (struct ethhdr *)frame; | |
5479 | if (!(eth_hdr)) { | |
5480 | SLSI_DBG2(ndev_vif->sdev, SLSI_RX, "SKB from SMAPPER is NULL\n"); | |
5481 | return; | |
5482 | } | |
5483 | frame = frame + sizeof(struct ethhdr); | |
5484 | } else { | |
5485 | frame = fapi_get_data(skb) + sizeof(struct ethhdr); | |
5486 | eth_hdr = (struct ethhdr *)fapi_get_data(skb); | |
5487 | } | |
5488 | #else | |
5489 | frame = fapi_get_data(skb) + sizeof(struct ethhdr); | |
5490 | eth_hdr = (struct ethhdr *)fapi_get_data(skb); | |
5491 | #endif | |
5492 | ||
5493 | arp_opcode = frame[SLSI_ARP_OPCODE_OFFSET] << 8 | frame[SLSI_ARP_OPCODE_OFFSET + 1]; | |
5494 | /* check if sender ip = gateway ip and it is an ARP response*/ | |
5495 | if ((ntohs(eth_hdr->h_proto) == ETH_P_ARP) && | |
5496 | (arp_opcode == SLSI_ARP_REPLY_OPCODE) && | |
5497 | !SLSI_IS_GRATUITOUS_ARP(frame) && | |
5498 | !memcmp(&frame[SLSI_ARP_SRC_IP_ADDR_OFFSET], &ndev_vif->target_ip_addr, 4)) | |
5499 | ndev_vif->enhanced_arp_stats.arp_rsp_count_out_of_order_drop++; | |
5500 | } | |
5501 | #endif | |
5502 | ||
5503 | void slsi_modify_ies_on_channel_switch(struct net_device *dev, struct cfg80211_ap_settings *settings, | |
5504 | u8 *ds_params_ie, u8 *ht_operation_ie, struct ieee80211_mgmt *mgmt, | |
5505 | u16 beacon_ie_head_len) | |
5506 | { | |
5507 | slsi_modify_ies(dev, WLAN_EID_DS_PARAMS, mgmt->u.beacon.variable, | |
5508 | beacon_ie_head_len, 2, ieee80211_frequency_to_channel(settings->chandef.chan->center_freq)); | |
5509 | ||
5510 | slsi_modify_ies(dev, WLAN_EID_HT_OPERATION, (u8 *)settings->beacon.tail, | |
5511 | settings->beacon.tail_len, 2, | |
5512 | ieee80211_frequency_to_channel(settings->chandef.chan->center_freq)); | |
5513 | } | |
5514 | ||
5515 | #ifdef CONFIG_SCSC_WLAN_WIFI_SHARING | |
5516 | void slsi_extract_valid_wifi_sharing_channels(struct slsi_dev *sdev) | |
5517 | { | |
5518 | int i, j; | |
5519 | int p = 0; | |
5520 | int k = (SLSI_MAX_CHAN_5G_BAND - 1); | |
5521 | int flag = 0; | |
5522 | ||
5523 | for (i = 4; i >= 0 ; i--) { | |
5524 | for (j = 0; j <= 7 ; j++) { | |
5525 | if ((i == 4) && (j == 0)) | |
5526 | j = 1; | |
5527 | if (sdev->wifi_sharing_5ghz_channel[i] & (u8)(1 << (7 - j))) | |
5528 | sdev->valid_5g_chan[p] = slsi_5ghz_all_chans[k]; | |
5529 | else | |
5530 | sdev->valid_5g_chan[p] = 0; | |
5531 | p++; | |
5532 | k--; | |
5533 | if (p == SLSI_MAX_CHAN_5G_BAND) { | |
5534 | flag = 1; | |
5535 | break; | |
5536 | } | |
5537 | } | |
5538 | if (flag == 1) | |
5539 | break; | |
5540 | } | |
5541 | } | |
5542 | ||
5543 | bool slsi_if_valid_wifi_sharing_channel(struct slsi_dev *sdev, int freq) | |
5544 | { | |
5545 | int i; | |
5546 | ||
5547 | for (i = 0; i <= (SLSI_MAX_CHAN_5G_BAND - 1) ; i++) { | |
5548 | if (sdev->valid_5g_chan[i] == ieee80211_get_channel(sdev->wiphy, freq)->hw_value) | |
5549 | return 1; | |
5550 | } | |
5551 | return 0; | |
5552 | } | |
5553 | ||
5554 | int slsi_check_if_non_indoor_non_dfs_channel(struct slsi_dev *sdev, int freq) | |
5555 | { | |
5556 | struct ieee80211_channel *channel = NULL; | |
5557 | u32 chan_flags = 0; | |
5558 | ||
5559 | channel = ieee80211_get_channel(sdev->wiphy, freq); | |
5560 | if (!channel) { | |
5561 | SLSI_ERR(sdev, "Invalid frequency %d used to start AP. Channel not found\n", freq); | |
5562 | return 0; | |
5563 | } | |
5564 | ||
5565 | chan_flags = (IEEE80211_CHAN_INDOOR_ONLY | IEEE80211_CHAN_RADAR | | |
5566 | IEEE80211_CHAN_DISABLED | | |
5567 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 13) | |
5568 | IEEE80211_CHAN_PASSIVE_SCAN | |
5569 | #else | |
5570 | IEEE80211_CHAN_NO_IR | |
5571 | #endif | |
5572 | ); | |
5573 | ||
5574 | if ((channel->flags) & chan_flags) | |
5575 | return 0; | |
5576 | ||
5577 | return 1; | |
5578 | } | |
5579 | ||
5580 | int slsi_get_mhs_ws_chan_vsdb(struct wiphy *wiphy, struct net_device *dev, | |
5581 | struct cfg80211_ap_settings *settings, | |
5582 | struct slsi_dev *sdev, int *wifi_sharing_channel_switched) | |
5583 | { | |
5584 | struct net_device *sta_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN); | |
5585 | struct netdev_vif *ndev_sta_vif = netdev_priv(sta_dev); | |
5586 | int sta_frequency = ndev_sta_vif->chan->center_freq; | |
5587 | ||
5588 | if (!slsi_check_if_non_indoor_non_dfs_channel(sdev, sta_frequency)) | |
5589 | return 1; /*AP cannot start on indoor/DFS channel so we will reject request from the host*/ | |
5590 | ||
5591 | if ((settings->chandef.chan->center_freq) != (sta_frequency)) { | |
5592 | *wifi_sharing_channel_switched = 1; | |
5593 | settings->chandef.chan = ieee80211_get_channel(wiphy, sta_frequency); | |
5594 | settings->chandef.center_freq1 = sta_frequency; | |
5595 | if (((sta_frequency) / 1000) == 2) | |
5596 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
5597 | settings->chandef.width = NL80211_CHAN_WIDTH_20; | |
5598 | #endif | |
5599 | } | |
5600 | ||
5601 | return 0; | |
5602 | } | |
5603 | ||
5604 | int slsi_get_mhs_ws_chan_rsdb(struct wiphy *wiphy, struct net_device *dev, | |
5605 | struct cfg80211_ap_settings *settings, | |
5606 | struct slsi_dev *sdev, int *wifi_sharing_channel_switched) | |
5607 | { | |
5608 | struct net_device *sta_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN); | |
5609 | struct netdev_vif *ndev_sta_vif = netdev_priv(sta_dev); | |
5610 | int sta_frequency = ndev_sta_vif->chan->center_freq; | |
5611 | ||
5612 | if (((sta_frequency) / 1000) == 2) { /*For 2.4GHz */ | |
5613 | if ((((settings->chandef.chan->center_freq) / 1000) == 5) && | |
5614 | !(slsi_check_if_channel_restricted_already(sdev, | |
5615 | ieee80211_frequency_to_channel(settings->chandef.chan->center_freq))) && | |
5616 | slsi_if_valid_wifi_sharing_channel(sdev, settings->chandef.chan->center_freq) && | |
5617 | slsi_check_if_non_indoor_non_dfs_channel(sdev, settings->chandef.chan->center_freq)) { | |
5618 | settings->chandef.chan = ieee80211_get_channel(wiphy, settings->chandef.chan->center_freq); | |
5619 | settings->chandef.center_freq1 = settings->chandef.chan->center_freq; | |
5620 | } else { | |
5621 | if ((settings->chandef.chan->center_freq) != (sta_frequency)) { | |
5622 | *wifi_sharing_channel_switched = 1; | |
5623 | settings->chandef.chan = ieee80211_get_channel(wiphy, sta_frequency); | |
5624 | settings->chandef.center_freq1 = sta_frequency; | |
5625 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
5626 | settings->chandef.width = NL80211_CHAN_WIDTH_20; | |
5627 | #endif | |
5628 | } | |
5629 | } | |
5630 | } else { /* For 5GHz */ | |
5631 | if (((settings->chandef.chan->center_freq) / 1000) == 5) { | |
5632 | if (!(slsi_check_if_channel_restricted_already(sdev, | |
5633 | ieee80211_frequency_to_channel(sta_frequency))) && | |
5634 | slsi_if_valid_wifi_sharing_channel(sdev, sta_frequency) && | |
5635 | slsi_check_if_non_indoor_non_dfs_channel(sdev, sta_frequency)) { | |
5636 | if ((settings->chandef.chan->center_freq) != (sta_frequency)) { | |
5637 | *wifi_sharing_channel_switched = 1; | |
5638 | settings->chandef.chan = ieee80211_get_channel(wiphy, sta_frequency); | |
5639 | } | |
5640 | } else { | |
5641 | *wifi_sharing_channel_switched = 1; | |
5642 | settings->chandef.chan = ieee80211_get_channel(wiphy, SLSI_2G_CHANNEL_ONE); | |
5643 | settings->chandef.center_freq1 = SLSI_2G_CHANNEL_ONE; | |
5644 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
5645 | settings->chandef.width = NL80211_CHAN_WIDTH_20; | |
5646 | #endif | |
5647 | } | |
5648 | } | |
5649 | } | |
5650 | ||
5651 | return 0; | |
5652 | } | |
5653 | ||
5654 | int slsi_check_if_channel_restricted_already(struct slsi_dev *sdev, int channel) | |
5655 | { | |
5656 | int i; | |
5657 | ||
5658 | for (i = 0; i < sdev->num_5g_restricted_channels; i++) | |
5659 | if (sdev->wifi_sharing_5g_restricted_channels[i] == channel) | |
5660 | return 1; | |
5661 | ||
5662 | return 0; | |
5663 | } | |
5664 | ||
5665 | int slsi_set_wifisharing_permitted_channels(struct slsi_dev *sdev, struct net_device *dev, char *arg) | |
5666 | { | |
5667 | int error = 0; | |
5668 | int i = 0; | |
5669 | int bit = 0; /* find which bit to set */ | |
5670 | int j = 0; | |
5671 | int bit_mask = 0; | |
5672 | int num_channels = 0; | |
5673 | int readbyte = 0; | |
5674 | int offset = 0; | |
5675 | int indoor_chan_arg = 0; | |
5676 | u8 *permitted_channels = NULL; | |
5677 | ||
5678 | readbyte = slsi_str_to_int(&arg[offset], &indoor_chan_arg); | |
5679 | permitted_channels = kmalloc(8, GFP_KERNEL); | |
5680 | ||
5681 | if (!permitted_channels) { | |
5682 | error = -ENOMEM; | |
5683 | goto exit; | |
5684 | } | |
5685 | ||
5686 | /* res = 0 -> all 5G channels permitted */ | |
5687 | /* res = -1 -> no 5G channel permitted */ | |
5688 | /* res = n -> set n indoor channels */ | |
5689 | if (indoor_chan_arg == 0) { | |
5690 | SLSI_DBG2(sdev, SLSI_MLME, "All 5G channels permitted\n"); | |
5691 | sdev->num_5g_restricted_channels = 0; | |
5692 | for (i = 0; i < 25 ; i++) | |
5693 | sdev->wifi_sharing_5g_restricted_channels[i] = 0; | |
5694 | permitted_channels[0] = 0xFF; | |
5695 | permitted_channels[1] = 0xDF; | |
5696 | permitted_channels[2] = 0xFF; | |
5697 | permitted_channels[3] = 0xFF; | |
5698 | permitted_channels[4] = 0x7F; | |
5699 | permitted_channels[5] = 0x00; | |
5700 | permitted_channels[6] = 0x00; | |
5701 | permitted_channels[7] = 0x00; | |
5702 | } else if (indoor_chan_arg == -1) { | |
5703 | SLSI_DBG2(sdev, SLSI_MLME, "No 5G channel permitted\n"); | |
5704 | permitted_channels[0] = 0xFF; | |
5705 | permitted_channels[1] = 0x1F; | |
5706 | for (i = 2; i < 8; i++) | |
5707 | permitted_channels[i] = 0x00; | |
5708 | ||
5709 | for (i = 0; i < 25; i++) { | |
5710 | sdev->wifi_sharing_5g_restricted_channels[i] = slsi_5ghz_all_chans[i]; | |
5711 | } | |
5712 | sdev->num_5g_restricted_channels = 25; | |
5713 | } else { | |
5714 | sdev->num_5g_restricted_channels = 0; | |
5715 | for (i = 0; i < 25 ; i++) | |
5716 | sdev->wifi_sharing_5g_restricted_channels[i] = 0; | |
5717 | permitted_channels[0] = 0xFF; | |
5718 | permitted_channels[1] = 0xDF; | |
5719 | permitted_channels[2] = 0xFF; | |
5720 | permitted_channels[3] = 0xFF; | |
5721 | permitted_channels[4] = 0x7F; | |
5722 | permitted_channels[5] = 0x00; | |
5723 | permitted_channels[6] = 0x00; | |
5724 | permitted_channels[7] = 0x00; | |
5725 | num_channels = indoor_chan_arg; | |
5726 | if (num_channels > 25) { | |
5727 | error = -EINVAL; | |
5728 | goto exit; | |
5729 | } | |
5730 | ||
5731 | for (i = 0; i < num_channels; i++) { | |
5732 | offset = offset + readbyte + 1; | |
5733 | readbyte = slsi_str_to_int(&arg[offset], &indoor_chan_arg); | |
5734 | sdev->wifi_sharing_5g_restricted_channels[(sdev->num_5g_restricted_channels)++] = indoor_chan_arg; | |
5735 | ||
5736 | for (j = 0; j < 25; j++) { | |
5737 | if (slsi_5ghz_all_chans[j] == sdev->wifi_sharing_5g_restricted_channels[i]) { | |
5738 | bit = j + 14; | |
5739 | break; | |
5740 | } | |
5741 | } | |
5742 | if ((bit < 14) || (bit > 38)) { | |
5743 | error = -EINVAL; | |
5744 | SLSI_ERR(sdev, "Incorrect bit position = %d\n", bit); | |
5745 | goto exit; | |
5746 | } | |
5747 | ||
5748 | bit_mask = (bit % 8); | |
5749 | permitted_channels[bit / 8] &= (u8)(~(1 << (bit_mask))); | |
5750 | } | |
5751 | } | |
5752 | ||
5753 | error = slsi_mlme_wifisharing_permitted_channels(sdev, dev, permitted_channels); | |
5754 | ||
5755 | exit: | |
5756 | if (error) | |
5757 | SLSI_ERR(sdev, "Error in setting wifi sharing permitted channels. error = %d\n", error); | |
5758 | kfree(permitted_channels); | |
5759 | return error; | |
5760 | } | |
5761 | #endif | |
5762 | #ifdef CONFIG_SCSC_WLAN_ENABLE_MAC_RANDOMISATION | |
5763 | int slsi_set_mac_randomisation_mask(struct slsi_dev *sdev, u8 *mac_address_mask) | |
5764 | { | |
5765 | int r = 0; | |
5766 | struct slsi_mib_data mib_data = { 0, NULL }; | |
5767 | ||
5768 | SLSI_DBG1(sdev, SLSI_CFG80211, "Mask is :%pM\n", mac_address_mask); | |
5769 | r = slsi_mib_encode_octet(&mib_data, SLSI_PSID_UNIFI_MAC_ADDRESS_RANDOMISATION_MASK, ETH_ALEN, | |
5770 | mac_address_mask, 0); | |
5771 | if (r != SLSI_MIB_STATUS_SUCCESS) { | |
5772 | return -ENOMEM; | |
5773 | } | |
5774 | ||
5775 | r = slsi_mlme_set(sdev, NULL, mib_data.data, mib_data.dataLength); | |
5776 | kfree(mib_data.data); | |
5777 | ||
5778 | if (r != SLSI_MIB_STATUS_SUCCESS) { | |
5779 | SLSI_ERR(sdev, "Err setting unifiMacAddrRandomistaionMask MIB. error = %d\n", r); | |
5780 | if (sdev->scan_addr_set) { | |
5781 | struct slsi_mib_data mib_data_randomization_activated = { 0, NULL }; | |
5782 | ||
5783 | r = slsi_mib_encode_bool(&mib_data_randomization_activated, | |
5784 | SLSI_PSID_UNIFI_MAC_ADDRESS_RANDOMISATION, 1, 0); | |
5785 | if (r != SLSI_MIB_STATUS_SUCCESS) | |
5786 | return -ENOMEM; | |
5787 | ||
5788 | r = slsi_mlme_set(sdev, NULL, mib_data_randomization_activated.data, | |
5789 | mib_data_randomization_activated.dataLength); | |
5790 | ||
5791 | kfree(mib_data_randomization_activated.data); | |
5792 | ||
5793 | if (r) { | |
5794 | SLSI_ERR(sdev, "Err setting unifiMacAddrRandomistaionActivated MIB. error = %d\n", r); | |
5795 | return r; | |
5796 | } | |
5797 | } | |
5798 | } | |
5799 | return r; | |
5800 | } | |
5801 | #endif | |
5802 | /* Set the new country code and read the regulatory parameters of updated country. */ | |
5803 | int slsi_set_country_update_regd(struct slsi_dev *sdev, const char *alpha2_code, int size) | |
5804 | { | |
5805 | char alpha2[4]; | |
5806 | int error = 0; | |
5807 | ||
5808 | SLSI_DBG2(sdev, SLSI_MLME, "Set country code: %c%c\n", alpha2_code[0], alpha2_code[1]); | |
5809 | ||
5810 | if (size == 4) { | |
5811 | memcpy(alpha2, alpha2_code, 4); | |
5812 | } else { | |
5813 | memcpy(alpha2, alpha2_code, 3); | |
5814 | alpha2[3] = '\0'; | |
5815 | } | |
5816 | ||
5817 | if (memcmp(alpha2, sdev->device_config.domain_info.regdomain->alpha2, 2) == 0) { | |
5818 | SLSI_DBG3(sdev, SLSI_MLME, "Country is already set to the requested country code\n"); | |
5819 | return 0; | |
5820 | } | |
5821 | ||
5822 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
5823 | error = slsi_mlme_set_country(sdev, alpha2); | |
5824 | ||
5825 | if (error) { | |
5826 | SLSI_ERR(sdev, "Err setting country error = %d\n", error); | |
5827 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
5828 | return -1; | |
5829 | } | |
5830 | ||
5831 | /* Read the regulatory params for the country */ | |
5832 | if (slsi_read_regulatory_rules(sdev, &sdev->device_config.domain_info, alpha2) == 0) { | |
5833 | slsi_reset_channel_flags(sdev); | |
5834 | wiphy_apply_custom_regulatory(sdev->wiphy, sdev->device_config.domain_info.regdomain); | |
5835 | slsi_update_supported_channels_regd_flags(sdev); | |
5836 | } | |
5837 | ||
5838 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
5839 | return error; | |
5840 | } | |
5841 | ||
5842 | /* Read unifiDisconnectTimeOut MIB */ | |
5843 | int slsi_read_disconnect_ind_timeout(struct slsi_dev *sdev, u16 psid) | |
5844 | { | |
5845 | struct slsi_mib_data mibreq = { 0, NULL }; | |
5846 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
5847 | struct slsi_mib_entry mib_val; | |
5848 | int r = 0; | |
5849 | int rx_len = 0; | |
5850 | int len = 0; | |
5851 | ||
5852 | SLSI_DBG3(sdev, SLSI_MLME, "\n"); | |
5853 | ||
5854 | slsi_mib_encode_get(&mibreq, psid, 0); | |
5855 | ||
5856 | mibrsp.dataLength = 10; /* PSID header(5) + uint 4 bytes + status(1) */ | |
5857 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
5858 | ||
5859 | if (!mibrsp.data) { | |
5860 | SLSI_ERR(sdev, "Failed to alloc for Mib response\n"); | |
5861 | kfree(mibreq.data); | |
5862 | return -ENOMEM; | |
5863 | } | |
5864 | ||
5865 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, mibrsp.data, | |
5866 | mibrsp.dataLength, &rx_len); | |
5867 | kfree(mibreq.data); | |
5868 | ||
5869 | if (r == 0) { | |
5870 | mibrsp.dataLength = rx_len; | |
5871 | len = slsi_mib_decode(&mibrsp, &mib_val); | |
5872 | ||
5873 | if (len == 0) { | |
5874 | kfree(mibrsp.data); | |
5875 | SLSI_ERR(sdev, "Mib decode error\n"); | |
5876 | return -EINVAL; | |
5877 | } | |
5878 | /* Add additional 1 sec delay */ | |
5879 | sdev->device_config.ap_disconnect_ind_timeout = ((mib_val.value.u.uintValue + 1) * 1000); | |
5880 | } else { | |
5881 | SLSI_ERR(sdev, "Mib read failed (error: %d)\n", r); | |
5882 | } | |
5883 | ||
5884 | kfree(mibrsp.data); | |
5885 | return r; | |
5886 | } | |
5887 | ||
5888 | /* Read unifiDefaultCountry MIB */ | |
5889 | int slsi_read_default_country(struct slsi_dev *sdev, u8 *alpha2, u16 index) | |
5890 | { | |
5891 | struct slsi_mib_data mibreq = { 0, NULL }; | |
5892 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
5893 | struct slsi_mib_entry mib_val; | |
5894 | int r = 0; | |
5895 | int rx_len = 0; | |
5896 | int len = 0; | |
5897 | ||
5898 | slsi_mib_encode_get(&mibreq, SLSI_PSID_UNIFI_DEFAULT_COUNTRY, index); | |
5899 | ||
5900 | mibrsp.dataLength = 11; /* PSID header(5) + index(1) + country code alpha2 3 bytes + status(1) */ | |
5901 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
5902 | ||
5903 | if (!mibrsp.data) { | |
5904 | SLSI_ERR(sdev, "Failed to alloc for Mib response\n"); | |
5905 | kfree(mibreq.data); | |
5906 | return -ENOMEM; | |
5907 | } | |
5908 | ||
5909 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, mibrsp.data, | |
5910 | mibrsp.dataLength, &rx_len); | |
5911 | ||
5912 | kfree(mibreq.data); | |
5913 | ||
5914 | if (r == 0) { | |
5915 | mibrsp.dataLength = rx_len; | |
5916 | len = slsi_mib_decode(&mibrsp, &mib_val); | |
5917 | ||
5918 | if (len == 0) { | |
5919 | kfree(mibrsp.data); | |
5920 | SLSI_ERR(sdev, "Mib decode error\n"); | |
5921 | return -EINVAL; | |
5922 | } | |
5923 | memcpy(alpha2, mib_val.value.u.octetValue.data, 2); | |
5924 | } else { | |
5925 | SLSI_ERR(sdev, "Mib read failed (error: %d)\n", r); | |
5926 | } | |
5927 | ||
5928 | kfree(mibrsp.data); | |
5929 | return r; | |
5930 | } | |
5931 | ||
5932 | int slsi_copy_country_table(struct slsi_dev *sdev, struct slsi_mib_data *mib, int len) | |
5933 | { | |
5934 | SLSI_DBG3(sdev, SLSI_MLME, "\n"); | |
5935 | ||
5936 | kfree(sdev->device_config.domain_info.countrylist); | |
5937 | sdev->device_config.domain_info.countrylist = kmalloc(len, GFP_KERNEL); | |
5938 | ||
5939 | if (!sdev->device_config.domain_info.countrylist) { | |
5940 | SLSI_ERR(sdev, "kmalloc failed\n"); | |
5941 | return -EINVAL; | |
5942 | } | |
5943 | ||
5944 | if (!mib || !mib->data) { | |
5945 | SLSI_ERR(sdev, "Invalid MIB country table\n"); | |
5946 | return -EINVAL; | |
5947 | } | |
5948 | ||
5949 | memcpy(sdev->device_config.domain_info.countrylist, mib->data, len); | |
5950 | sdev->device_config.domain_info.country_len = len; | |
5951 | ||
5952 | return 0; | |
5953 | } | |
5954 | ||
5955 | /* Read unifi country list */ | |
5956 | int slsi_read_unifi_countrylist(struct slsi_dev *sdev, u16 psid) | |
5957 | { | |
5958 | struct slsi_mib_data mibreq = { 0, NULL }; | |
5959 | struct slsi_mib_data mibrsp = { 0, NULL }; | |
5960 | struct slsi_mib_entry mib_val; | |
5961 | int r = 0; | |
5962 | int rx_len = 0; | |
5963 | int len = 0; | |
5964 | int ret; | |
5965 | ||
5966 | slsi_mib_encode_get(&mibreq, psid, 0); | |
5967 | ||
5968 | /* Fixed fields len (5) : 2 bytes(PSID) + 2 bytes (Len) + 1 byte (status) | |
5969 | * Data : 148 countries??? for SLSI_PSID_UNIFI_COUNTRY_LIST | |
5970 | */ | |
5971 | mibrsp.dataLength = 5 + (NUM_COUNTRY * 2); | |
5972 | mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL); | |
5973 | ||
5974 | if (!mibrsp.data) { | |
5975 | SLSI_ERR(sdev, "Failed to alloc for Mib response\n"); | |
5976 | kfree(mibreq.data); | |
5977 | return -ENOMEM; | |
5978 | } | |
5979 | ||
5980 | r = slsi_mlme_get(sdev, NULL, mibreq.data, mibreq.dataLength, mibrsp.data, | |
5981 | mibrsp.dataLength, &rx_len); | |
5982 | ||
5983 | kfree(mibreq.data); | |
5984 | ||
5985 | if (r == 0) { | |
5986 | mibrsp.dataLength = rx_len; | |
5987 | len = slsi_mib_decode(&mibrsp, &mib_val); | |
5988 | ||
5989 | if (len == 0) { | |
5990 | kfree(mibrsp.data); | |
5991 | return -EINVAL; | |
5992 | } | |
5993 | ret = slsi_copy_country_table(sdev, &mib_val.value.u.octetValue, len); | |
5994 | if (ret < 0) { | |
5995 | kfree(mibrsp.data); | |
5996 | return ret; | |
5997 | } | |
5998 | } else { | |
5999 | SLSI_ERR(sdev, "Mib read failed (error: %d)\n", r); | |
6000 | } | |
6001 | ||
6002 | kfree(mibrsp.data); | |
6003 | return r; | |
6004 | } | |
6005 | ||
6006 | void slsi_clear_offchannel_data(struct slsi_dev *sdev, bool acquire_lock) | |
6007 | { | |
6008 | struct net_device *dev = NULL; | |
6009 | struct netdev_vif *ndev_vif = NULL; | |
6010 | ||
6011 | dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2PX_SWLAN); | |
6012 | if (WARN_ON(!dev)) { | |
6013 | SLSI_ERR(sdev, "No Group net dev found\n"); | |
6014 | return; | |
6015 | } | |
6016 | ndev_vif = netdev_priv(dev); | |
6017 | ||
6018 | if (acquire_lock) | |
6019 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
6020 | ||
6021 | /* Reset dwell time should be sent on group vif */ | |
6022 | (void)slsi_mlme_reset_dwell_time(sdev, dev); | |
6023 | ||
6024 | if (acquire_lock) | |
6025 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
6026 | ||
6027 | sdev->p2p_group_exp_frame = SLSI_PA_INVALID; | |
6028 | } | |
6029 | ||
6030 | static void slsi_hs2_unsync_vif_delete_work(struct work_struct *work) | |
6031 | { | |
6032 | struct netdev_vif *ndev_vif = container_of((struct delayed_work *)work, struct netdev_vif, unsync.hs2_del_vif_work); | |
6033 | ||
6034 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
6035 | SLSI_NET_DBG1(ndev_vif->wdev.netdev, SLSI_CFG80211, "Delete HS vif duration expired - Deactivate unsync vif\n"); | |
6036 | slsi_wlan_unsync_vif_deactivate(ndev_vif->sdev, ndev_vif->wdev.netdev, true); | |
6037 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
6038 | } | |
6039 | ||
6040 | int slsi_wlan_unsync_vif_activate(struct slsi_dev *sdev, struct net_device *dev, | |
6041 | struct ieee80211_channel *chan, u16 wait) | |
6042 | { | |
6043 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
6044 | int r = 0; | |
6045 | u8 device_address[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | |
6046 | u32 action_frame_bmap; | |
6047 | ||
6048 | SLSI_DBG1(sdev, SLSI_INIT_DEINIT, "Activate wlan unsync vif\n"); | |
6049 | ||
6050 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
6051 | ||
6052 | ndev_vif->vif_type = FAPI_VIFTYPE_UNSYNCHRONISED; | |
6053 | ||
6054 | /* Avoid suspend when wlan unsync VIF is active */ | |
6055 | slsi_wake_lock(&sdev->wlan_wl); | |
6056 | ||
bd5e44ae MG |
6057 | if (ndev_vif->mgmt_tx_gas_frame) { |
6058 | if (slsi_mlme_add_vif(sdev, dev, ndev_vif->gas_frame_mac_addr, device_address) != 0) { | |
6059 | SLSI_NET_ERR(dev, "add vif failed for wlan unsync vif\n"); | |
6060 | goto exit_with_error; | |
6061 | } | |
6062 | } else { | |
6063 | if (slsi_mlme_add_vif(sdev, dev, dev->dev_addr, device_address) != 0) { | |
6064 | SLSI_NET_ERR(dev, "add vif failed for wlan unsync vif\n"); | |
6065 | goto exit_with_error; | |
6066 | } | |
cc6398c8 TK |
6067 | } |
6068 | ||
6069 | if (slsi_vif_activated(sdev, dev) != 0) { | |
6070 | SLSI_NET_ERR(dev, "vif activate failed for wlan unsync vif\n"); | |
6071 | slsi_mlme_del_vif(sdev, dev); | |
6072 | goto exit_with_error; | |
6073 | } | |
6074 | sdev->wlan_unsync_vif_state = WLAN_UNSYNC_VIF_ACTIVE; | |
6075 | INIT_DELAYED_WORK(&ndev_vif->unsync.hs2_del_vif_work, slsi_hs2_unsync_vif_delete_work); | |
6076 | action_frame_bmap = SLSI_ACTION_FRAME_PUBLIC | SLSI_ACTION_FRAME_RADIO_MEASUREMENT; | |
6077 | ||
6078 | r = slsi_mlme_register_action_frame(sdev, dev, action_frame_bmap, action_frame_bmap); | |
6079 | if (r != 0) { | |
6080 | SLSI_NET_ERR(dev, "slsi_mlme_register_action_frame failed: resultcode = %d, action_frame_bmap:%d\n", | |
6081 | r, action_frame_bmap); | |
6082 | goto exit_with_vif; | |
6083 | } | |
6084 | ||
6085 | if (slsi_mlme_set_channel(sdev, dev, chan, SLSI_FW_CHANNEL_DURATION_UNSPECIFIED, 0, 0) != 0) { | |
6086 | SLSI_NET_ERR(dev, "Set channel failed for wlan unsync vif\n"); | |
6087 | goto exit_with_vif; | |
6088 | } | |
6089 | ndev_vif->chan = chan; | |
6090 | ndev_vif->driver_channel = chan->hw_value; | |
6091 | return r; | |
6092 | ||
6093 | exit_with_vif: | |
6094 | slsi_wlan_unsync_vif_deactivate(sdev, dev, true); | |
6095 | exit_with_error: | |
6096 | slsi_wake_unlock(&sdev->wlan_wl); | |
6097 | return -EINVAL; | |
6098 | } | |
6099 | ||
6100 | /* Delete unsync vif - DON'T update the vif type */ | |
6101 | void slsi_wlan_unsync_vif_deactivate(struct slsi_dev *sdev, struct net_device *dev, bool hw_available) | |
6102 | { | |
6103 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
6104 | ||
6105 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "De-activate wlan unsync vif\n"); | |
6106 | ||
6107 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
6108 | ||
6109 | if (sdev->wlan_unsync_vif_state == WLAN_UNSYNC_NO_VIF) { | |
6110 | SLSI_NET_DBG1(dev, SLSI_INIT_DEINIT, "wlan unsync vif already deactivated\n"); | |
6111 | return; | |
6112 | } | |
6113 | ||
6114 | cancel_delayed_work(&ndev_vif->unsync.hs2_del_vif_work); | |
6115 | /*cancel any remain on channel and send roc expiry to cfg80211.*/ | |
6116 | if (delayed_work_pending(&ndev_vif->unsync.roc_expiry_work) && sdev->recovery_status) { | |
6117 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) | |
6118 | cfg80211_remain_on_channel_expired(&ndev_vif->wdev, ndev_vif->unsync.roc_cookie, ndev_vif->chan, | |
6119 | GFP_KERNEL); | |
6120 | #else | |
6121 | cfg80211_remain_on_channel_expired(ndev_vif->wdev.netdev, ndev_vif->unsync.roc_cookie, | |
6122 | ndev_vif->chan, ndev_vif->channel_type, GFP_KERNEL); | |
6123 | #endif | |
6124 | cancel_delayed_work(&ndev_vif->unsync.roc_expiry_work); | |
6125 | } | |
6126 | /* slsi_vif_deactivated is not used here after slsi_mlme_del_vif | |
6127 | * as it modifies vif type as well | |
6128 | */ | |
6129 | if (hw_available) | |
6130 | slsi_mlme_del_vif(sdev, dev); | |
6131 | ||
6132 | slsi_wake_unlock(&sdev->wlan_wl); | |
6133 | ||
6134 | sdev->wlan_unsync_vif_state = WLAN_UNSYNC_NO_VIF; | |
6135 | ndev_vif->activated = false; | |
6136 | ndev_vif->chan = NULL; | |
6137 | ||
6138 | (void)slsi_set_mgmt_tx_data(ndev_vif, 0, 0, NULL, 0); | |
6139 | } | |
6140 | ||
6141 | void slsi_scan_ind_timeout_handle(struct work_struct *work) | |
6142 | { | |
6143 | struct netdev_vif *ndev_vif = container_of((struct delayed_work *)work, struct netdev_vif, scan_timeout_work); | |
6144 | struct net_device *dev = slsi_get_netdev(ndev_vif->sdev, ndev_vif->ifnum); | |
6145 | ||
6146 | SLSI_MUTEX_LOCK(ndev_vif->vif_mutex); | |
6147 | SLSI_MUTEX_LOCK(ndev_vif->scan_mutex); | |
6148 | if (ndev_vif->scan[SLSI_SCAN_HW_ID].scan_req) { | |
6149 | if (ndev_vif->scan[SLSI_SCAN_HW_ID].requeue_timeout_work) { | |
6150 | queue_delayed_work(ndev_vif->sdev->device_wq, &ndev_vif->scan_timeout_work, | |
6151 | msecs_to_jiffies(SLSI_FW_SCAN_DONE_TIMEOUT_MSEC)); | |
6152 | ndev_vif->scan[SLSI_SCAN_HW_ID].requeue_timeout_work = false; | |
6153 | } else { | |
6154 | SLSI_WARN(ndev_vif->sdev, "Mlme_scan_done_ind not received\n"); | |
6155 | (void)slsi_mlme_del_scan(ndev_vif->sdev, dev, ndev_vif->ifnum << 8 | SLSI_SCAN_HW_ID, true); | |
6156 | slsi_scan_complete(ndev_vif->sdev, dev, SLSI_SCAN_HW_ID, false); | |
6157 | } | |
6158 | } | |
6159 | SLSI_MUTEX_UNLOCK(ndev_vif->scan_mutex); | |
6160 | SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex); | |
6161 | } | |
6162 | ||
6163 | void slsi_update_supported_channels_regd_flags(struct slsi_dev *sdev) | |
6164 | { | |
6165 | int i = 0; | |
6166 | struct wiphy *wiphy = sdev->wiphy; | |
6167 | struct ieee80211_channel *chan; | |
6168 | ||
6169 | /* If all channels are supported by chip no need disable any channel | |
6170 | * So return | |
6171 | */ | |
6172 | if (sdev->enabled_channel_count == 39) | |
6173 | return; | |
6174 | if (wiphy->bands[0]) { | |
6175 | for (i = 0; i < ARRAY_SIZE(sdev->supported_2g_channels); i++) { | |
6176 | if (sdev->supported_2g_channels[i] == 0) { | |
6177 | chan = &wiphy->bands[0]->channels[i]; | |
6178 | chan->flags |= IEEE80211_CHAN_DISABLED; | |
6179 | } | |
6180 | } | |
6181 | } | |
6182 | if (sdev->band_5g_supported && wiphy->bands[1]) { | |
6183 | for (i = 0; i < ARRAY_SIZE(sdev->supported_5g_channels); i++) { | |
6184 | if (sdev->supported_5g_channels[i] == 0) { | |
6185 | chan = &wiphy->bands[1]->channels[i]; | |
6186 | chan->flags |= IEEE80211_CHAN_DISABLED; | |
6187 | } | |
6188 | } | |
6189 | } | |
6190 | } | |
6191 | ||
6192 | int slsi_find_chan_idx(u16 chan, u8 hw_mode) | |
6193 | { | |
6194 | int idx = -1, i = 0; | |
6195 | u16 slsi_5ghz_channels_list[25] = {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, | |
6196 | 136, 140, 144, 149, 153, 157, 161, 165}; | |
6197 | ||
6198 | if (hw_mode == SLSI_ACS_MODE_IEEE80211B || hw_mode == SLSI_ACS_MODE_IEEE80211G) { | |
6199 | if (chan <= MAX_24G_CHANNELS) | |
6200 | idx = chan - 1; | |
6201 | } else if (hw_mode == SLSI_ACS_MODE_IEEE80211A) { | |
6202 | for (i = 0; i < MAX_5G_CHANNELS; i++) { | |
6203 | if (chan == slsi_5ghz_channels_list[i]) { | |
6204 | idx = i; | |
6205 | break; | |
6206 | } | |
6207 | } | |
6208 | } else { | |
6209 | if (chan <= MAX_24G_CHANNELS) { | |
6210 | idx = chan - 1; | |
6211 | } else { | |
6212 | for (i = 0; i < MAX_5G_CHANNELS; i++) { | |
6213 | if (chan == slsi_5ghz_channels_list[i]) { | |
6214 | idx = i + MAX_24G_CHANNELS; | |
6215 | break; | |
6216 | } | |
6217 | } | |
6218 | } | |
6219 | } | |
6220 | return idx; | |
6221 | } | |
6222 | ||
6223 | #ifdef CONFIG_SCSC_WLAN_SET_NUM_ANTENNAS | |
6224 | /* Note : netdev_vif lock should be taken care by caller. */ | |
6225 | int slsi_set_num_antennas(struct net_device *dev, const u16 num_of_antennas) | |
6226 | { | |
6227 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
6228 | struct slsi_dev *sdev = ndev_vif->sdev; | |
6229 | struct sk_buff *req; | |
6230 | struct sk_buff *cfm; | |
6231 | int ret = 0; | |
6232 | const bool is_sta = (ndev_vif->iftype == NL80211_IFTYPE_STATION); | |
6233 | const bool is_softap = (ndev_vif->iftype == NL80211_IFTYPE_AP); | |
6234 | ||
6235 | WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); | |
6236 | ||
6237 | if (num_of_antennas > 2 || num_of_antennas == 0) { | |
6238 | SLSI_NET_ERR(dev, "Invalid num_of_antennas %hu\n", num_of_antennas); | |
6239 | return -EINVAL; | |
6240 | } | |
6241 | if (!is_sta && !is_softap) { | |
6242 | SLSI_NET_ERR(dev, "Invalid interface type %s\n", dev->name); | |
6243 | return -EPERM; | |
6244 | } | |
6245 | if (is_sta && (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) { | |
6246 | SLSI_NET_ERR(dev, "sta is not in connected state\n"); | |
6247 | return -EPERM; | |
6248 | } | |
6249 | SLSI_NET_INFO(dev, "mlme_set_num_antennas_req(vif:%u num_of_antennas:%u)\n", ndev_vif->ifnum, num_of_antennas); | |
6250 | /* TODO: Change signal name to MLME_SET_NUM_ANTENNAS_REQ and MLME_SET_NUM_ANTENNAS_CFM. */ | |
6251 | req = fapi_alloc(mlme_set_num_antennas_req, MLME_SET_NUM_ANTENNAS_REQ, ndev_vif->ifnum, 0); | |
6252 | fapi_set_u16(req, u.mlme_set_num_antennas_req.vif, ndev_vif->ifnum); | |
6253 | fapi_set_u16(req, u.mlme_set_num_antennas_req.number_of_antennas, num_of_antennas); | |
6254 | cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_SET_NUM_ANTENNAS_CFM); | |
6255 | if (!cfm) | |
6256 | return -EIO; | |
6257 | ||
6258 | if (fapi_get_u16(cfm, u.mlme_set_num_antennas_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { | |
6259 | SLSI_NET_ERR(dev, "mlme_set_num_antennas_cfm(result:0x%04x) ERROR\n", | |
6260 | fapi_get_u16(cfm, u.mlme_set_num_antennas_cfm.result_code)); | |
6261 | ret = -EINVAL; | |
6262 | } | |
6263 | slsi_kfree_skb(cfm); | |
6264 | return ret; | |
6265 | } | |
6266 | #endif | |
6267 | ||
6268 | int slsi_set_latency_mode(struct net_device *dev, int latency_mode, int cmd_len) | |
6269 | { | |
6270 | struct netdev_vif *ndev_vif = netdev_priv(dev); | |
6271 | struct slsi_dev *sdev = ndev_vif->sdev; | |
6272 | int ret = 0; | |
6273 | u8 host_state; | |
6274 | ||
6275 | SLSI_DBG1(sdev, SLSI_CFG80211, "latency_mode = %d\n", latency_mode); | |
6276 | ||
6277 | SLSI_MUTEX_LOCK(sdev->device_config_mutex); | |
6278 | host_state = sdev->device_config.host_state; | |
6279 | ||
6280 | /* latency_mode =0 (Normal), latency_mode =1 (Low) */ | |
6281 | if (latency_mode) | |
6282 | host_state = host_state | SLSI_HOSTSTATE_LOW_LATENCY_ACTIVE; | |
6283 | else | |
6284 | host_state = host_state & ~SLSI_HOSTSTATE_LOW_LATENCY_ACTIVE; | |
6285 | ||
6286 | ret = slsi_mlme_set_host_state(sdev, dev, host_state); | |
6287 | if (ret != 0) | |
6288 | SLSI_NET_ERR(dev, "Error in setting the Host State, ret=%d", ret); | |
6289 | else | |
6290 | sdev->device_config.host_state = host_state; | |
6291 | ||
6292 | SLSI_MUTEX_UNLOCK(sdev->device_config_mutex); | |
6293 | ||
6294 | return ret; | |
6295 | } | |
6296 | ||
6297 | #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY | |
6298 | void slsi_wlan_recovery_init(struct slsi_dev *sdev) | |
6299 | { | |
6300 | int i; | |
6301 | struct netdev_vif *ndev_vif; | |
6302 | struct net_device *dev; | |
6303 | ||
6304 | slsi_mlme_set_country_for_recovery(sdev); | |
6305 | for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { | |
6306 | if (sdev->netdev[i]) { | |
6307 | dev = slsi_get_netdev(sdev, i); | |
6308 | ndev_vif = netdev_priv(dev); | |
6309 | if (ndev_vif->is_available) { | |
6310 | netif_tx_start_all_queues(dev); | |
6311 | if (ndev_vif->vif_type == FAPI_VIFTYPE_AP) { | |
6312 | slsi_start_ap(sdev->wiphy, sdev->netdev[i], &ndev_vif->backup_settings); | |
6313 | } | |
6314 | } | |
6315 | } | |
6316 | } | |
6317 | } | |
6318 | ||
6319 | void slsi_subsystem_reset(struct work_struct *work) | |
6320 | { | |
6321 | struct slsi_dev *sdev = container_of(work, struct slsi_dev, recovery_work); | |
6322 | int err = 0, i; | |
6323 | int level; | |
6324 | struct netdev_vif *ndev_vif; | |
6325 | #ifndef CONFIG_SCSC_DOWNLOAD_FILE | |
6326 | const struct firmware *fw[SLSI_WLAN_MAX_MIB_FILE] = { NULL, NULL }; | |
6327 | #endif | |
6328 | ||
6329 | level = atomic_read(&sdev->cm_if.reset_level); | |
6330 | SLSI_INFO_NODEV("Inside subsytem_reset\n"); | |
6331 | if (level < SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) { | |
6332 | err = slsi_sm_recovery_service_stop(sdev); | |
6333 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STOPPED; | |
6334 | sdev->device_state = SLSI_DEVICE_STATE_STOPPED; | |
6335 | slsi_hip_stop(sdev); | |
6336 | level = atomic_read(&sdev->cm_if.reset_level); | |
6337 | if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) | |
6338 | return; | |
6339 | err = slsi_sm_recovery_service_close(sdev); | |
6340 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_CLOSED; | |
6341 | level = atomic_read(&sdev->cm_if.reset_level); | |
6342 | if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC || sdev->netdev_up_count == 0) { | |
6343 | if (sdev->netdev_up_count == 0) | |
6344 | sdev->mlme_blocked = false; | |
6345 | return; | |
6346 | } | |
6347 | SLSI_MUTEX_LOCK(sdev->start_stop_mutex); | |
6348 | sdev->device_state = SLSI_DEVICE_STATE_STARTING; | |
6349 | err = slsi_sm_recovery_service_open(sdev); | |
6350 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_OPENED; | |
6351 | level = atomic_read(&sdev->cm_if.reset_level); | |
6352 | if (err != 0 || level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) { | |
6353 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6354 | return; | |
6355 | } | |
6356 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | |
6357 | reinit_completion(&sdev->sig_wait.completion); | |
6358 | #else | |
6359 | INIT_COMPLETION(sdev->sig_wait.completion); | |
6360 | #endif | |
6361 | ||
6362 | #ifndef CONFIG_SCSC_DOWNLOAD_FILE | |
6363 | /* The "_t" HCF is used in RF Test mode and wlanlite/production test mode */ | |
6364 | if (slsi_is_rf_test_mode_enabled() || slsi_is_test_mode_enabled()) { | |
6365 | sdev->mib[0].mib_file_name = mib_file_t; | |
6366 | sdev->mib[1].mib_file_name = mib_file2_t; | |
6367 | } else { | |
6368 | sdev->mib[0].mib_file_name = slsi_mib_file; | |
6369 | sdev->mib[1].mib_file_name = slsi_mib_file2; | |
6370 | } | |
c4a3b08a | 6371 | #ifdef CONFIG_SCSC_LOG_COLLECTION |
cc6398c8 | 6372 | sdev->collect_mib.num_files = 0; |
c4a3b08a | 6373 | #endif |
cc6398c8 TK |
6374 | /* Place MIB files in shared memory */ |
6375 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) { | |
6376 | err = slsi_mib_open_file(sdev, &sdev->mib[i], &fw[i]); | |
6377 | ||
6378 | /* Only the first file is mandatory */ | |
6379 | if (i == 0 && err) { | |
6380 | SLSI_ERR(sdev, "mib: Mandatory wlan hcf missing. WLAN will not start (err=%d)\n", err); | |
6381 | goto err_done; | |
6382 | } | |
6383 | } | |
6384 | err = slsi_sm_recovery_service_start(sdev); | |
6385 | if (err) { | |
6386 | SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); | |
6387 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) | |
6388 | slsi_mib_close_file(sdev, fw[i]); | |
6389 | goto err_done; | |
6390 | } | |
6391 | ||
6392 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) | |
6393 | slsi_mib_close_file(sdev, fw[i]); | |
6394 | #else | |
6395 | /* Download main MIB file via mlme_set */ | |
6396 | err = slsi_sm_recovery_service_start(sdev); | |
6397 | if (err) { | |
6398 | SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); | |
6399 | goto err_done; | |
6400 | } | |
6401 | SLSI_EC_GOTO(slsi_mib_download_file(sdev, &sdev->mib), err, err_hip_started); | |
6402 | #endif | |
6403 | level = atomic_read(&sdev->cm_if.reset_level); | |
6404 | if (level == SLSI_WIFI_CM_IF_SYSTEM_ERROR_PANIC) { | |
6405 | SLSI_INFO_NODEV("slsi_sm_recovery_service_start failed subsytem error level changed:%d\n", level); | |
6406 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6407 | return; | |
6408 | } | |
6409 | sdev->device_state = SLSI_DEVICE_STATE_STARTED; | |
6410 | sdev->mlme_blocked = false; | |
6411 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STARTED; | |
6412 | for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { | |
6413 | if (sdev->netdev[i]) { | |
6414 | ndev_vif = netdev_priv(sdev->netdev[i]); | |
6415 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) | |
6416 | reinit_completion(&ndev_vif->sig_wait.completion); | |
6417 | #else | |
6418 | INIT_COMPLETION(ndev_vif->sig_wait.completion); | |
6419 | #endif | |
6420 | } | |
6421 | } | |
6422 | ||
6423 | /*wlan system recovery actions*/ | |
6424 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6425 | slsi_wlan_recovery_init(sdev); | |
6426 | return; | |
6427 | } else { | |
6428 | return; | |
6429 | } | |
6430 | #ifdef CONFIG_SCSC_DOWNLOAD_FILE | |
6431 | err_hip_started: | |
6432 | slsi_sm_recovery_service_stop(sdev); | |
6433 | slsi_hip_stop(sdev); | |
6434 | slsi_sm_recovery_service_close(sdev); | |
6435 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6436 | return; | |
6437 | #endif | |
6438 | err_done: | |
6439 | slsi_sm_recovery_service_close(sdev); | |
6440 | sdev->device_state = SLSI_DEVICE_STATE_STOPPED; | |
6441 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6442 | return; | |
6443 | } | |
6444 | #endif | |
6445 | ||
6446 | void slsi_failure_reset(struct work_struct *work) | |
6447 | { | |
6448 | struct slsi_dev *sdev = container_of(work, struct slsi_dev, recovery_work_on_stop); | |
6449 | int r = 0; | |
6450 | ||
6451 | if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_STARTED) { | |
6452 | r = slsi_sm_recovery_service_stop(sdev); | |
6453 | sdev->device_state = SLSI_DEVICE_STATE_STOPPED; | |
6454 | slsi_hip_stop(sdev); | |
6455 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STOPPED; | |
6456 | } | |
6457 | if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_STOPPED) { | |
6458 | r = slsi_sm_recovery_service_close(sdev); | |
6459 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_CLOSED; | |
6460 | } | |
6461 | if (sdev->netdev_up_count == 0) { | |
6462 | sdev->mlme_blocked = false; | |
6463 | #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY | |
6464 | if (work_pending(&sdev->recovery_work_on_start)) { | |
6465 | SLSI_INFO(sdev, "Cancel work for chip recovery!!\n"); | |
6466 | cancel_work_sync(&sdev->recovery_work_on_start); | |
6467 | } | |
6468 | #endif | |
6469 | } | |
6470 | } | |
6471 | ||
6472 | #ifdef CONFIG_SCSC_WLAN_SILENT_RECOVERY | |
6473 | void slsi_chip_recovery(struct work_struct *work) | |
6474 | { | |
6475 | struct slsi_dev *sdev = container_of(work, struct slsi_dev, recovery_work_on_start); | |
6476 | int r = 0, err = 0, i; | |
6477 | struct netdev_vif *ndev_vif; | |
6478 | #ifndef CONFIG_SCSC_DOWNLOAD_FILE | |
6479 | const struct firmware *fw[SLSI_WLAN_MAX_MIB_FILE] = { NULL, NULL }; | |
6480 | #endif | |
6481 | ||
6482 | slsi_wake_lock(&sdev->wlan_wl); | |
6483 | SLSI_MUTEX_LOCK(sdev->start_stop_mutex); | |
6484 | if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_CLOSED && sdev->netdev_up_count > 0) { | |
6485 | if (sdev->recovery_status) { | |
6486 | r = wait_for_completion_timeout(&sdev->recovery_completed, | |
6487 | msecs_to_jiffies(sdev->recovery_timeout)); | |
6488 | if (r == 0) | |
6489 | SLSI_INFO(sdev, "recovery_completed timeout\n"); | |
6490 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | |
6491 | reinit_completion(&sdev->recovery_completed); | |
6492 | #else | |
6493 | INIT_COMPLETION(sdev->recovery_completed); | |
6494 | #endif | |
6495 | } | |
6496 | sdev->device_state = SLSI_DEVICE_STATE_STARTING; | |
6497 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | |
6498 | reinit_completion(&sdev->sig_wait.completion); | |
6499 | #else | |
6500 | INIT_COMPLETION(sdev->sig_wait.completion); | |
6501 | #endif | |
6502 | SLSI_EC_GOTO(slsi_sm_wlan_service_open(sdev), err, err_done); //separate function is not required. | |
6503 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_OPENED; | |
6504 | } else if (sdev->netdev_up_count == 0) { | |
6505 | sdev->mlme_blocked = false; | |
6506 | goto err_done; | |
6507 | } | |
6508 | if (sdev->cm_if.recovery_state == SLSI_RECOVERY_SERVICE_OPENED && sdev->netdev_up_count > 0) { | |
6509 | #ifndef CONFIG_SCSC_DOWNLOAD_FILE | |
6510 | /* The "_t" HCF is used in RF Test mode and wlanlite/production test mode */ | |
6511 | if (slsi_is_rf_test_mode_enabled() || slsi_is_test_mode_enabled()) { | |
6512 | sdev->mib[0].mib_file_name = mib_file_t; | |
6513 | sdev->mib[1].mib_file_name = mib_file2_t; | |
6514 | } else { | |
6515 | sdev->mib[0].mib_file_name = slsi_mib_file; | |
6516 | sdev->mib[1].mib_file_name = slsi_mib_file2; | |
6517 | } | |
c4a3b08a | 6518 | #ifdef CONFIG_SCSC_LOG_COLLECTION |
cc6398c8 | 6519 | sdev->collect_mib.num_files = 0; |
c4a3b08a | 6520 | #endif |
cc6398c8 TK |
6521 | /* Place MIB files in shared memory */ |
6522 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) { | |
6523 | err = slsi_mib_open_file(sdev, &sdev->mib[i], &fw[i]); | |
6524 | ||
6525 | /* Only the first file is mandatory */ | |
6526 | if (i == 0 && err) { | |
6527 | SLSI_ERR(sdev, "mib: Mandatory wlan hcf missing. WLAN will not start (err=%d)\n", err); | |
6528 | slsi_sm_recovery_service_close(sdev); | |
6529 | goto err_done; | |
6530 | } | |
6531 | } | |
6532 | err = slsi_sm_recovery_service_start(sdev); | |
6533 | if (err) { | |
6534 | SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); | |
6535 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) | |
6536 | slsi_mib_close_file(sdev, fw[i]); | |
6537 | slsi_sm_recovery_service_close(sdev); | |
6538 | goto err_done; | |
6539 | } | |
6540 | ||
6541 | for (i = 0; i < SLSI_WLAN_MAX_MIB_FILE; i++) | |
6542 | slsi_mib_close_file(sdev, fw[i]); | |
6543 | #else | |
6544 | /* Download main MIB file via mlme_set */ | |
6545 | err = slsi_sm_recovery_service_start(sdev); | |
6546 | if (err) { | |
6547 | SLSI_ERR(sdev, "slsi_sm_wlan_service_start failed: err=%d\n", err); | |
6548 | slsi_sm_recovery_service_close(sdev); | |
6549 | goto err_done; | |
6550 | } | |
6551 | SLSI_EC_GOTO(slsi_mib_download_file(sdev, &sdev->mib), err, err_hip_started); | |
6552 | #endif | |
6553 | sdev->device_state = SLSI_DEVICE_STATE_STARTED; | |
6554 | ||
6555 | /*wlan system recovery actions*/ | |
6556 | sdev->mlme_blocked = false; | |
6557 | sdev->cm_if.recovery_state = SLSI_RECOVERY_SERVICE_STARTED; | |
6558 | for (i = 1; i <= CONFIG_SCSC_WLAN_MAX_INTERFACES; i++) { | |
6559 | if (sdev->netdev[i]) { | |
6560 | ndev_vif = netdev_priv(sdev->netdev[i]); | |
6561 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) | |
6562 | reinit_completion(&ndev_vif->sig_wait.completion); | |
6563 | #else | |
6564 | INIT_COMPLETION(ndev_vif->sig_wait.completion); | |
6565 | #endif | |
6566 | } | |
6567 | } | |
6568 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6569 | slsi_wlan_recovery_init(sdev); | |
6570 | slsi_wake_unlock(&sdev->wlan_wl); | |
6571 | return; | |
6572 | } else { | |
6573 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6574 | slsi_wake_unlock(&sdev->wlan_wl); | |
6575 | return; | |
6576 | } | |
6577 | #ifdef CONFIG_SCSC_DOWNLOAD_FILE | |
6578 | err_hip_started: | |
6579 | slsi_sm_recovery_service_stop(sdev); | |
6580 | slsi_hip_stop(sdev); | |
6581 | slsi_sm_recovery_service_close(sdev); | |
6582 | slsi_wake_unlock(&sdev->wlan_wl); | |
6583 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6584 | return; | |
6585 | #endif | |
6586 | err_done: | |
6587 | sdev->device_state = SLSI_DEVICE_STATE_STOPPED; | |
6588 | SLSI_MUTEX_UNLOCK(sdev->start_stop_mutex); | |
6589 | slsi_wake_unlock(&sdev->wlan_wl); | |
6590 | } | |
6591 | #endif |