Commit | Line | Data |
---|---|---|
3c2a0909 S |
1 | /* |
2 | * Linux cfg80211 driver - Dongle Host Driver (DHD) related | |
3 | * | |
4c205efb | 4 | * Copyright (C) 1999-2018, Broadcom Corporation |
3c2a0909 S |
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 | * | |
4c205efb | 27 | * $Id: dhd_cfg80211.c 699163 2017-05-12 05:18:23Z $ |
3c2a0909 S |
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 | ||
65 | s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) | |
66 | { | |
67 | dhd_dongle_up = FALSE; | |
68 | return 0; | |
69 | } | |
70 | ||
71 | s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) | |
72 | { | |
73 | dhd_dongle_up = FALSE; | |
74 | return 0; | |
75 | } | |
76 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 (ndev) | |
165 | free_netdev(ndev); | |
166 | } | |
167 | ||
168 | static s32 | |
169 | wl_dongle_up(struct net_device *ndev) | |
170 | { | |
171 | s32 err = 0; | |
172 | u32 local_up = 0; | |
173 | ||
4c205efb | 174 | err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up)); |
3c2a0909 S |
175 | if (unlikely(err)) { |
176 | WL_ERR(("WLC_UP error (%d)\n", err)); | |
177 | } | |
178 | return err; | |
179 | } | |
180 | ||
181 | static s32 | |
182 | wl_dongle_down(struct net_device *ndev) | |
183 | { | |
184 | s32 err = 0; | |
185 | u32 local_down = 0; | |
186 | ||
4c205efb | 187 | err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down)); |
3c2a0909 S |
188 | if (unlikely(err)) { |
189 | WL_ERR(("WLC_DOWN error (%d)\n", err)); | |
190 | } | |
191 | return err; | |
192 | } | |
193 | ||
194 | ||
195 | s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) | |
196 | { | |
197 | #ifndef DHD_SDALIGN | |
198 | #define DHD_SDALIGN 32 | |
199 | #endif | |
200 | struct net_device *ndev; | |
201 | s32 err = 0; | |
202 | ||
203 | WL_TRACE(("In\n")); | |
204 | if (dhd_dongle_up) { | |
205 | WL_ERR(("Dongle is already up\n")); | |
206 | return err; | |
207 | } | |
208 | ||
209 | ndev = bcmcfg_to_prmry_ndev(cfg); | |
210 | ||
211 | err = wl_dongle_up(ndev); | |
212 | if (unlikely(err)) { | |
213 | WL_ERR(("wl_dongle_up failed\n")); | |
214 | goto default_conf_out; | |
215 | } | |
216 | dhd_dongle_up = true; | |
217 | ||
218 | default_conf_out: | |
219 | ||
220 | return err; | |
221 | ||
222 | } | |
223 | ||
224 | int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, | |
225 | const struct bcm_nlmsg_hdr *nlioc, void *buf) | |
226 | { | |
227 | struct net_device *ndev = NULL; | |
228 | dhd_pub_t *dhd; | |
229 | dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0}; | |
230 | int ret = 0; | |
231 | int8 index; | |
232 | ||
233 | WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); | |
234 | ||
235 | dhd = cfg->pub; | |
236 | DHD_OS_WAKE_LOCK(dhd); | |
237 | ||
238 | /* send to dongle only if we are not waiting for reload already */ | |
239 | if (dhd->hang_was_sent) { | |
240 | WL_ERR(("HANG was sent up earlier\n")); | |
241 | DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); | |
242 | DHD_OS_WAKE_UNLOCK(dhd); | |
243 | return OSL_ERROR(BCME_DONGLE_DOWN); | |
244 | } | |
245 | ||
246 | ndev = wdev_to_wlc_ndev(wdev, cfg); | |
247 | index = dhd_net2idx(dhd->info, ndev); | |
248 | if (index == DHD_BAD_IF) { | |
249 | WL_ERR(("Bad ifidx from wdev:%p\n", wdev)); | |
250 | ret = BCME_ERROR; | |
251 | goto done; | |
252 | } | |
253 | ||
254 | ioc.cmd = nlioc->cmd; | |
255 | ioc.len = nlioc->len; | |
256 | ioc.set = nlioc->set; | |
257 | ioc.driver = nlioc->magic; | |
258 | ioc.buf = buf; | |
259 | ret = dhd_ioctl_process(dhd, index, &ioc, buf); | |
260 | if (ret) { | |
261 | WL_TRACE(("dhd_ioctl_process return err %d\n", ret)); | |
262 | ret = OSL_ERROR(ret); | |
263 | goto done; | |
264 | } | |
265 | ||
266 | done: | |
267 | DHD_OS_WAKE_UNLOCK(dhd); | |
268 | return ret; | |
269 | } |