2 * Linux cfg80211 vendor command/event handlers of DHD
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_cfg_vendor.c 495605 2014-08-07 18:41:34Z $
9 #include <linux/vmalloc.h>
11 #include <net/cfg80211.h>
12 #include <net/netlink.h>
15 #include <wl_cfg80211.h>
16 #include <wl_cfgvendor.h>
17 #include <dngl_stats.h>
21 #include <brcm_nl80211.h>
23 #ifdef VENDOR_EXT_SUPPORT
24 static int dhd_cfgvendor_priv_string_handler(struct wiphy *wiphy,
25 struct wireless_dev *wdev, const void *data, int len)
27 const struct bcm_nlmsg_hdr *nlioc = data;
28 struct net_device *ndev = NULL;
29 struct bcm_cfg80211 *cfg;
30 struct sk_buff *reply;
31 void *buf = NULL, *cur;
33 dhd_ioctl_t ioc = { 0 };
34 int ret = 0, ret_len, payload, msglen;
35 int maxmsglen = PAGE_SIZE - 0x100;
38 WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
39 DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd));
41 cfg = wiphy_priv(wiphy);
44 DHD_OS_WAKE_LOCK(dhd);
46 /* send to dongle only if we are not waiting for reload already */
47 if (dhd->hang_was_sent) {
48 WL_ERR(("HANG was sent up earlier\n"));
49 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
50 DHD_OS_WAKE_UNLOCK(dhd);
51 return OSL_ERROR(BCME_DONGLE_DOWN);
54 len -= sizeof(struct bcm_nlmsg_hdr);
56 if (ret_len > 0 || len > 0) {
57 if (len > DHD_IOCTL_MAXLEN) {
58 WL_ERR(("oversize input buffer %d\n", len));
59 len = DHD_IOCTL_MAXLEN;
61 if (ret_len > DHD_IOCTL_MAXLEN) {
62 WL_ERR(("oversize return buffer %d\n", ret_len));
63 ret_len = DHD_IOCTL_MAXLEN;
65 payload = max(ret_len, len) + 1;
66 buf = vzalloc(payload);
68 DHD_OS_WAKE_UNLOCK(dhd);
71 memcpy(buf, (void *)nlioc + nlioc->offset, len);
72 *(char *)(buf + len) = '\0';
75 ndev = wdev_to_wlc_ndev(wdev, cfg);
76 index = dhd_net2idx(dhd->info, ndev);
77 if (index == DHD_BAD_IF) {
78 WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
86 ioc.driver = nlioc->magic;
87 ret = dhd_ioctl_process(dhd, index, &ioc, buf);
89 WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
96 msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
98 payload = msglen + sizeof(msglen);
99 reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
101 WL_ERR(("Failed to allocate reply msg\n"));
106 if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
107 nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
113 ret = cfg80211_vendor_cmd_reply(reply);
115 WL_ERR(("testmode reply failed:%d\n", ret));
123 DHD_OS_WAKE_UNLOCK(dhd);
127 const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = {
130 .vendor_id = OUI_BRCM,
131 .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
133 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
134 .doit = dhd_cfgvendor_priv_string_handler
138 int cfgvendor_attach(struct wiphy *wiphy)
140 wiphy->vendor_commands = dhd_cfgvendor_cmds;
141 wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds);
146 int cfgvendor_detach(struct wiphy *wiphy)
148 wiphy->vendor_commands = NULL;
149 wiphy->n_vendor_commands = 0;
153 #endif /* VENDOR_EXT_SUPPORT */