forked from mirrors/linux
		
	brcmfmac: replace cfg80211 testmode with vendor command
Passing a pointer from user space and using it directly in driver is not a preferable behavior. Switch to cfg80211 vendor mode for dongle command for better cross platform compatibility. Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Franky Lin <frankyl@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
		
							parent
							
								
									51c7f5eddd
								
							
						
					
					
						commit
						1bacb0487d
					
				
					 5 changed files with 188 additions and 41 deletions
				
			
		| 
						 | 
				
			
			@ -34,7 +34,8 @@ brcmfmac-objs += \
 | 
			
		|||
		dhd_common.o \
 | 
			
		||||
		dhd_linux.o \
 | 
			
		||||
		firmware.o \
 | 
			
		||||
		btcoex.o
 | 
			
		||||
		btcoex.o \
 | 
			
		||||
		vendor.o
 | 
			
		||||
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
 | 
			
		||||
		dhd_sdio.o \
 | 
			
		||||
		bcmsdh.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,16 +49,6 @@
 | 
			
		|||
 */
 | 
			
		||||
#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN	32
 | 
			
		||||
 | 
			
		||||
/* Bus independent dongle command */
 | 
			
		||||
struct brcmf_dcmd {
 | 
			
		||||
	uint cmd;		/* common dongle cmd definition */
 | 
			
		||||
	void *buf;		/* pointer to user buffer */
 | 
			
		||||
	uint len;		/* length of user buffer */
 | 
			
		||||
	u8 set;			/* get or set request (optional) */
 | 
			
		||||
	uint used;		/* bytes read or written (optional) */
 | 
			
