1 /*
2 * Linux cfg80211 driver - Dongle Host Driver (DHD) related
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions
16 * of the license of that module. An independent module is a module which is
17 * not derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: dhd_cfg80211.c 807961 2019-03-05 05:47:47Z $
28 */
29
30 #include <linux/vmalloc.h>
31 #include <net/rtnetlink.h>
32
33 #include <bcmutils.h>
34 #include <wldev_common.h>
35 #include <wl_cfg80211.h>
36 #include <dhd_cfg80211.h>
37
38 #ifdef PKT_FILTER_SUPPORT
39 #include <dngl_stats.h>
40 #include <dhd.h>
41 #endif // endif
42
43 #ifdef PKT_FILTER_SUPPORT
44 extern uint dhd_pkt_filter_enable;
45 extern uint dhd_master_mode;
46 extern void dhd_pktfilter_offload_enable(dhd_pub_t *dhd, char *arg, int enable,
47 int master_mode);
48 #endif // endif
49
50 static int dhd_dongle_up = FALSE;
51
52 #include <dngl_stats.h>
53 #include <dhd.h>
54 #include <dhdioctl.h>
55 #include <wlioctl.h>
56 #include <brcm_nl80211.h>
57 #include <dhd_cfg80211.h>
58
59 #ifdef CONFIG_AP6XXX_WIFI6_HDF
60 #include "net_device.h"
61 struct NetDevice *GetHdfNetDeviceByLinuxInf(struct net_device *dev);
62
63 #endif
64
65 static s32 wl_dongle_up(struct net_device *ndev);
66 static s32 wl_dongle_down(struct net_device *ndev);
67
68 /**
69 * Function implementations
70 */
71
dhd_cfg80211_init(struct bcm_cfg80211 * cfg)72 s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg)
73 {
74 dhd_dongle_up = FALSE;
75 return 0;
76 }
77
dhd_cfg80211_deinit(struct bcm_cfg80211 * cfg)78 s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg)
79 {
80 dhd_dongle_up = FALSE;
81 return 0;
82 }
83
dhd_cfg80211_down(struct bcm_cfg80211 * cfg)84 s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
85 {
86 struct net_device *ndev;
87 s32 err = 0;
88 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
89
90 WL_TRACE(("In\n"));
91 if ((!dhd_dongle_up) || (!dhd->up)) {
92 WL_INFORM_MEM(("Dongle is already down\n"));
93 err = 0;
94 goto done;
95 }
96 ndev = bcmcfg_to_prmry_ndev(cfg);
97 wl_dongle_down(ndev);
98 done:
99 dhd_dongle_up = FALSE;
100 return err;
101 }
102
dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 * cfg,int val)103 s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val)
104 {
105 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
106 dhd->op_mode |= val;
107 WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
108 #ifdef ARP_OFFLOAD_SUPPORT
109 if (dhd->arp_version == 1) {
110 /* IF P2P is enabled, disable arpoe */
111 dhd_arp_offload_set(dhd, 0);
112 dhd_arp_offload_enable(dhd, false);
113 }
114 #endif /* ARP_OFFLOAD_SUPPORT */
115
116 return 0;
117 }
118
dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 * cfg)119 s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg)
120 {
121 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
122 dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE);
123 WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
124
125 #ifdef ARP_OFFLOAD_SUPPORT
126 if (dhd->arp_version == 1) {
127 /* IF P2P is disabled, enable arpoe back for STA mode. */
128 dhd_arp_offload_set(dhd, dhd_arp_mode);
129 dhd_arp_offload_enable(dhd, true);
130 }
131 #endif /* ARP_OFFLOAD_SUPPORT */
132
133 return 0;
134 }
135
136 #ifdef WL_STATIC_IF
wl_cfg80211_update_iflist_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,int ifidx,uint8 * addr,int bssidx,char * name,int if_state)137 int32 wl_cfg80211_update_iflist_info(struct bcm_cfg80211 *cfg,
138 struct net_device *ndev, int ifidx,
139 uint8 *addr, int bssidx, char *name,
140 int if_state)
141 {
142 return dhd_update_iflist_info(cfg->pub, ndev, ifidx, addr, bssidx, name,
143 if_state);
144 }
145 #endif /* WL_STATIC_IF */
146
wl_cfg80211_allocate_if(struct bcm_cfg80211 * cfg,int ifidx,const char * name,uint8 * mac,uint8 bssidx,const char * dngl_name)147 struct net_device *wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx,
148 const char *name, uint8 *mac,
149 uint8 bssidx, const char *dngl_name)
150 {
151 return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE,
152 dngl_name);
153 }
154
wl_cfg80211_register_if(struct bcm_cfg80211 * cfg,int ifidx,struct net_device * ndev,bool rtnl_lock_reqd)155 int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx,
156 struct net_device *ndev, bool rtnl_lock_reqd)
157 {
158 return dhd_register_if(cfg->pub, ifidx, rtnl_lock_reqd);
159 }
160
wl_cfg80211_remove_if(struct bcm_cfg80211 * cfg,int ifidx,struct net_device * ndev,bool rtnl_lock_reqd)161 int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx,
162 struct net_device *ndev, bool rtnl_lock_reqd)
163 {
164 WL_ERR(("lijg123: call wl_cfg80211_remove_if ifidx=%d rtnl_lock_reqd=%d\n",
165 ifidx, rtnl_lock_reqd));
166 return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd);
167 }
168
wl_cfg80211_cleanup_if(struct net_device * net)169 void wl_cfg80211_cleanup_if(struct net_device *net)
170 {
171 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
172 BCM_REFERENCE(cfg);
173 dhd_cleanup_if(net);
174 }
175
dhd_cfg80211_netdev_free(struct net_device * ndev)176 struct net_device *dhd_cfg80211_netdev_free(struct net_device *ndev)
177 {
178 struct bcm_cfg80211 *cfg;
179 #ifdef CONFIG_AP6XXX_WIFI6_HDF
180 struct NetDevice *hnetdev = NULL;
181 #endif
182
183 if (ndev) {
184 cfg = wl_get_cfg(ndev);
185 if (ndev->ieee80211_ptr) {
186 MFREE(cfg->osh, ndev->ieee80211_ptr, sizeof(struct wireless_dev));
187 ndev->ieee80211_ptr = NULL;
188 }
189
190 WL_ERR(("call dhd_cfg80211_netdev_free %s\n", ndev->name));
191 #ifdef CONFIG_AP6XXX_WIFI6_HDF
192 hnetdev = GetHdfNetDeviceByLinuxInf(ndev);
193 if (hnetdev == NULL) {
194 WL_ERR(("get NetDevice %s failed\n", ndev->name));
195 return NULL;
196 }
197
198 // clear private obj
199 kfree(hnetdev->mlPriv);
200 hnetdev->mlPriv = NULL;
201
202 // clear NetDevice object
203 NetDeviceDeInit(hnetdev);
204 #else
205 free_netdev(ndev);
206 #endif
207 return NULL;
208 }
209
210 return ndev;
211 }
212
dhd_netdev_free(struct net_device * ndev)213 void dhd_netdev_free(struct net_device *ndev)
214 {
215 #ifdef WL_CFG80211
216 WL_ERR(("lijg123 call dhd_netdev_free 01 run this %s\n", ndev->name));
217 ndev = dhd_cfg80211_netdev_free(ndev);
218 #endif // endif
219 if (ndev) {
220 WL_ERR(("lijg123 call dhd_netdev_free 02 %s\n", ndev->name));
221 free_netdev(ndev);
222 }
223 }
224
wl_dongle_up(struct net_device * ndev)225 static s32 wl_dongle_up(struct net_device *ndev)
226 {
227 s32 err = 0;
228 u32 local_up = 0;
229
230 err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up));
231 if (unlikely(err)) {
232 WL_ERR(("WLC_UP error (%d)\n", err));
233 }
234 return err;
235 }
236
wl_dongle_down(struct net_device * ndev)237 static s32 wl_dongle_down(struct net_device *ndev)
238 {
239 s32 err = 0;
240 u32 local_down = 0;
241
242 err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down));
243 if (unlikely(err)) {
244 WL_ERR(("WLC_DOWN error (%d)\n", err));
245 }
246 return err;
247 }
248
wl_dongle_roam(struct net_device * ndev,u32 roamvar,u32 bcn_timeout)249 s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
250 {
251 s32 err = 0;
252
253 /* Setup timeout if Beacons are lost and roam is off to report link down */
254 if (roamvar) {
255 err = wldev_iovar_setint(ndev, "bcn_timeout", bcn_timeout);
256 if (unlikely(err)) {
257 WL_ERR(("bcn_timeout error (%d)\n", err));
258 goto dongle_rom_out;
259 }
260 }
261 /* Enable/Disable built-in roaming to allow supplicant to take care of
262 * roaming */
263 err = wldev_iovar_setint(ndev, "roam_off", roamvar);
264 if (unlikely(err)) {
265 WL_ERR(("roam_off error (%d)\n", err));
266 goto dongle_rom_out;
267 }
268 dongle_rom_out:
269 return err;
270 }
271
dhd_config_dongle(struct bcm_cfg80211 * cfg)272 s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
273 {
274 #ifndef DHD_SDALIGN
275 #define DHD_SDALIGN 32
276 #endif // endif
277 struct net_device *ndev;
278 s32 err = 0;
279
280 WL_TRACE(("In\n"));
281 if (dhd_dongle_up) {
282 WL_ERR(("Dongle is already up\n"));
283 return err;
284 }
285
286 ndev = bcmcfg_to_prmry_ndev(cfg);
287
288 err = wl_dongle_up(ndev);
289 if (unlikely(err)) {
290 WL_ERR(("wl_dongle_up failed\n"));
291 goto default_conf_out;
292 }
293 dhd_dongle_up = true;
294
295 default_conf_out:
296
297 return err;
298 }
299
dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const struct bcm_nlmsg_hdr * nlioc,void * buf)300 int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg,
301 struct wireless_dev *wdev,
302 const struct bcm_nlmsg_hdr *nlioc,
303 void *buf)
304 {
305 struct net_device *ndev = NULL;
306 dhd_pub_t *dhd;
307 dhd_ioctl_t ioc = {0, NULL, 0, 0, 0, 0, 0};
308 int ret = 0;
309 int8 index;
310
311 WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
312
313 dhd = cfg->pub;
314 DHD_OS_WAKE_LOCK(dhd);
315
316 ndev = wdev_to_wlc_ndev(wdev, cfg);
317 index = dhd_net2idx(dhd->info, ndev);
318 if (index == DHD_BAD_IF) {
319 WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
320 ret = BCME_ERROR;
321 goto done;
322 }
323
324 ioc.cmd = nlioc->cmd;
325 ioc.len = nlioc->len;
326 ioc.set = nlioc->set;
327 ioc.driver = nlioc->magic;
328 ioc.buf = buf;
329 ret = dhd_ioctl_process(dhd, index, &ioc, buf);
330 if (ret) {
331 WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
332 ret = OSL_ERROR(ret);
333 goto done;
334 }
335
336 done:
337 DHD_OS_WAKE_UNLOCK(dhd);
338 return ret;
339 }
340