ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / dhd_cfg_vendor.c
1 /*
2  * Linux cfg80211 vendor command/event handlers of DHD
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_cfg_vendor.c 525516 2015-01-09 23:12:53Z $
28  */
29
30 #include <linux/vmalloc.h>
31 #include <linuxver.h>
32 #include <net/cfg80211.h>
33 #include <net/netlink.h>
34
35 #include <bcmutils.h>
36 #include <wl_cfg80211.h>
37 #include <wl_cfgvendor.h>
38 #include <dngl_stats.h>
39 #include <dhd.h>
40 #include <dhd_dbg.h>
41 #include <dhdioctl.h>
42 #include <brcm_nl80211.h>
43
44 #ifdef VENDOR_EXT_SUPPORT
45 static int dhd_cfgvendor_priv_string_handler(struct wiphy *wiphy,
46         struct wireless_dev *wdev, const void  *data, int len)
47 {
48         const struct bcm_nlmsg_hdr *nlioc = data;
49         struct net_device *ndev = NULL;
50         struct bcm_cfg80211 *cfg;
51         struct sk_buff *reply;
52         void *buf = NULL, *cur;
53         dhd_pub_t *dhd;
54         dhd_ioctl_t ioc = { 0 };
55         int ret = 0, ret_len, payload, msglen;
56         int maxmsglen = PAGE_SIZE - 0x100;
57         int8 index;
58
59         WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
60         DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd));
61
62         cfg = wiphy_priv(wiphy);
63         dhd = cfg->pub;
64
65         DHD_OS_WAKE_LOCK(dhd);
66
67         /* send to dongle only if we are not waiting for reload already */
68         if (dhd->hang_was_sent) {
69                 WL_ERR(("HANG was sent up earlier\n"));
70                 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
71                 DHD_OS_WAKE_UNLOCK(dhd);
72                 return OSL_ERROR(BCME_DONGLE_DOWN);
73         }
74
75         len -= sizeof(struct bcm_nlmsg_hdr);
76         ret_len = nlioc->len;
77         if (ret_len > 0 || len > 0) {
78                 if (len > DHD_IOCTL_MAXLEN) {
79                         WL_ERR(("oversize input buffer %d\n", len));
80                         len = DHD_IOCTL_MAXLEN;
81                 }
82                 if (ret_len > DHD_IOCTL_MAXLEN) {
83                         WL_ERR(("oversize return buffer %d\n", ret_len));
84                         ret_len = DHD_IOCTL_MAXLEN;
85                 }
86                 payload = max(ret_len, len) + 1;
87                 buf = vzalloc(payload);
88                 if (!buf) {
89                         DHD_OS_WAKE_UNLOCK(dhd);
90                         return -ENOMEM;
91                 }
92                 memcpy(buf, (void *)nlioc + nlioc->offset, len);
93                 *(char *)(buf + len) = '\0';
94         }
95
96         ndev = wdev_to_wlc_ndev(wdev, cfg);
97         index = dhd_net2idx(dhd->info, ndev);
98         if (index == DHD_BAD_IF) {
99                 WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
100                 ret = BCME_ERROR;
101                 goto done;
102         }
103
104         ioc.cmd = nlioc->cmd;
105         ioc.len = nlioc->len;
106         ioc.set = nlioc->set;
107         ioc.driver = nlioc->magic;
108         ret = dhd_ioctl_process(dhd, index, &ioc, buf);
109         if (ret) {
110                 WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
111                 ret = OSL_ERROR(ret);
112                 goto done;
113         }
114
115         cur = buf;
116         while (ret_len > 0) {
117                 msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
118                 ret_len -= msglen;
119                 payload = msglen + sizeof(msglen);
120                 reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
121                 if (!reply) {
122                         WL_ERR(("Failed to allocate reply msg\n"));
123                         ret = -ENOMEM;
124                         break;
125                 }
126
127                 if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
128                         nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
129                         kfree_skb(reply);
130                         ret = -ENOBUFS;
131                         break;
132                 }
133
134                 ret = cfg80211_vendor_cmd_reply(reply);
135                 if (ret) {
136                         WL_ERR(("testmode reply failed:%d\n", ret));
137                         break;
138                 }
139                 cur += msglen;
140         }
141
142 done:
143         vfree(buf);
144         DHD_OS_WAKE_UNLOCK(dhd);
145         return ret;
146 }
147
148 const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = {
149         {
150                 {
151                         .vendor_id = OUI_BRCM,
152                         .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
153                 },
154                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
155                 .doit = dhd_cfgvendor_priv_string_handler
156         },
157 };
158
159 int cfgvendor_attach(struct wiphy *wiphy)
160 {
161         wiphy->vendor_commands  = dhd_cfgvendor_cmds;
162         wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds);
163
164         return 0;
165 }
166
167 int cfgvendor_detach(struct wiphy *wiphy)
168 {
169         wiphy->vendor_commands  = NULL;
170         wiphy->n_vendor_commands = 0;
171
172         return 0;
173 }
174 #endif /* VENDOR_EXT_SUPPORT */