cnss_nl.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */
  3. #include <net/genetlink.h>
  4. #ifdef CONFIG_CNSS_OUT_OF_TREE
  5. #include "cnss_nl.h"
  6. #else
  7. #include <net/cnss_nl.h>
  8. #endif
  9. #include <linux/module.h>
  10. #include <linux/of.h>
  11. #define CLD80211_GENL_NAME "cld80211"
  12. #define CLD80211_MULTICAST_GROUP_SVC_MSGS "svc_msgs"
  13. #define CLD80211_MULTICAST_GROUP_HOST_LOGS "host_logs"
  14. #define CLD80211_MULTICAST_GROUP_FW_LOGS "fw_logs"
  15. #define CLD80211_MULTICAST_GROUP_PER_PKT_STATS "per_pkt_stats"
  16. #define CLD80211_MULTICAST_GROUP_DIAG_EVENTS "diag_events"
  17. #define CLD80211_MULTICAST_GROUP_FATAL_EVENTS "fatal_events"
  18. #define CLD80211_MULTICAST_GROUP_OEM_MSGS "oem_msgs"
  19. static const struct genl_multicast_group nl_mcgrps[] = {
  20. [CLD80211_MCGRP_SVC_MSGS] = { .name =
  21. CLD80211_MULTICAST_GROUP_SVC_MSGS},
  22. [CLD80211_MCGRP_HOST_LOGS] = { .name =
  23. CLD80211_MULTICAST_GROUP_HOST_LOGS},
  24. [CLD80211_MCGRP_FW_LOGS] = { .name =
  25. CLD80211_MULTICAST_GROUP_FW_LOGS},
  26. [CLD80211_MCGRP_PER_PKT_STATS] = { .name =
  27. CLD80211_MULTICAST_GROUP_PER_PKT_STATS},
  28. [CLD80211_MCGRP_DIAG_EVENTS] = { .name =
  29. CLD80211_MULTICAST_GROUP_DIAG_EVENTS},
  30. [CLD80211_MCGRP_FATAL_EVENTS] = { .name =
  31. CLD80211_MULTICAST_GROUP_FATAL_EVENTS},
  32. [CLD80211_MCGRP_OEM_MSGS] = { .name =
  33. CLD80211_MULTICAST_GROUP_OEM_MSGS},
  34. };
  35. struct cld_ops {
  36. cld80211_cb cb;
  37. void *cb_ctx;
  38. };
  39. struct cld80211_nl_data {
  40. struct cld_ops cld_ops[CLD80211_MAX_COMMANDS];
  41. };
  42. static struct cld80211_nl_data nl_data;
  43. static inline struct cld80211_nl_data *get_local_ctx(void)
  44. {
  45. return &nl_data;
  46. }
  47. static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS];
  48. /* policy for the attributes */
  49. static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = {
  50. [CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED },
  51. [CLD80211_ATTR_DATA] = { .type = NLA_BINARY,
  52. .len = CLD80211_MAX_NL_DATA },
  53. [CLD80211_ATTR_META_DATA] = { .type = NLA_BINARY,
  54. .len = CLD80211_MAX_NL_DATA },
  55. [CLD80211_ATTR_CMD] = { .type = NLA_U32 },
  56. [CLD80211_ATTR_CMD_TAG_DATA] = { .type = NLA_NESTED },
  57. };
  58. static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
  59. struct genl_info *info)
  60. {
  61. u8 cmd_id = ops->cmd;
  62. struct cld80211_nl_data *nl = get_local_ctx();
  63. if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
  64. pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
  65. return -EOPNOTSUPP;
  66. }
  67. info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
  68. info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
  69. return 0;
  70. }
  71. /* The netlink family */
  72. static struct genl_family cld80211_fam __ro_after_init = {
  73. .name = CLD80211_GENL_NAME,
  74. .hdrsize = 0, /* no private header */
  75. .version = 1, /* no particular meaning now */
  76. .maxattr = CLD80211_ATTR_MAX,
  77. .policy = cld80211_policy,
  78. .netnsok = true,
  79. .pre_doit = cld80211_pre_doit,
  80. .post_doit = NULL,
  81. .module = THIS_MODULE,
  82. .ops = nl_ops,
  83. .n_ops = ARRAY_SIZE(nl_ops),
  84. .mcgrps = nl_mcgrps,
  85. .n_mcgrps = ARRAY_SIZE(nl_mcgrps),
  86. };
  87. int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx)
  88. {
  89. struct cld80211_nl_data *nl = get_local_ctx();
  90. pr_debug("CLD80211: Registering command: %d\n", cmd_id);
  91. if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
  92. pr_debug("CLD80211: invalid command: %d\n", cmd_id);
  93. return -EINVAL;
  94. }
  95. nl->cld_ops[cmd_id - 1].cb = func;
  96. nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx;
  97. return 0;
  98. }
  99. EXPORT_SYMBOL(register_cld_cmd_cb);
  100. int deregister_cld_cmd_cb(u8 cmd_id)
  101. {
  102. struct cld80211_nl_data *nl = get_local_ctx();
  103. pr_debug("CLD80211: De-registering command: %d\n", cmd_id);
  104. if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
  105. pr_debug("CLD80211: invalid command: %d\n", cmd_id);
  106. return -EINVAL;
  107. }
  108. nl->cld_ops[cmd_id - 1].cb = NULL;
  109. nl->cld_ops[cmd_id - 1].cb_ctx = NULL;
  110. return 0;
  111. }
  112. EXPORT_SYMBOL(deregister_cld_cmd_cb);
  113. struct genl_family *cld80211_get_genl_family(void)
  114. {
  115. return &cld80211_fam;
  116. }
  117. EXPORT_SYMBOL(cld80211_get_genl_family);
  118. static int cld80211_doit(struct sk_buff *skb, struct genl_info *info)
  119. {
  120. cld80211_cb cld_cb;
  121. void *cld_ctx;
  122. cld_cb = info->user_ptr[0];
  123. if (!cld_cb) {
  124. pr_err("CLD80211: Not supported\n");
  125. return -EOPNOTSUPP;
  126. }
  127. cld_ctx = info->user_ptr[1];
  128. if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) {
  129. cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
  130. nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
  131. cld_ctx, info->snd_portid);
  132. } else {
  133. pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n");
  134. return -EINVAL;
  135. }
  136. return 0;
  137. }
  138. static int __cld80211_init(void)
  139. {
  140. int err, i;
  141. memset(&nl_ops[0], 0, sizeof(nl_ops));
  142. pr_info("CLD80211: Initializing\n");
  143. for (i = 0; i < CLD80211_MAX_COMMANDS; i++) {
  144. nl_ops[i].cmd = i + 1;
  145. nl_ops[i].doit = cld80211_doit;
  146. nl_ops[i].flags = GENL_ADMIN_PERM;
  147. }
  148. err = genl_register_family(&cld80211_fam);
  149. if (err) {
  150. pr_err("CLD80211: Failed to register cld80211 family: %d\n",
  151. err);
  152. }
  153. return err;
  154. }
  155. static void __cld80211_exit(void)
  156. {
  157. genl_unregister_family(&cld80211_fam);
  158. }
  159. /**
  160. * cld80211_is_valid_dt_node_found - Check if valid device tree node present
  161. *
  162. * Valid device tree node means a node with "qcom,wlan" property present and
  163. * "status" property not disabled.
  164. *
  165. * Return: true if valid device tree node found, false if not found
  166. */
  167. static bool cld80211_is_valid_dt_node_found(void)
  168. {
  169. struct device_node *dn = NULL;
  170. for_each_node_with_property(dn, "qcom,wlan") {
  171. if (of_device_is_available(dn))
  172. break;
  173. }
  174. if (dn)
  175. return true;
  176. return false;
  177. }
  178. static int __init cld80211_init(void)
  179. {
  180. if (!cld80211_is_valid_dt_node_found())
  181. return -ENODEV;
  182. return __cld80211_init();
  183. }
  184. static void __exit cld80211_exit(void)
  185. {
  186. __cld80211_exit();
  187. }
  188. module_init(cld80211_init);
  189. module_exit(cld80211_exit);
  190. MODULE_LICENSE("GPL v2");
  191. MODULE_DESCRIPTION("CNSS generic netlink module");