blob: c9087981cfa49f4d0e276d9318cdcc627e827ca1 [file] [log] [blame]
/*
* Linux cfg80211 vendor command/event handlers of DHD
*
* Copyright (C) 1999-2016, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cfg_vendor.c 525516 2015-01-09 23:12:53Z $
*/
#include <linux/vmalloc.h>
#include <linuxver.h>
#include <net/cfg80211.h>
#include <net/netlink.h>
#include <bcmutils.h>
#ifdef WL_CFG80211_V1
#include <wl_cfg80211_v1.h>
#else
#include <wl_cfg80211.h>
#endif /* WL_CFG80211_V1 */
#include <wl_cfgvendor.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhdioctl.h>
#include <brcm_nl80211.h>
#ifdef VENDOR_EXT_SUPPORT
int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
const struct bcm_nlmsg_hdr *nlioc, void *buf)
{
struct net_device *ndev = NULL;
dhd_pub_t *dhd;
dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0};
int ret = 0, err = 0;
int8 index;
WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
dhd = cfg->pub;
DHD_OS_WAKE_LOCK(dhd);
/* send to dongle only if we are not waiting for reload already */
if (dhd->hang_was_sent) {
WL_ERR(("HANG was sent up earlier\n"));
DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
DHD_OS_WAKE_UNLOCK(dhd);
return OSL_ERROR(BCME_DONGLE_DOWN);
}
index = dhd_ifindex2idx(dhd->info, nlioc->ifindex);
if (index == DHD_BAD_IF) {
ndev = wdev_to_wlc_ndev(wdev, cfg);
index = dhd_net2idx(dhd->info, ndev);
if (index == DHD_BAD_IF) {
WL_ERR(("Bad ifidx %d, wdev:%p\n", nlioc->ifindex, wdev));
ret = BCME_ERROR;
goto done;
}
}
ioc.cmd = nlioc->cmd;
ioc.len = nlioc->len;
ioc.set = nlioc->set;
ioc.driver = nlioc->magic;
err = dhd_ioctl_process(dhd, index, &ioc, buf);
if (err) {
ret = OSL_ERROR(err);
ndev = dhd_idx2net(dhd, index);
if(ndev && (ndev->flags & IFF_UP)) {
if ((err == BCME_NOTFOUND) || (err == BCME_NOTREADY)) {
WL_TRACE(("cmd %d return err %d on %s, ret %d\n",
nlioc->cmd, err, ndev->name, ret));
} else {
WL_ERR(("cmd %d return err %d on %s, ret %d\n",
nlioc->cmd, err, ndev->name, ret));
}
}
goto done;
}
done:
DHD_OS_WAKE_UNLOCK(dhd);
return ret;
}
const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = {
{
{
.vendor_id = OUI_BRCM,
.subcmd = BRCM_VENDOR_SCMD_PRIV_STR
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = dhd_cfgvendor_priv_string_handler
},
};
int cfgvendor_attach(struct wiphy *wiphy)
{
wiphy->vendor_commands = dhd_cfgvendor_cmds;
wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds);
return 0;
}
int cfgvendor_detach(struct wiphy *wiphy)
{
wiphy->vendor_commands = NULL;
wiphy->n_vendor_commands = 0;
return 0;
}
#endif /* VENDOR_EXT_SUPPORT */