198 lines
5.5 KiB
C
198 lines
5.5 KiB
C
/*
|
|
* Linux cfg80211 Vendor Extension Code
|
|
*
|
|
* Copyright (C) 1999-2015, 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.
|
|
*
|
|
* $Id: wl_cfgvendor.c 455257 2014-02-13 08:10:24Z $
|
|
*/
|
|
|
|
/*
|
|
* New vendor interface additon to nl80211/cfg80211 to allow vendors
|
|
* to implement proprietary features over the cfg80211 stack.
|
|
*/
|
|
|
|
#include <typedefs.h>
|
|
#include <linuxver.h>
|
|
#include <osl.h>
|
|
#include <linux/kernel.h>
|
|
|
|
#include <bcmutils.h>
|
|
#include <bcmwifi_channels.h>
|
|
#include <bcmendian.h>
|
|
#include <proto/ethernet.h>
|
|
#include <proto/802.11.h>
|
|
#include <linux/if_arp.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
#include <dngl_stats.h>
|
|
#include <dhd.h>
|
|
#include <dhdioctl.h>
|
|
#include <wlioctl.h>
|
|
#include <dhd_cfg80211.h>
|
|
#ifdef PNO_SUPPORT
|
|
#include <dhd_pno.h>
|
|
#endif /* PNO_SUPPORT */
|
|
|
|
#include <proto/ethernet.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/wireless.h>
|
|
#include <linux/ieee80211.h>
|
|
#include <linux/wait.h>
|
|
#include <net/cfg80211.h>
|
|
#include <net/rtnetlink.h>
|
|
|
|
#include <wlioctl.h>
|
|
#include <wldev_common.h>
|
|
#include <wl_cfg80211.h>
|
|
#include <wl_cfgp2p.h>
|
|
#include <wl_android.h>
|
|
#include <wl_cfgvendor.h>
|
|
#ifdef PROP_TXSTATUS
|
|
#include <dhd_wlfc.h>
|
|
#endif
|
|
|
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
|
|
/*
|
|
* This API is to be used for asynchronous vendor events. This
|
|
* shouldn't be used in response to a vendor command from its
|
|
* do_it handler context (instead wl_cfgvendor_send_cmd_reply should
|
|
* be used).
|
|
*/
|
|
int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
|
|
struct net_device *dev, int event_id, const void *data, int len)
|
|
{
|
|
u16 kflags;
|
|
struct sk_buff *skb;
|
|
|
|
kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
|
|
|
|
/* Alloc the SKB for vendor_event */
|
|
skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
|
|
if (!skb) {
|
|
WL_ERR(("skb alloc failed"));
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Push the data to the skb */
|
|
nla_put_nohdr(skb, len, data);
|
|
|
|
cfg80211_vendor_event(skb, kflags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
|
|
struct net_device *dev, const void *data, int len)
|
|
{
|
|
struct sk_buff *skb;
|
|
|
|
/* Alloc the SKB for vendor_event */
|
|
skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
|
|
if (unlikely(!skb)) {
|
|
WL_ERR(("skb alloc failed"));
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Push the data to the skb */
|
|
nla_put_nohdr(skb, len, data);
|
|
|
|
return cfg80211_vendor_cmd_reply(skb);
|
|
}
|
|
|
|
static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
|
|
struct wireless_dev *wdev, const void *data, int len)
|
|
{
|
|
struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
|
|
int err = 0;
|
|
int data_len = 0;
|
|
|
|
WL_INFO(("%s: Enter \n", __func__));
|
|
|
|
bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
|
|
|
|
if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) {
|
|
err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0,
|
|
cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
|
|
if (unlikely(err)) {
|
|
WL_ERR(("error (%d)\n", err));
|
|
return err;
|
|
}
|
|
data_len = strlen(cfg->ioctl_buf);
|
|
cfg->ioctl_buf[data_len] = '\0';
|
|
}
|
|
|
|
err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
|
|
cfg->ioctl_buf, data_len+1);
|
|
if (unlikely(err))
|
|
WL_ERR(("Vendor Command reply failed ret:%d \n", err));
|
|
else
|
|
WL_INFO(("Vendor Command reply sent successfully!\n"));
|
|
|
|
return err;
|
|
}
|
|
|
|
static const struct wiphy_vendor_command wl_vendor_cmds [] = {
|
|
{
|
|
{
|
|
.vendor_id = OUI_BRCM,
|
|
.subcmd = BRCM_VENDOR_SCMD_PRIV_STR
|
|
},
|
|
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
|
|
.doit = wl_cfgvendor_priv_string_handler
|
|
},
|
|
};
|
|
|
|
static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
|
|
{ OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
|
|
{ OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
|
|
};
|
|
|
|
int wl_cfgvendor_attach(struct wiphy *wiphy)
|
|
{
|
|
|
|
WL_INFO(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
|
|
NL80211_CMD_VENDOR));
|
|
|
|
wiphy->vendor_commands = wl_vendor_cmds;
|
|
wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
|
|
wiphy->vendor_events = wl_vendor_events;
|
|
wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wl_cfgvendor_detach(struct wiphy *wiphy)
|
|
{
|
|
WL_INFO(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
|
|
|
|
wiphy->vendor_commands = NULL;
|
|
wiphy->vendor_events = NULL;
|
|
wiphy->n_vendor_commands = 0;
|
|
wiphy->n_vendor_events = 0;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
|