		||||
	uint needed;		/* bytes needed (optional) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										115
									
								
								drivers/net/wireless/brcm80211/brcmfmac/vendor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								drivers/net/wireless/brcm80211/brcmfmac/vendor.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,115 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014 Broadcom Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
 * purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
 * copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 | 
			
		||||
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/vmalloc.h>
 | 
			
		||||
#include <net/cfg80211.h>
 | 
			
		||||
#include <net/netlink.h>
 | 
			
		||||
 | 
			
		||||
#include <brcmu_wifi.h>
 | 
			
		||||
#include "fwil_types.h"
 | 
			
		||||
#include "dhd.h"
 | 
			
		||||
#include "p2p.h"
 | 
			
		||||
#include "dhd_dbg.h"
 | 
			
		||||
#include "wl_cfg80211.h"
 | 
			
		||||
#include "vendor.h"
 | 
			
		||||
#include "fwil.h"
 | 
			
		||||
 | 
			
		||||
static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy,
 | 
			
		||||
						 struct wireless_dev *wdev,
 | 
			
		||||
						 const void *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 | 
			
		||||
	struct net_device *ndev = cfg_to_ndev(cfg);
 | 
			
		||||
	const struct brcmf_vndr_dcmd_hdr *cmdhdr = data;
 | 
			
		||||
	struct sk_buff *reply;
 | 
			
		||||
	int ret, payload, ret_len;
 | 
			
		||||
	void *dcmd_buf = NULL, *wr_pointer;
 | 
			
		||||
	u16 msglen, maxmsglen = PAGE_SIZE - 0x100;
 | 
			
		||||
 | 
			
		||||
	brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set,
 | 
			
		||||
		  cmdhdr->len);
 | 
			
		||||
 | 
			
		||||
	len -= sizeof(struct brcmf_vndr_dcmd_hdr);
 | 
			
		||||
	ret_len = cmdhdr->len;
 | 
			
		||||
	if (ret_len > 0 || len > 0) {
 | 
			
		||||
		if (len > BRCMF_DCMD_MAXLEN) {
 | 
			
		||||
			brcmf_err("oversize input buffer %d\n", len);
 | 
			
		||||
			len = BRCMF_DCMD_MAXLEN;
 | 
			
		||||
		}
 | 
			
		||||
		if (ret_len > BRCMF_DCMD_MAXLEN) {
 | 
			
		||||
			brcmf_err("oversize return buffer %d\n", ret_len);
 | 
			
		||||
			ret_len = BRCMF_DCMD_MAXLEN;
 | 
			
		||||
		}
 | 
			
		||||
		payload = max(ret_len, len) + 1;
 | 
			
		||||
		dcmd_buf = vzalloc(payload);
 | 
			
		||||
		if (NULL == dcmd_buf)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		memcpy(dcmd_buf, (void *)cmdhdr + cmdhdr->offset, len);
 | 
			
		||||
		*(char *)(dcmd_buf + len)  = '\0';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cmdhdr->set)
 | 
			
		||||
		ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), cmdhdr->cmd,
 | 
			
		||||
					     dcmd_buf, ret_len);
 | 
			
		||||
	else
 | 
			
		||||
		ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), cmdhdr->cmd,
 | 
			
		||||
					     dcmd_buf, ret_len);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		goto exit;
 | 
			
		||||
 | 
			
		||||
	wr_pointer = dcmd_buf;
 | 
			
		||||
	while (ret_len > 0) {
 | 
			
		||||
		msglen = ret_len > maxmsglen ? maxmsglen : ret_len;
 | 
			
		||||
		ret_len -= msglen;
 | 
			
		||||
		payload = msglen + sizeof(msglen);
 | 
			
		||||
		reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
 | 
			
		||||
		if (NULL == reply) {
 | 
			
		||||
			ret = -ENOMEM;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (nla_put(reply, BRCMF_NLATTR_DATA, msglen, wr_pointer) ||
 | 
			
		||||
		    nla_put_u16(reply, BRCMF_NLATTR_LEN, msglen)) {
 | 
			
		||||
			kfree_skb(reply);
 | 
			
		||||
			ret = -ENOBUFS;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = cfg80211_vendor_cmd_reply(reply);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		wr_pointer += msglen;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
exit:
 | 
			
		||||
	vfree(dcmd_buf);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
 | 
			
		||||
	{
 | 
			
		||||
		{
 | 
			
		||||
			.vendor_id = BROADCOM_OUI,
 | 
			
		||||
			.subcmd = BRCMF_VNDR_CMDS_DCMD
 | 
			
		||||
		},
 | 
			
		||||
		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
 | 
			
		||||
			 WIPHY_VENDOR_CMD_NEED_NETDEV,
 | 
			
		||||
		.doit = brcmf_cfg80211_vndr_cmds_dcmd_handler
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										64
									
								
								drivers/net/wireless/brcm80211/brcmfmac/vendor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								drivers/net/wireless/brcm80211/brcmfmac/vendor.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014 Broadcom Corporation
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, and/or distribute this software for any
 | 
			
		||||
 * purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
 * copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 | 
			
		||||
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 | 
			
		||||
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 | 
			
		||||
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _vendor_h_
 | 
			
		||||
#define _vendor_h_
 | 
			
		||||
 | 
			
		||||
#define BROADCOM_OUI	0x001018
 | 
			
		||||
 | 
			
		||||
enum brcmf_vndr_cmds {
 | 
			
		||||
	BRCMF_VNDR_CMDS_UNSPEC,
 | 
			
		||||
	BRCMF_VNDR_CMDS_DCMD,
 | 
			
		||||
	BRCMF_VNDR_CMDS_LAST
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum brcmf_nlattrs - nl80211 message attributes
 | 
			
		||||
 *
 | 
			
		||||
 * @BRCMF_NLATTR_LEN: message body length
 | 
			
		||||
 * @BRCMF_NLATTR_DATA: message body
 | 
			
		||||
 */
 | 
			
		||||
enum brcmf_nlattrs {
 | 
			
		||||
	BRCMF_NLATTR_UNSPEC,
 | 
			
		||||
 | 
			
		||||
	BRCMF_NLATTR_LEN,
 | 
			
		||||
	BRCMF_NLATTR_DATA,
 | 
			
		||||
 | 
			
