net: wifi: rockchip: update broadcom drivers for kernel4.4
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / dhd_cfg80211.c
1 /*
2  * Linux cfg80211 driver - Dongle Host Driver (DHD) related
3  *
4  * Copyright (C) 1999-2016, 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 591285 2015-10-07 11:56:29Z $
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 extern struct bcm_cfg80211 *g_bcm_cfg;
44
45 #ifdef PKT_FILTER_SUPPORT
46 extern uint dhd_pkt_filter_enable;
47 extern uint dhd_master_mode;
48 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
49 #endif
50
51 static int dhd_dongle_up = FALSE;
52
53 #include <dngl_stats.h>
54 #include <dhd.h>
55 #include <dhdioctl.h>
56 #include <wlioctl.h>
57 #include <brcm_nl80211.h>
58 #include <dhd_cfg80211.h>
59
60 static s32 wl_dongle_up(struct net_device *ndev);
61 static s32 wl_dongle_down(struct net_device *ndev);
62
63 /**
64  * Function implementations
65  */
66
67 s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg)
68 {
69         dhd_dongle_up = FALSE;
70         return 0;
71 }
72
73 s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg)
74 {
75         dhd_dongle_up = FALSE;
76         return 0;
77 }
78
79 s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
80 {
81         struct net_device *ndev;
82         s32 err = 0;
83
84         WL_TRACE(("In\n"));
85         if (!dhd_dongle_up) {
86                 WL_ERR(("Dongle is already down\n"));
87                 return err;
88         }
89
90         ndev = bcmcfg_to_prmry_ndev(cfg);
91         wl_dongle_down(ndev);
92         dhd_dongle_up = FALSE;
93         return 0;
94 }
95
96 s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val)
97 {
98         dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
99         dhd->op_mode |= val;
100         WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
101 #ifdef ARP_OFFLOAD_SUPPORT
102         if (dhd->arp_version == 1) {
103                 /* IF P2P is enabled, disable arpoe */
104                 dhd_arp_offload_set(dhd, 0);
105                 dhd_arp_offload_enable(dhd, false);
106         }
107 #endif /* ARP_OFFLOAD_SUPPORT */
108
109         return 0;
110 }
111
112 s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg)
113 {
114         dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
115         dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE);
116         WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
117
118 #ifdef ARP_OFFLOAD_SUPPORT
119         if (dhd->arp_version == 1) {
120                 /* IF P2P is disabled, enable arpoe back for STA mode. */
121                 dhd_arp_offload_set(dhd, dhd_arp_mode);
122                 dhd_arp_offload_enable(dhd, true);
123         }
124 #endif /* ARP_OFFLOAD_SUPPORT */
125
126         return 0;
127 }
128
129 struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name,
130         uint8 *mac, uint8 bssidx, char *dngl_name)
131 {
132         return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name);
133 }
134
135 int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev)
136 {
137         return dhd_register_if(cfg->pub, ifidx, FALSE);
138 }
139
140 int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev)
141 {
142         return dhd_remove_if(cfg->pub, ifidx, FALSE);
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 up = 0;
173
174         err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
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 down = 0;
186
187         err = wldev_ioctl(ndev, WLC_DOWN, &down, sizeof(down), true);
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 };
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         ret = dhd_ioctl_process(dhd, index, &ioc, buf);
259         if (ret) {
260                 WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
261                 ret = OSL_ERROR(ret);
262                 goto done;
263         }
264
265 done:
266         DHD_OS_WAKE_UNLOCK(dhd);
267         return ret;
268 }