Driver to create cld80211 nl family at bootup time

Create cnss_genl driver to create a netlink family cld80211
and make it available to cld driver and applications when
they query for it.
This driver creates multicast groups to facilitate communication
from cld driver to userspace and allows cld driver to register
for different commands from user space.

Resolve compilation errors and tweak netlink family creation

Change-Id: I0795dd08b6429fad60187fee724b3fd3ccfa5603
CRs-Fixed: 1100401
Bug: 32775496
Signed-off-by: Srinivas Dasari <dasaris@codeaurora.org>
Signed-off-by: Srinivas Girigowda <sgirigow@codeaurora.org>
This commit is contained in:
Srinivas Girigowda 2017-02-16 18:25:31 +05:30 committed by syphyr
parent 22691f3714
commit e7cc63ad89
6 changed files with 338 additions and 0 deletions

View file

@ -335,4 +335,5 @@ source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/mwifiex/Kconfig"
source "drivers/net/wireless/cnss/Kconfig"
source "drivers/net/wireless/cnss_genl/Kconfig"
endif # WLAN

View file

@ -62,4 +62,5 @@ obj-$(CONFIG_LIBRA_SDIOIF) += libra/
obj-$(CONFIG_WCNSS_CORE) += wcnss/
obj-$(CONFIG_CNSS) += cnss/
obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
obj-$(CONFIG_CNSS_GENL) += cnss_genl/
obj-$(CONFIG_QCA_CLD_WLAN) += qcacld-2.0/

View file

@ -0,0 +1,7 @@
config CNSS_GENL
tristate "CNSS Generic Netlink Socket Driver"
---help---
This module creates generic netlink family "CLD80211". This can be
used by cld driver and userspace utilities to communicate over
netlink sockets. This module creates different multicast groups to
facilitate the same.

View file

@ -0,0 +1 @@
obj-$(CONFIG_CNSS_GENL) := cnss_nl.o

View file

