• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Linux cfg80211 driver - Dongle Host Driver (DHD) related
3  *
4  * Copyright (C) 1999-2017, Broadcom Corporation
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  *
25  * <<Broadcom-WL-IPTag/Open:>>
26  *
27  * $Id: dhd_cfg80211.c 699163 2017-05-12 05:18:23Z $
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
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, int master_mode);
47 #endif
48 
49 static int dhd_dongle_up = FALSE;
50 
51 #include <dngl_stats.h>
52 #include <dhd.h>
53 #include <dhdioctl.h>
54 #include <wlioctl.h>
55 #include <brcm_nl80211.h>
56 #include <dhd_cfg80211.h>
57 
58 static s32 wl_dongle_up(struct net_device *ndev);
59 static s32 wl_dongle_down(struct net_device *ndev);
60 
61 /**
62  * Function implementations
63  */
64 
dhd_cfg80211_init(struct bcm_cfg80211 * cfg)65 s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg)
66 {
67     dhd_dongle_up = FALSE;
68     return 0;
69 }
70 
dhd_cfg80211_deinit(struct bcm_cfg80211 * cfg)71 s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg)
72 {
73     dhd_dongle_up = FALSE;
74     return 0;
75 }
76 
dhd_cfg80211_down(struct bcm_cfg80211 * cfg)77 s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
78 {
79     struct net_device *ndev;
80     s32 err = 0;
81 
82     WL_TRACE(("In\n"));
83     if (!dhd_dongle_up) {
84         WL_ERR(("Dongle is already down\n"));
85         return err;
86     }
87 
88     ndev = bcmcfg_to_prmry_ndev(cfg);
89     wl_dongle_down(ndev);
90     dhd_dongle_up = FALSE;
91     return 0;
92 }
93 
dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 * cfg,int val)94 s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val)
95 {
96     dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
97     dhd->op_mode |= val;
98     WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
99 #ifdef ARP_OFFLOAD_SUPPORT
100     if (dhd->arp_version == 1) {
101         /* IF P2P is enabled, disable arpoe */
102         dhd_arp_offload_set(dhd, 0);
103         dhd_arp_offload_enable(dhd, false);
104     }
105 #endif /* ARP_OFFLOAD_SUPPORT */
106 
107     return 0;
108 }
109 
dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 * cfg)110 s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg)
111 {
112     dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
113     dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE);
114     WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
115 
116 #ifdef ARP_OFFLOAD_SUPPORT
117     if (dhd->arp_version == 1) {
118         /* IF P2P is disabled, enable arpoe back for STA mode. */
119         dhd_arp_offload_set(dhd, dhd_arp_mode);
120         dhd_arp_offload_enable(dhd, true);
121     }
122 #endif /* ARP_OFFLOAD_SUPPORT */
123 
124     return 0;
125 }
126 
wl_cfg80211_allocate_if(struct bcm_cfg80211 * cfg,int ifidx,const char * name,uint8 * mac,uint8 bssidx,const char * dngl_name)127 struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, const char *name,
128     uint8 *mac, uint8 bssidx, const char *dngl_name)
129 {
130     return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name);
131 }
132 
wl_cfg80211_register_if(struct bcm_cfg80211 * cfg,int ifidx,struct net_device * ndev,bool rtnl_lock_reqd)133 int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg,
134     int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
135 {
136     return dhd_register_if(cfg->pub, ifidx, rtnl_lock_reqd);
137 }
138 
wl_cfg80211_remove_if(struct bcm_cfg80211 * cfg,int ifidx,struct net_device * ndev,bool rtnl_lock_reqd)139 int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg,
140     int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
141 {
142     return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd);
143 }
144 
dhd_cfg80211_netdev_free(struct net_device * ndev)145 struct net_device *dhd_cfg80211_netdev_free(struct net_device *ndev)
146 {
147     if (ndev) {
148         if (ndev->ieee80211_ptr) {
149             kfree(ndev->ieee80211_ptr);
150             ndev->ieee80211_ptr = NULL;
151         }
152         free_netdev(ndev);
153         return NULL;
154     }
155 
156     return ndev;
157 }
158 
dhd_netdev_free(struct net_device * ndev)159 void dhd_netdev_free(struct net_device *ndev)
160 {
161 #ifdef WL_CFG80211
162     ndev = dhd_cfg80211_netdev_free(ndev);
163 #endif
164 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
165     if (ndev)
166         free_netdev(ndev);
167 #endif
168 }
169 
170 static s32
wl_dongle_up(struct net_device * ndev)171 wl_dongle_up(struct net_device *ndev)
172 {
173     s32 err = 0;
174     u32 local_up = 0;
175 
176     err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up));
177     if (unlikely(err)) {
178         WL_ERR(("WLC_UP error (%d)\n", err));
179     }
180     return err;
181 }
182 
183 static s32
wl_dongle_down(struct net_device * ndev)184 wl_dongle_down(struct net_device *ndev)
185 {
186     s32 err = 0;
187     u32 local_down = 0;
188 
189     err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down));
190     if (unlikely(err)) {
191         WL_ERR(("WLC_DOWN error (%d)\n", err));
192     }
193     return err;
194 }
195 
196 
dhd_config_dongle(struct bcm_cfg80211 * cfg)197 s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
198 {
199 #ifndef DHD_SDALIGN
200 #define DHD_SDALIGN    32
201 #endif
202     struct net_device *ndev;
203     s32 err = 0;
204 
205     WL_TRACE(("In\n"));
206     if (dhd_dongle_up) {
207         WL_ERR(("Dongle is already up\n"));
208         return err;
209     }
210 
211     ndev = bcmcfg_to_prmry_ndev(cfg);
212 
213     err = wl_dongle_up(ndev);
214     if (unlikely(err)) {
215         WL_ERR(("wl_dongle_up failed\n"));
216         goto default_conf_out;
217     }
218     dhd_dongle_up = true;
219 
220 default_conf_out:
221 
222     return err;
223 }
224 
dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const struct bcm_nlmsg_hdr * nlioc,void * buf)225 int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
226     const struct bcm_nlmsg_hdr *nlioc, void *buf)
227 {
228     struct net_device *ndev = NULL;
229     dhd_pub_t *dhd;
230     dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0};
231     int ret = 0;
232     int8 index;
233 
234     WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
235 
236     dhd = cfg->pub;
237     DHD_OS_WAKE_LOCK(dhd);
238 
239     /* send to dongle only if we are not waiting for reload already */
240     if (dhd->hang_was_sent) {
241         WL_ERR(("HANG was sent up earlier\n"));
242         DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
243         DHD_OS_WAKE_UNLOCK(dhd);
244         return OSL_ERROR(BCME_DONGLE_DOWN);
245     }
246 
247     ndev = wdev_to_wlc_ndev(wdev, cfg);
248     index = dhd_net2idx(dhd->info, ndev);
249     if (index == DHD_BAD_IF) {
250         WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
251         ret = BCME_ERROR;
252         goto done;
253     }
254 
255     ioc.cmd = nlioc->cmd;
256     ioc.len = nlioc->len;
257     ioc.set = nlioc->set;
258     ioc.driver = nlioc->magic;
259     ioc.buf = buf;
260     ret = dhd_ioctl_process(dhd, index, &ioc, buf);
261     if (ret) {
262         WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
263         ret = OSL_ERROR(ret);
264         goto done;
265     }
266 
267 done:
268     DHD_OS_WAKE_UNLOCK(dhd);
269     return ret;
270 }
271