• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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