		||||
	__BRCMF_NLATTR_AFTER_LAST,
 | 
			
		||||
	BRCMF_NLATTR_MAX = __BRCMF_NLATTR_AFTER_LAST - 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct brcmf_vndr_dcmd_hdr - message header for cfg80211 vendor command dcmd
 | 
			
		||||
 *				support
 | 
			
		||||
 *
 | 
			
		||||
 * @cmd: common dongle cmd definition
 | 
			
		||||
 * @len: length of expecting return buffer
 | 
			
		||||
 * @offset: offset of data buffer
 | 
			
		||||
 * @set: get or set request(optional)
 | 
			
		||||
 * @magic: magic number for verification
 | 
			
		||||
 */
 | 
			
		||||
struct brcmf_vndr_dcmd_hdr {
 | 
			
		||||
	uint cmd;
 | 
			
		||||
	int len;
 | 
			
		||||
	uint offset;
 | 
			
		||||
	uint set;
 | 
			
		||||
	uint magic;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct wiphy_vendor_command brcmf_vendor_cmds[];
 | 
			
		||||
 | 
			
		||||
#endif /* _vendor_h_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +19,7 @@
 | 
			
		|||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/etherdevice.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/vmalloc.h>
 | 
			
		||||
#include <net/cfg80211.h>
 | 
			
		||||
#include <net/netlink.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +34,7 @@
 | 
			
		|||
#include "btcoex.h"
 | 
			
		||||
#include "wl_cfg80211.h"
 | 
			
		||||
#include "fwil.h"
 | 
			
		||||
#include "vendor.h"
 | 
			
		||||
 | 
			
		||||
#define BRCMF_SCAN_IE_LEN_MAX		2048
 | 
			
		||||
#define BRCMF_PNO_VERSION		2
 | 
			
		||||
| 
						 | 
				
			
			@ -3257,35 +3259,6 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_NL80211_TESTMODE
 | 
			
		||||
static int brcmf_cfg80211_testmode(struct wiphy *wiphy,
 | 
			
		||||
				   struct wireless_dev *wdev,
 | 
			
		||||
				   void *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 | 
			
		||||
	struct net_device *ndev = cfg_to_ndev(cfg);
 | 
			
		||||
	struct brcmf_dcmd *dcmd = data;
 | 
			
		||||
	struct sk_buff *reply;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
 | 
			
		||||
		  dcmd->buf, dcmd->len);
 | 
			
		||||
 | 
			
		||||
	if (dcmd->set)
 | 
			
		||||
		ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
 | 
			
		||||
					     dcmd->buf, dcmd->len);
 | 
			
		||||
	else
 | 
			
		||||
		ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
 | 
			
		||||
					     dcmd->buf, dcmd->len);
 | 
			
		||||
	if (ret == 0) {
 | 
			
		||||
		reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
 | 
			
		||||
		nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
 | 
			
		||||
		ret = cfg80211_testmode_reply(reply);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
 | 
			
		||||
{
 | 
			
		||||
	s32 err;
 | 
			
		||||
| 
						 | 
				
			
			@ -4303,7 +4276,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
 | 
			
		|||
	.crit_proto_start = brcmf_cfg80211_crit_proto_start,
 | 
			
		||||
	.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
 | 
			
		||||
	.tdls_oper = brcmf_cfg80211_tdls_oper,
 | 
			
		||||
	CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
 | 
			
		||||
| 
						 | 
				
			
			@ -4408,6 +4380,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 | 
			
		|||
	brcmf_dbg(INFO, "Registering custom regulatory\n");
 | 
			
		||||
	wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
 | 
			
		||||
	wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
 | 
			
		||||
 | 
			
		||||
	/* vendor commands/events support */
 | 
			
		||||
	wiphy->vendor_commands = brcmf_vendor_cmds;
 | 
			
		||||
	wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
 | 
			
		||||
 | 
			
		||||
	err = wiphy_register(wiphy);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		brcmf_err("Could not register wiphy device (%d)\n", err);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue