bcmdhd_1_77: Import A320F (A320FLXXU2CRE3) Oreo driver
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / drivers / net / wireless / bcmdhd_1_77 / dhd_cfg80211.c
CommitLineData
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
44extern uint dhd_pkt_filter_enable;
45extern uint dhd_master_mode;
46extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
47#endif
48
49static 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
58static s32 wl_dongle_up(struct net_device *ndev);
59static s32 wl_dongle_down(struct net_device *ndev);
60
61/**
62 * Function implementations
63 */
64
65s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg)
66{
67 dhd_dongle_up = FALSE;
68 return 0;
69}
70
71s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg)
72{
73 dhd_dongle_up = FALSE;
74 return 0;
75}
76
77s32 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
94s32 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
110s32 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
127struct 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
133int 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
139int 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
145struct 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
159void 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
168static s32
169wl_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
181static s32
182wl_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
195s32 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
218default_conf_out:
219
220 return err;
221
222}
223
224int 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
266done:
267 DHD_OS_WAKE_UNLOCK(dhd);
268 return ret;
269}