cnss_nl.c 5.7 KB

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