@ -0,0 +1,221 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <net/genetlink.h>
#include <net/cnss_nl.h>
#include <linux/module.h>
#include <linux/string.h>
#define CLD80211_GENL_NAME "cld80211"
#define CLD80211_MULTICAST_GROUP_SVC_MSGS "svc_msgs"
#define CLD80211_MULTICAST_GROUP_HOST_LOGS "host_logs"
#define CLD80211_MULTICAST_GROUP_FW_LOGS "fw_logs"
#define CLD80211_MULTICAST_GROUP_PER_PKT_STATS "per_pkt_stats"
#define CLD80211_MULTICAST_GROUP_DIAG_EVENTS "diag_events"
#define CLD80211_MULTICAST_GROUP_FATAL_EVENTS "fatal_events"
#define CLD80211_MULTICAST_GROUP_OEM_MSGS "oem_msgs"
static struct genl_multicast_group nl_mcgrps[] = {
[CLD80211_MCGRP_SVC_MSGS] = { .name =
CLD80211_MULTICAST_GROUP_SVC_MSGS},
[CLD80211_MCGRP_HOST_LOGS] = { .name =
CLD80211_MULTICAST_GROUP_HOST_LOGS},
[CLD80211_MCGRP_FW_LOGS] = { .name =
CLD80211_MULTICAST_GROUP_FW_LOGS},
[CLD80211_MCGRP_PER_PKT_STATS] = { .name =
CLD80211_MULTICAST_GROUP_PER_PKT_STATS},
[CLD80211_MCGRP_DIAG_EVENTS] = { .name =
CLD80211_MULTICAST_GROUP_DIAG_EVENTS},
[CLD80211_MCGRP_FATAL_EVENTS] = { .name =
CLD80211_MULTICAST_GROUP_FATAL_EVENTS},
[CLD80211_MCGRP_OEM_MSGS] = { .name =
CLD80211_MULTICAST_GROUP_OEM_MSGS},
};
struct cld_ops {
cld80211_cb cb;
void *cb_ctx;
};
struct cld80211_nl_data {
struct cld_ops cld_ops[CLD80211_MAX_COMMANDS];
};
static struct cld80211_nl_data nl_data;
static inline struct cld80211_nl_data *get_local_ctx(void)
{
return &nl_data;
}
static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS];
/* policy for the attributes */
static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX+1] = {
[CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED },
[CLD80211_ATTR_DATA] = { .type = NLA_BINARY,
.len = CLD80211_MAX_NL_DATA },
};
static int cld80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info)
{
u8 cmd_id = ops->cmd;
struct cld80211_nl_data *nl = get_local_ctx();
if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
return -EOPNOTSUPP;
}
info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
return 0;
}
/* The netlink family */
static struct genl_family cld80211_fam = {
.id = GENL_ID_GENERATE,
.name = CLD80211_GENL_NAME,
.hdrsize = 0, /* no private header */
.version = 1, /* no particular meaning now */
.maxattr = CLD80211_ATTR_MAX,
.netnsok = true,
.pre_doit = cld80211_pre_doit,
.post_doit = NULL,
};
int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx)
{
struct cld80211_nl_data *nl = get_local_ctx();
pr_debug("CLD80211: Registering command: %d\n", cmd_id);
if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
pr_debug("CLD80211: invalid command: %d\n", cmd_id);
return -EINVAL;
}
nl->cld_ops[cmd_id - 1].cb = func;
nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx;
return 0;
}
EXPORT_SYMBOL(register_cld_cmd_cb);
int deregister_cld_cmd_cb(u8 cmd_id)
{
struct cld80211_nl_data *nl = get_local_ctx();
pr_debug("CLD80211: De-registering command: %d\n", cmd_id);
if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
pr_debug("CLD80211: invalid command: %d\n", cmd_id);
return -EINVAL;
}
nl->cld_ops[cmd_id - 1].cb = NULL;
nl->cld_ops[cmd_id - 1].cb_ctx = NULL;
return 0;
}
EXPORT_SYMBOL(deregister_cld_cmd_cb);
struct genl_family *cld80211_get_genl_family(void)
{
return &cld80211_fam;
}
EXPORT_SYMBOL(cld80211_get_genl_family);
int cld80211_get_mcgrp_id(enum cld80211_multicast_groups groupid)
{
if (groupid > ARRAY_SIZE(nl_ops))
return -1;
return nl_mcgrps[groupid].id;
}
EXPORT_SYMBOL(cld80211_get_mcgrp_id);
static int cld80211_doit(struct sk_buff *skb, struct genl_info *info)
{
cld80211_cb cld_cb;
void *cld_ctx;
cld_cb = info->user_ptr[0];
if (cld_cb == NULL) {
pr_err("CLD80211: Not supported\n");
return -EOPNOTSUPP;
}
cld_ctx = info->user_ptr[1];
if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) {
cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
cld_ctx, info->snd_portid);
} else {
pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n");
return -EINVAL;
}
return 0;
}
static int __cld80211_init(void)
{
int err, i;
memset(&nl_ops[0], 0, sizeof(nl_ops));
pr_info("CLD80211: Initializing\n");
for (i = 0; i < CLD80211_MAX_COMMANDS; i++) {
nl_ops[i].cmd = i + 1;
nl_ops[i].doit = cld80211_doit;
nl_ops[i].policy = cld80211_policy;
}
err = genl_register_family_with_ops(&cld80211_fam, nl_ops,
ARRAY_SIZE(nl_ops));
if (err) {
pr_err("CLD80211: Failed to register cld80211 family: %d\n",
err);
return err;
}
for (i = 0; i < ARRAY_SIZE(nl_mcgrps); i++) {
err = genl_register_mc_group(&cld80211_fam, &nl_mcgrps[i]);
if (err)
goto err_out;
}
return 0;
err_out:
genl_unregister_family(&cld80211_fam);
return err;
}
static void __cld80211_exit(void)
{
genl_unregister_family(&cld80211_fam);
}
static int __init cld80211_init(void)
{
return __cld80211_init();
}
static void __exit cld80211_exit(void)
{
__cld80211_exit();
}
module_init(cld80211_init);
module_exit(cld80211_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CNSS generic netlink module");

107
include/net/cnss_nl.h Normal file
View file

@ -0,0 +1,107 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _NET_CNSS_GENETLINK_H_
#define _NET_CNSS_GENETLINK_H_
#define CLD80211_MAX_COMMANDS 40
#define CLD80211_MAX_NL_DATA 4096
/**
* enum cld80211_attr - Driver/Application embeds the data in nlmsg with the
* help of below attributes
*
* @CLD80211_ATTR_VENDOR_DATA: Embed all other attributes in this nested
* attribute.
* @CLD80211_ATTR_DATA: Embed complete data in this attribute
*
* Any new message in future can be added as another attribute
*/
enum cld80211_attr {
CLD80211_ATTR_VENDOR_DATA = 1,
CLD80211_ATTR_DATA,
/* add new attributes above here */
__CLD80211_ATTR_AFTER_LAST,
CLD80211_ATTR_MAX = __CLD80211_ATTR_AFTER_LAST - 1
};
/**
* enum cld80211_multicast_groups - List of multicast groups supported
*
* @CLD80211_MCGRP_SVC_MSGS: WLAN service message will be sent to this group.
* Ex: Status ind messages
* @CLD80211_MCGRP_HOST_LOGS: All logging related messages from driver will be
* sent to this multicast group
* @CLD80211_MCGRP_FW_LOGS: Firmware logging messages will be sent to this group
* @CLD80211_MCGRP_PER_PKT_STATS: Messages related packet stats debugging infra
* will be sent to this group
* @CLD80211_MCGRP_DIAG_EVENTS: Driver/Firmware status logging diag events will
* be sent to this group
* @CLD80211_MCGRP_FATAL_EVENTS: Any fatal message generated in driver/firmware
* will be sent to this group
* @CLD80211_MCGRP_OEM_MSGS: All OEM message will be sent to this group
* Ex: LOWI messages
*/
enum cld80211_multicast_groups {
CLD80211_MCGRP_SVC_MSGS,
CLD80211_MCGRP_HOST_LOGS,
CLD80211_MCGRP_FW_LOGS,
CLD80211_MCGRP_PER_PKT_STATS,
CLD80211_MCGRP_DIAG_EVENTS,
CLD80211_MCGRP_FATAL_EVENTS,
CLD80211_MCGRP_OEM_MSGS,
};
/**
* typedef cld80211_cb - Callback to be called when an nlmsg is received with
* the registered cmd_id command from userspace
* @data: Payload of the message to be sent to driver
* @data_len: Length of the payload
* @cb_ctx: callback context to be returned to driver when the callback
* is called
* @pid: process id of the sender
*/
typedef void (*cld80211_cb)(const void *data, int data_len,
void *cb_ctx, int pid);
/**
* register_cld_cmd_cb() - Allows cld driver to register for commands with
* callback
* @cmd_id: Command to be registered. Valid range [1, CLD80211_MAX_COMMANDS]
* @cb: Callback to be called when an nlmsg is received with cmd_id command
* from userspace
* @cb_ctx: context provided by driver; Send this as cb_ctx of func()
* to driver
*/
int register_cld_cmd_cb(u8 cmd_id, cld80211_cb cb, void *cb_ctx);
/**
* deregister_cld_cmd_cb() - Allows cld driver to de-register the command it
* has already registered
* @cmd_id: Command to be deregistered.
*/
int deregister_cld_cmd_cb(u8 cmd_id);
/**
* cld80211_get_genl_family() - Returns current netlink family context
*/
struct genl_family *cld80211_get_genl_family(void);
/**
* cld80211_get_mcgrp_id() - Returns netlink multicast group id of the local
* groupid
* @groupid: index of the group from enum cld80211_multicast_groups
*/
int cld80211_get_mcgrp_id(enum cld80211_multicast_groups groupid);
#endif /* _NET_CNSS_GENETLINK_H_ */