123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- #include <net/genetlink.h>
- #ifdef CONFIG_CNSS_OUT_OF_TREE
- #include "cnss_nl.h"
- #else
- #include <net/cnss_nl.h>
- #endif
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/version.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];
- 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 },
- [CLD80211_ATTR_META_DATA] = { .type = NLA_BINARY,
- .len = CLD80211_MAX_NL_DATA },
- [CLD80211_ATTR_CMD] = { .type = NLA_U32 },
- [CLD80211_ATTR_CMD_TAG_DATA] = { .type = NLA_NESTED },
- };
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0))
- static int cld80211_pre_doit(const struct genl_split_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;
- }
- #else
- 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;
- }
- #endif
- static struct genl_family cld80211_fam __ro_after_init = {
- .name = CLD80211_GENL_NAME,
- .hdrsize = 0,
- .version = 1,
- .maxattr = CLD80211_ATTR_MAX,
- .policy = cld80211_policy,
- .netnsok = true,
- .pre_doit = cld80211_pre_doit,
- .post_doit = NULL,
- .module = THIS_MODULE,
- .ops = nl_ops,
- .n_ops = ARRAY_SIZE(nl_ops),
- .mcgrps = nl_mcgrps,
- .n_mcgrps = ARRAY_SIZE(nl_mcgrps),
- };
- 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;
- }
- err = genl_register_family(&cld80211_fam);
- 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 bool cld80211_is_valid_dt_node_found(void)
- {
- struct device_node *dn = NULL;
- for_each_node_with_property(dn, "qcom,wlan") {
- if (of_device_is_available(dn))
- break;
- }
- if (dn)
- return true;
- return false;
- }
- static int __init cld80211_init(void)
- {
- if (!cld80211_is_valid_dt_node_found())
- return -ENODEV;
- 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");
|