net: cnss_utils: Add snapshot of cnss_utils driver

This is a snapshot of cnss_utils driver and associated files as of
msm-4.14 commit bea9b04a157b
("cnss_utils: Add support for derived MAC address").

Checkpatch issues are also fixed on top of this commit.

CRs-Fixed: 2375545
Change-Id: Ic2b2824ccf642f6becb9569c42b58178300de320
Signed-off-by: Yuanyuan Liu <yuanliu@codeaurora.org>
This commit is contained in:
Yuanyuan Liu 2019-01-04 11:57:35 -08:00
parent d5ec14caa7
commit 6cc9b3862e
7 changed files with 522 additions and 0 deletions

View File

@ -122,5 +122,6 @@ config VIRT_WIFI
are wifi connections through a special rtnetlink device.
source "drivers/net/wireless/cnss2/Kconfig"
source "drivers/net/wireless/cnss_utils/Kconfig"
endif # WLAN

View File

@ -31,3 +31,5 @@ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_VIRT_WIFI) += virt_wifi.o
obj-$(CONFIG_CNSS2) += cnss2/
obj-$(CONFIG_CNSS_UTILS) += cnss_utils/

View File

@ -3,6 +3,7 @@
config CNSS2
tristate "CNSS2 Platform Driver for Wi-Fi Module"
depends on !CNSS && PCI_MSM
select CNSS_UTILS
help
This module adds the support for Connectivity Subsystem (CNSS) used
for PCIe based Wi-Fi devices with QCA6174/QCA6290 chipsets.

View File

@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
config CNSS_UTILS
bool "CNSS utilities support"
help
Add CNSS utilities support for the WLAN driver module.
This feature enable wlan driver to use CNSS utilities APIs to set
and get wlan related information.

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CNSS_UTILS) += cnss_utils.o

View File

