• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Linux cfg80211 driver - Dongle Host Driver (DHD) related
4  *
5  * Copyright (C) 1999-2019, Broadcom.
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  *
26  * <<Broadcom-WL-IPTag/Open:>>
27  *
28  * $Id: dhd_cfg80211.c 807961 2019-03-05 05:47:47Z $
29  */
30 
31 #include <linux/vmalloc.h>
32 #include <net/rtnetlink.h>
33 
34 #include <bcmutils.h>
35 #include <wldev_common.h>
36 #include <wl_cfg80211.h>
37 #include <dhd_cfg80211.h>
38 
39 #ifdef PKT_FILTER_SUPPORT
40 #include <dngl_stats.h>
41 #include <dhd.h>
42 #endif // endif
43 
44 #ifdef PKT_FILTER_SUPPORT
45 extern uint dhd_pkt_filter_enable;
46 extern uint dhd_master_mode;
47 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, 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
137 int32
wl_cfg80211_update_iflist_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,int ifidx,uint8 * addr,int bssidx,char * name,int if_state)138 wl_cfg80211_update_iflist_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
139 	int ifidx, uint8 *addr, int bssidx, char *name, int if_state)
140 {
141 	return dhd_update_iflist_info(cfg->pub, ndev, ifidx, addr, bssidx, name, if_state);
142 }
143 #endif /* WL_STATIC_IF */
144 
wl_cfg80211_allocate_if(struct bcm_cfg80211 * cfg,int ifidx,const char * name,uint8 * mac,uint8 bssidx,const char * dngl_name)145 struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, const char *name,
146 	uint8 *mac, uint8 bssidx, const char *dngl_name)
147 {
148 	return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name);
149 }
150 
wl_cfg80211_register_if(struct bcm_cfg80211 * cfg,int ifidx,struct net_device * ndev,bool rtnl_lock_reqd)151 int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg,
152 	int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
153 {
154 	return dhd_register_if(cfg->pub, ifidx, rtnl_lock_reqd);
155 }
156 
wl_cfg80211_remove_if(struct bcm_cfg80211 * cfg,int ifidx,struct net_device * ndev,bool rtnl_lock_reqd)157 int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg,
158 	int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
159 {
160 	return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd);
161 }
162 
wl_cfg80211_cleanup_if(struct net_device * net)163 void wl_cfg80211_cleanup_if(struct net_device *net)
164 {
165 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
166 	BCM_REFERENCE(cfg);
167 	dhd_cleanup_if(net);
168 }
169 
dhd_cfg80211_netdev_free(struct net_device * ndev)170 struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev)
171 {
172 	struct bcm_cfg80211 *cfg;
173 #ifdef CONFIG_AP6XXX_WIFI6_HDF
174 	struct NetDevice *hnetdev = NULL;
175 #endif
176 
177 	if (ndev) {
178 		cfg = wl_get_cfg(ndev);
179 		if (ndev->ieee80211_ptr) {
180 			MFREE(cfg->osh, ndev->ieee80211_ptr, sizeof(struct wireless_dev));
181 			ndev->ieee80211_ptr = NULL;
182 		}
183 
184 		WL_ERR(("call dhd_cfg80211_netdev_free %s\n", ndev->name));
185 #ifdef CONFIG_AP6XXX_WIFI6_HDF
186 		hnetdev = GetHdfNetDeviceByLinuxInf(ndev);
187 		if (hnetdev == NULL) {
188 			WL_ERR(("get NetDevice %s failed\n", ndev->name));
189 			return NULL;
190 		}
191 
192 		// clear private obj
193 		kfree(hnetdev->mlPriv);
194 		hnetdev->mlPriv = NULL;
195 
196 		// clear NetDevice object
197 		NetDeviceDeInit(hnetdev);
198 #else
199 		free_netdev(ndev);
200 #endif
201 		return NULL;
202 	}
203 
204 	return ndev;
205 }
206 
dhd_netdev_free(struct net_device * ndev)207 void dhd_netdev_free(struct net_device *ndev)
208 {
209 #ifdef WL_CFG80211
210 	ndev = dhd_cfg80211_netdev_free(ndev);
211 #endif // endif
212 	if (ndev) {
213 		free_netdev(ndev);
214 	}
215 }
216 
217 static s32
wl_dongle_up(struct net_device * ndev)218 wl_dongle_up(struct net_device *ndev)
219 {
220 	s32 err = 0;
221 	u32 local_up = 0;
222 
223 	err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up));
224 	if (unlikely(err)) {
225 		WL_ERR(("WLC_UP error (%d)\n", err));
226 	}
227 	return err;
228 }
229 
230 static s32
wl_dongle_down(struct net_device * ndev)231 wl_dongle_down(struct net_device *ndev)
232 {
233 	s32 err = 0;
234 	u32 local_down = 0;
235 
236 	err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down));
237 	if (unlikely(err)) {
238 		WL_ERR(("WLC_DOWN error (%d)\n", err));
239 	}
240 	return err;
241 }
242 
243 s32
wl_dongle_roam(struct net_device * ndev,u32 roamvar,u32 bcn_timeout)244 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
245 {
246 	s32 err = 0;
247 
248 	/* Setup timeout if Beacons are lost and roam is off to report link down */
249 	if (roamvar) {
250 		err = wldev_iovar_setint(ndev, "bcn_timeout", bcn_timeout);
251 		if (unlikely(err)) {
252 			WL_ERR(("bcn_timeout error (%d)\n", err));
253 			goto dongle_rom_out;
254 		}
255 	}
256 	/* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
257 	err = wldev_iovar_setint(ndev, "roam_off", roamvar);
258 	if (unlikely(err)) {
259 		WL_ERR(("roam_off error (%d)\n", err));
260 		goto dongle_rom_out;
261 	}
262 dongle_rom_out:
263 	return err;
264 }
265 
dhd_config_dongle(struct bcm_cfg80211 * cfg)266 s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
267 {
268 #ifndef DHD_SDALIGN
269 #define DHD_SDALIGN	32
270 #endif // endif
271 	struct net_device *ndev;
272 	s32 err = 0;
273 
274 	WL_TRACE(("In\n"));
275 	if (dhd_dongle_up) {
276 		WL_ERR(("Dongle is already up\n"));
277 		return err;
278 	}
279 
280 	ndev = bcmcfg_to_prmry_ndev(cfg);
281 
282 	err = wl_dongle_up(ndev);
283 	if (unlikely(err)) {
284 		WL_ERR(("wl_dongle_up failed\n"));
285 		goto default_conf_out;
286 	}
287 	dhd_dongle_up = true;
288 
289 default_conf_out:
290 
291 	return err;
292 
293 }
294 
dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const struct bcm_nlmsg_hdr * nlioc,void * buf)295 int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
296 	const struct bcm_nlmsg_hdr *nlioc, void *buf)
297 {
298 	struct net_device *ndev = NULL;
299 	dhd_pub_t *dhd;
300 	dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0};
301 	int ret = 0;
302 	int8 index;
303 
304 	WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
305 
306 	dhd = cfg->pub;
307 	DHD_OS_WAKE_LOCK(dhd);
308 
309 	ndev = wdev_to_wlc_ndev(wdev, cfg);
310 	index = dhd_net2idx(dhd->info, ndev);
311 	if (index == DHD_BAD_IF) {
312 		WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
313 		ret = BCME_ERROR;
314 		goto done;
315 	}
316 
317 	ioc.cmd = nlioc->cmd;
318 	ioc.len = nlioc->len;
319 	ioc.set = nlioc->set;
320 	ioc.driver = nlioc->magic;
321 	ioc.buf = buf;
322 	ret = dhd_ioctl_process(dhd, index, &ioc, buf);
323 	if (ret) {
324 		WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
325 		ret = OSL_ERROR(ret);
326 		goto done;
327 	}
328 
329 done:
330 	DHD_OS_WAKE_UNLOCK(dhd);
331 	return ret;
332 }
333