diff options
-rw-r--r-- | drivers/net/wireless/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/wireless/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/cnss_genl/Kconfig | 7 | ||||
-rw-r--r-- | drivers/net/wireless/cnss_genl/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/cnss_genl/cnss_nl.c | 204 | ||||
-rw-r--r-- | include/net/cnss_nl.h | 100 |
6 files changed, 314 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 284caf81e808..486af5dac5df 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -332,5 +332,6 @@ source "drivers/net/wireless/mwifiex/Kconfig" source "drivers/net/wireless/cw1200/Kconfig" source "drivers/net/wireless/rsi/Kconfig" source "drivers/net/wireless/cnss/Kconfig" +source "drivers/net/wireless/cnss_genl/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 818fa279b25d..0204fc00f0c5 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -66,3 +66,4 @@ obj-$(CONFIG_WCNSS_CORE) += wcnss/ obj-$(CONFIG_CNSS) += cnss/ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ +obj-$(CONFIG_CNSS_GENL) += cnss_genl/ diff --git a/drivers/net/wireless/cnss_genl/Kconfig b/drivers/net/wireless/cnss_genl/Kconfig new file mode 100644 index 000000000000..f1b8a586ec90 --- /dev/null +++ b/drivers/net/wireless/cnss_genl/Kconfig @@ -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. diff --git a/drivers/net/wireless/cnss_genl/Makefile b/drivers/net/wireless/cnss_genl/Makefile new file mode 100644 index 000000000000..9431c9e596bb --- /dev/null +++ b/drivers/net/wireless/cnss_genl/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CNSS_GENL) := cnss_nl.o diff --git a/drivers/net/wireless/cnss_genl/cnss_nl.c b/drivers/net/wireless/cnss_genl/cnss_nl.c new file mode 100644 index 000000000000..fafd9ce4b4c4 --- /dev/null +++ b/drivers/net/wireless/cnss_genl/cnss_nl.c @@ -0,0 +1,204 @@ +/* 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> + +#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 const 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(const 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); + +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) { + 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].flags = GENL_ADMIN_PERM; + nl_ops[i].policy = cld80211_policy; + } + + err = genl_register_family_with_ops_groups(&cld80211_fam, nl_ops, + nl_mcgrps); + if (err) { + pr_err("CLD80211: Failed to register cld80211 family: %d\n", + err); + } + + 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"); diff --git a/include/net/cnss_nl.h b/include/net/cnss_nl.h new file mode 100644 index 000000000000..86c2fccc930e --- /dev/null +++ b/include/net/cnss_nl.h @@ -0,0 +1,100 @@ +/* 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); + +#endif /* _NET_CNSS_GENETLINK_H_ */ |