@ -0,0 +1,473 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved. */
#define pr_fmt(fmt) "cnss_utils: " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/etherdevice.h>
#include <linux/debugfs.h>
#include <net/cnss_utils.h>
#define CNSS_MAX_CH_NUM 45
struct cnss_unsafe_channel_list {
u16 unsafe_ch_count;
u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
};
struct cnss_dfs_nol_info {
void *dfs_nol_info;
u16 dfs_nol_info_len;
};
#define MAX_NO_OF_MAC_ADDR 4
#define MAC_PREFIX_LEN 2
struct cnss_wlan_mac_addr {
u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
u32 no_of_mac_addr_set;
};
enum mac_type {
CNSS_MAC_PROVISIONED,
CNSS_MAC_DERIVED,
};
static struct cnss_utils_priv {
struct cnss_unsafe_channel_list unsafe_channel_list;
struct cnss_dfs_nol_info dfs_nol_info;
/* generic mutex for unsafe channel */
struct mutex unsafe_channel_list_lock;
/* generic spin-lock for dfs_nol info */
spinlock_t dfs_nol_info_lock;
int driver_load_cnt;
struct cnss_wlan_mac_addr wlan_mac_addr;
struct cnss_wlan_mac_addr wlan_der_mac_addr;
enum cnss_utils_cc_src cc_source;
struct dentry *root_dentry;
} *cnss_utils_priv;
int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
u16 *unsafe_ch_list, u16 ch_count)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return -EINVAL;
mutex_lock(&priv->unsafe_channel_list_lock);
if (!unsafe_ch_list || ch_count > CNSS_MAX_CH_NUM) {
mutex_unlock(&priv->unsafe_channel_list_lock);
return -EINVAL;
}
priv->unsafe_channel_list.unsafe_ch_count = ch_count;
if (ch_count == 0)
goto end;
memcpy(priv->unsafe_channel_list.unsafe_ch_list,
unsafe_ch_list, ch_count * sizeof(u16));
end:
mutex_unlock(&priv->unsafe_channel_list_lock);
return 0;
}
EXPORT_SYMBOL(cnss_utils_set_wlan_unsafe_channel);
int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
u16 *unsafe_ch_list,
u16 *ch_count, u16 buf_len)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return -EINVAL;
mutex_lock(&priv->unsafe_channel_list_lock);
if (!unsafe_ch_list || !ch_count) {
mutex_unlock(&priv->unsafe_channel_list_lock);
return -EINVAL;
}
if (buf_len <
(priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
mutex_unlock(&priv->unsafe_channel_list_lock);
return -ENOMEM;
}
*ch_count = priv->unsafe_channel_list.unsafe_ch_count;
memcpy(unsafe_ch_list, priv->unsafe_channel_list.unsafe_ch_list,
priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16));
mutex_unlock(&priv->unsafe_channel_list_lock);
return 0;
}
EXPORT_SYMBOL(cnss_utils_get_wlan_unsafe_channel);
int cnss_utils_wlan_set_dfs_nol(struct device *dev,
const void *info, u16 info_len)
{
void *temp;
void *old_nol_info;
struct cnss_dfs_nol_info *dfs_info;
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return -EINVAL;
if (!info || !info_len)
return -EINVAL;
temp = kmemdup(info, info_len, GFP_ATOMIC);
if (!temp)
return -ENOMEM;
spin_lock_bh(&priv->dfs_nol_info_lock);
dfs_info = &priv->dfs_nol_info;
old_nol_info = dfs_info->dfs_nol_info;
dfs_info->dfs_nol_info = temp;
dfs_info->dfs_nol_info_len = info_len;
spin_unlock_bh(&priv->dfs_nol_info_lock);
kfree(old_nol_info);
return 0;
}
EXPORT_SYMBOL(cnss_utils_wlan_set_dfs_nol);
int cnss_utils_wlan_get_dfs_nol(struct device *dev,
void *info, u16 info_len)
{
int len;
struct cnss_dfs_nol_info *dfs_info;
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return -EINVAL;
if (!info || !info_len)
return -EINVAL;
spin_lock_bh(&priv->dfs_nol_info_lock);
dfs_info = &priv->dfs_nol_info;
if (!dfs_info->dfs_nol_info ||
dfs_info->dfs_nol_info_len == 0) {
spin_unlock_bh(&priv->dfs_nol_info_lock);
return -ENOENT;
}
len = min(info_len, dfs_info->dfs_nol_info_len);
memcpy(info, dfs_info->dfs_nol_info, len);
spin_unlock_bh(&priv->dfs_nol_info_lock);
return len;
}
EXPORT_SYMBOL(cnss_utils_wlan_get_dfs_nol);
void cnss_utils_increment_driver_load_cnt(struct device *dev)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return;
++(priv->driver_load_cnt);
}
EXPORT_SYMBOL(cnss_utils_increment_driver_load_cnt);
int cnss_utils_get_driver_load_cnt(struct device *dev)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return -EINVAL;
return priv->driver_load_cnt;
}
EXPORT_SYMBOL(cnss_utils_get_driver_load_cnt);
static int set_wlan_mac_address(const u8 *mac_list, const uint32_t len,
enum mac_type type)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
u32 no_of_mac_addr;
struct cnss_wlan_mac_addr *addr = NULL;
int iter;
u8 *temp = NULL;
if (!priv)
return -EINVAL;
if (len == 0 || (len % ETH_ALEN) != 0) {
pr_err("Invalid length %d\n", len);
return -EINVAL;
}
no_of_mac_addr = len / ETH_ALEN;
if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
pr_err("Exceed maximum supported MAC address %u %u\n",
MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
return -EINVAL;
}
if (type == CNSS_MAC_PROVISIONED)
addr = &priv->wlan_mac_addr;
else
addr = &priv->wlan_der_mac_addr;
if (addr->no_of_mac_addr_set) {
pr_err("WLAN MAC address is already set, num %d type %d\n",
addr->no_of_mac_addr_set, type);
return 0;
}
addr->no_of_mac_addr_set = no_of_mac_addr;
temp = &addr->mac_addr[0][0];
for (iter = 0; iter < no_of_mac_addr;
++iter, temp += ETH_ALEN, mac_list += ETH_ALEN) {
ether_addr_copy(temp, mac_list);
pr_debug("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
temp[0], temp[1], temp[2],
temp[3], temp[4], temp[5]);
}
return 0;
}
int cnss_utils_set_wlan_mac_address(const u8 *mac_list, const uint32_t len)
{
return set_wlan_mac_address(mac_list, len, CNSS_MAC_PROVISIONED);
}
EXPORT_SYMBOL(cnss_utils_set_wlan_mac_address);
int cnss_utils_set_wlan_derived_mac_address(const u8 *mac_list,
const uint32_t len)
{
return set_wlan_mac_address(mac_list, len, CNSS_MAC_DERIVED);
}
EXPORT_SYMBOL(cnss_utils_set_wlan_derived_mac_address);
static u8 *get_wlan_mac_address(struct device *dev,
u32 *num, enum mac_type type)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
struct cnss_wlan_mac_addr *addr = NULL;
if (!priv)
goto out;
if (type == CNSS_MAC_PROVISIONED)
addr = &priv->wlan_mac_addr;
else
addr = &priv->wlan_der_mac_addr;
if (!addr->no_of_mac_addr_set) {
pr_err("WLAN MAC address is not set, type %d\n", type);
goto out;
}
*num = addr->no_of_mac_addr_set;
return &addr->mac_addr[0][0];
out:
*num = 0;
return NULL;
}
u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num)
{
return get_wlan_mac_address(dev, num, CNSS_MAC_PROVISIONED);
}
EXPORT_SYMBOL(cnss_utils_get_wlan_mac_address);
u8 *cnss_utils_get_wlan_derived_mac_address(struct device *dev,
uint32_t *num)
{
return get_wlan_mac_address(dev, num, CNSS_MAC_DERIVED);
}
EXPORT_SYMBOL(cnss_utils_get_wlan_derived_mac_address);
void cnss_utils_set_cc_source(struct device *dev,
enum cnss_utils_cc_src cc_source)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return;
priv->cc_source = cc_source;
}
EXPORT_SYMBOL(cnss_utils_set_cc_source);
enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev)
{
struct cnss_utils_priv *priv = cnss_utils_priv;
if (!priv)
return -EINVAL;
return priv->cc_source;
}
EXPORT_SYMBOL(cnss_utils_get_cc_source);
static ssize_t cnss_utils_mac_write(struct file *fp,
const char __user *user_buf,
size_t count, loff_t *off)
{
struct cnss_utils_priv *priv =
((struct seq_file *)fp->private_data)->private;
char buf[128];
char *input, *mac_type, *mac_address;
u8 *dest_mac;
u8 val;
const char *delim = "\n";
size_t len = 0;
char temp[3] = "";
len = min_t(size_t, count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EINVAL;
buf[len] = '\0';
input = buf;
mac_type = strsep(&input, delim);
if (!mac_type)
return -EINVAL;
if (!input)
return -EINVAL;
mac_address = strsep(&input, delim);
if (!mac_address)
return -EINVAL;
if (strcmp("0x", mac_address)) {
pr_err("Invalid MAC prefix\n");
return -EINVAL;
}
len = strlen(mac_address);
mac_address += MAC_PREFIX_LEN;
len -= MAC_PREFIX_LEN;
if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR ||
len % (ETH_ALEN * 2) != 0) {
pr_err("Invalid MAC address length %zu\n", len);
return -EINVAL;
}
if (!strcmp("provisioned", mac_type)) {
dest_mac = &priv->wlan_mac_addr.mac_addr[0][0];
priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2);
} else if (!strcmp("derived", mac_type)) {
dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0];
priv->wlan_der_mac_addr.no_of_mac_addr_set =
len / (ETH_ALEN * 2);
} else {
pr_err("Invalid MAC address type %s\n", mac_type);
return -EINVAL;
}
while (len--) {
temp[0] = *mac_address++;
temp[1] = *mac_address++;
if (kstrtou8(temp, 16, &val))
return -EINVAL;
*dest_mac++ = val;
}
return count;
}
static int cnss_utils_mac_show(struct seq_file *s, void *data)
{
u8 mac[6];
int i;
struct cnss_utils_priv *priv = s->private;
struct cnss_wlan_mac_addr *addr = NULL;
addr = &priv->wlan_mac_addr;
if (addr->no_of_mac_addr_set) {
seq_puts(s, "\nProvisioned MAC addresseses\n");
for (i = 0; i < addr->no_of_mac_addr_set; i++) {
ether_addr_copy(mac, addr->mac_addr[i]);
seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
}
}
addr = &priv->wlan_der_mac_addr;
if (addr->no_of_mac_addr_set) {
seq_puts(s, "\nDerived MAC addresseses\n");
for (i = 0; i < addr->no_of_mac_addr_set; i++) {
ether_addr_copy(mac, addr->mac_addr[i]);
seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
}
}
return 0;
}
static int cnss_utils_mac_open(struct inode *inode, struct file *file)
{
return single_open(file, cnss_utils_mac_show, inode->i_private);
}
static const struct file_operations cnss_utils_mac_fops = {
.read = seq_read,
.write = cnss_utils_mac_write,
.release = single_release,
.open = cnss_utils_mac_open,
.owner = THIS_MODULE,
.llseek = seq_lseek,
};
static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv)
{
int ret = 0;
struct dentry *root_dentry;
root_dentry = debugfs_create_dir("cnss_utils", NULL);
if (IS_ERR(root_dentry)) {
ret = PTR_ERR(root_dentry);
pr_err("Unable to create debugfs %d\n", ret);
goto out;
}
priv->root_dentry = root_dentry;
debugfs_create_file("mac_address", 0600, root_dentry, priv,
&cnss_utils_mac_fops);
out:
return ret;
}
static int __init cnss_utils_init(void)
{
struct cnss_utils_priv *priv = NULL;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->cc_source = CNSS_UTILS_SOURCE_CORE;
mutex_init(&priv->unsafe_channel_list_lock);
spin_lock_init(&priv->dfs_nol_info_lock);
cnss_utils_debugfs_create(priv);
cnss_utils_priv = priv;
return 0;
}
static void __exit cnss_utils_exit(void)
{
kfree(cnss_utils_priv);
cnss_utils_priv = NULL;
}
module_init(cnss_utils_init);
module_exit(cnss_utils_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(DEVICE "CNSS Utilities Driver");

34
include/net/cnss_utils.h Normal file
View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2017, 2019 The Linux Foundation. All rights reserved. */
#ifndef _CNSS_UTILS_H_
#define _CNSS_UTILS_H_
enum cnss_utils_cc_src {
CNSS_UTILS_SOURCE_CORE,
CNSS_UTILS_SOURCE_11D,
CNSS_UTILS_SOURCE_USER
};
extern int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
u16 *unsafe_ch_list,
u16 ch_count);
extern int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
u16 *unsafe_ch_list,
u16 *ch_count, u16 buf_len);
extern int cnss_utils_wlan_set_dfs_nol(struct device *dev,
const void *info, u16 info_len);
extern int cnss_utils_wlan_get_dfs_nol(struct device *dev,
void *info, u16 info_len);
extern int cnss_utils_get_driver_load_cnt(struct device *dev);
extern void cnss_utils_increment_driver_load_cnt(struct device *dev);
extern int cnss_utils_set_wlan_mac_address(const u8 *in, uint32_t len);
extern u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num);
extern int cnss_utils_set_wlan_derived_mac_address(const u8 *in, uint32_t len);
extern u8 *cnss_utils_get_wlan_derived_mac_address(struct device *dev,
uint32_t *num);
extern void cnss_utils_set_cc_source(struct device *dev,
enum cnss_utils_cc_src cc_source);
extern enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev);
#endif