2 * Linux cfg80211 vendor command/event handlers of DHD
4 * Copyright (C) 1999-2016, Broadcom Corporation
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: dhd_cfg_vendor.c 525516 2015-01-09 23:12:53Z $
30 #include <linux/vmalloc.h>
32 #include <net/cfg80211.h>
33 #include <net/netlink.h>
36 #include <wl_cfg80211.h>
37 #include <wl_cfgvendor.h>
38 #include <dngl_stats.h>
42 #include <brcm_nl80211.h>
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)
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;
54 dhd_ioctl_t ioc = { 0 };
55 int ret = 0, ret_len, payload, msglen;
56 int maxmsglen = PAGE_SIZE - 0x100;
59 WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
60 DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd));
62 cfg = wiphy_priv(wiphy);
65 DHD_OS_WAKE_LOCK(dhd);
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);
75 len -= sizeof(struct bcm_nlmsg_hdr);
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;
82 if (ret_len > DHD_IOCTL_MAXLEN) {
83 WL_ERR(("oversize return buffer %d\n", ret_len));
84 ret_len = DHD_IOCTL_MAXLEN;
86 payload = max(ret_len, len) + 1;
87 buf = vzalloc(payload);
89 DHD_OS_WAKE_UNLOCK(dhd);
92 memcpy(buf, (void *)nlioc + nlioc->offset, len);
93 *(char *)(buf + len) = '\0';
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));
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);
110 WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
111 ret = OSL_ERROR(ret);
116 while (ret_len > 0) {
117 msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
119 payload = msglen + sizeof(msglen);
120 reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
122 WL_ERR(("Failed to allocate reply msg\n"));
127 if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
128 nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
134 ret = cfg80211_vendor_cmd_reply(reply);
136 WL_ERR(("testmode reply failed:%d\n", ret));
144 DHD_OS_WAKE_UNLOCK(dhd);
148 const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = {
151 .vendor_id = OUI_BRCM,
152 .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
154 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
155 .doit = dhd_cfgvendor_priv_string_handler
159 int cfgvendor_attach(struct wiphy *wiphy)
161 wiphy->vendor_commands = dhd_cfgvendor_cmds;
162 wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds);
167 int cfgvendor_detach(struct wiphy *wiphy)
169 wiphy->vendor_commands = NULL;
170 wiphy->n_vendor_commands = 0;
174 #endif /* VENDOR_EXT_SUPPORT */