cnss_utils.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2017, 2019, 2021 The Linux Foundation. All rights reserved. */
  3. #define pr_fmt(fmt) "cnss_utils: " fmt
  4. #include <linux/module.h>
  5. #include <linux/kernel.h>
  6. #include <linux/slab.h>
  7. #include <linux/etherdevice.h>
  8. #include <linux/debugfs.h>
  9. #include <linux/of.h>
  10. #ifdef CONFIG_CNSS_OUT_OF_TREE
  11. #include "cnss_utils.h"
  12. #else
  13. #include <net/cnss_utils.h>
  14. #endif
  15. #define CNSS_MAX_CH_NUM 157
  16. struct cnss_unsafe_channel_list {
  17. u16 unsafe_ch_count;
  18. u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
  19. };
  20. struct cnss_dfs_nol_info {
  21. void *dfs_nol_info;
  22. u16 dfs_nol_info_len;
  23. };
  24. #define MAX_NO_OF_MAC_ADDR 4
  25. #define MAC_PREFIX_LEN 2
  26. struct cnss_wlan_mac_addr {
  27. u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
  28. u32 no_of_mac_addr_set;
  29. };
  30. enum mac_type {
  31. CNSS_MAC_PROVISIONED,
  32. CNSS_MAC_DERIVED,
  33. };
  34. static struct cnss_utils_priv {
  35. struct cnss_unsafe_channel_list unsafe_channel_list;
  36. struct cnss_dfs_nol_info dfs_nol_info;
  37. /* generic mutex for unsafe channel */
  38. struct mutex unsafe_channel_list_lock;
  39. /* generic spin-lock for dfs_nol info */
  40. spinlock_t dfs_nol_info_lock;
  41. int driver_load_cnt;
  42. struct cnss_wlan_mac_addr wlan_mac_addr;
  43. struct cnss_wlan_mac_addr wlan_der_mac_addr;
  44. enum cnss_utils_cc_src cc_source;
  45. struct dentry *root_dentry;
  46. } *cnss_utils_priv;
  47. int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
  48. u16 *unsafe_ch_list, u16 ch_count)
  49. {
  50. struct cnss_utils_priv *priv = cnss_utils_priv;
  51. if (!priv)
  52. return -EINVAL;
  53. mutex_lock(&priv->unsafe_channel_list_lock);
  54. if (!unsafe_ch_list || ch_count > CNSS_MAX_CH_NUM) {
  55. mutex_unlock(&priv->unsafe_channel_list_lock);
  56. return -EINVAL;
  57. }
  58. priv->unsafe_channel_list.unsafe_ch_count = ch_count;
  59. if (ch_count == 0)
  60. goto end;
  61. memcpy(priv->unsafe_channel_list.unsafe_ch_list,
  62. unsafe_ch_list, ch_count * sizeof(u16));
  63. end:
  64. mutex_unlock(&priv->unsafe_channel_list_lock);
  65. return 0;
  66. }
  67. EXPORT_SYMBOL(cnss_utils_set_wlan_unsafe_channel);
  68. int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
  69. u16 *unsafe_ch_list,
  70. u16 *ch_count, u16 buf_len)
  71. {
  72. struct cnss_utils_priv *priv = cnss_utils_priv;
  73. if (!priv)
  74. return -EINVAL;
  75. mutex_lock(&priv->unsafe_channel_list_lock);
  76. if (!unsafe_ch_list || !ch_count) {
  77. mutex_unlock(&priv->unsafe_channel_list_lock);
  78. return -EINVAL;
  79. }
  80. if (buf_len <
  81. (priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
  82. mutex_unlock(&priv->unsafe_channel_list_lock);
  83. return -ENOMEM;
  84. }
  85. *ch_count = priv->unsafe_channel_list.unsafe_ch_count;
  86. memcpy(unsafe_ch_list, priv->unsafe_channel_list.unsafe_ch_list,
  87. priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16));
  88. mutex_unlock(&priv->unsafe_channel_list_lock);
  89. return 0;
  90. }
  91. EXPORT_SYMBOL(cnss_utils_get_wlan_unsafe_channel);
  92. int cnss_utils_wlan_set_dfs_nol(struct device *dev,
  93. const void *info, u16 info_len)
  94. {
  95. void *temp;
  96. void *old_nol_info;
  97. struct cnss_dfs_nol_info *dfs_info;
  98. struct cnss_utils_priv *priv = cnss_utils_priv;
  99. if (!priv)
  100. return -EINVAL;
  101. if (!info || !info_len)
  102. return -EINVAL;
  103. temp = kmemdup(info, info_len, GFP_ATOMIC);
  104. if (!temp)
  105. return -ENOMEM;
  106. spin_lock_bh(&priv->dfs_nol_info_lock);
  107. dfs_info = &priv->dfs_nol_info;
  108. old_nol_info = dfs_info->dfs_nol_info;
  109. dfs_info->dfs_nol_info = temp;
  110. dfs_info->dfs_nol_info_len = info_len;
  111. spin_unlock_bh(&priv->dfs_nol_info_lock);
  112. kfree(old_nol_info);
  113. return 0;
  114. }
  115. EXPORT_SYMBOL(cnss_utils_wlan_set_dfs_nol);
  116. int cnss_utils_wlan_get_dfs_nol(struct device *dev,
  117. void *info, u16 info_len)
  118. {
  119. int len;
  120. struct cnss_dfs_nol_info *dfs_info;
  121. struct cnss_utils_priv *priv = cnss_utils_priv;
  122. if (!priv)
  123. return -EINVAL;
  124. if (!info || !info_len)
  125. return -EINVAL;
  126. spin_lock_bh(&priv->dfs_nol_info_lock);
  127. dfs_info = &priv->dfs_nol_info;
  128. if (!dfs_info->dfs_nol_info ||
  129. dfs_info->dfs_nol_info_len == 0) {
  130. spin_unlock_bh(&priv->dfs_nol_info_lock);
  131. return -ENOENT;
  132. }
  133. len = min(info_len, dfs_info->dfs_nol_info_len);
  134. memcpy(info, dfs_info->dfs_nol_info, len);
  135. spin_unlock_bh(&priv->dfs_nol_info_lock);
  136. return len;
  137. }
  138. EXPORT_SYMBOL(cnss_utils_wlan_get_dfs_nol);
  139. void cnss_utils_increment_driver_load_cnt(struct device *dev)
  140. {
  141. struct cnss_utils_priv *priv = cnss_utils_priv;
  142. if (!priv)
  143. return;
  144. ++(priv->driver_load_cnt);
  145. }
  146. EXPORT_SYMBOL(cnss_utils_increment_driver_load_cnt);
  147. int cnss_utils_get_driver_load_cnt(struct device *dev)
  148. {
  149. struct cnss_utils_priv *priv = cnss_utils_priv;
  150. if (!priv)
  151. return -EINVAL;
  152. return priv->driver_load_cnt;
  153. }
  154. EXPORT_SYMBOL(cnss_utils_get_driver_load_cnt);
  155. static int set_wlan_mac_address(const u8 *mac_list, const uint32_t len,
  156. enum mac_type type)
  157. {
  158. struct cnss_utils_priv *priv = cnss_utils_priv;
  159. u32 no_of_mac_addr;
  160. struct cnss_wlan_mac_addr *addr = NULL;
  161. int iter;
  162. u8 *temp = NULL;
  163. if (!priv)
  164. return -EINVAL;
  165. if (len == 0 || (len % ETH_ALEN) != 0) {
  166. pr_err("Invalid length %d\n", len);
  167. return -EINVAL;
  168. }
  169. no_of_mac_addr = len / ETH_ALEN;
  170. if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
  171. pr_err("Exceed maximum supported MAC address %u %u\n",
  172. MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
  173. return -EINVAL;
  174. }
  175. if (type == CNSS_MAC_PROVISIONED)
  176. addr = &priv->wlan_mac_addr;
  177. else
  178. addr = &priv->wlan_der_mac_addr;
  179. if (addr->no_of_mac_addr_set) {
  180. pr_err("WLAN MAC address is already set, num %d type %d\n",
  181. addr->no_of_mac_addr_set, type);
  182. return 0;
  183. }
  184. addr->no_of_mac_addr_set = no_of_mac_addr;
  185. temp = &addr->mac_addr[0][0];
  186. for (iter = 0; iter < no_of_mac_addr;
  187. ++iter, temp += ETH_ALEN, mac_list += ETH_ALEN) {
  188. ether_addr_copy(temp, mac_list);
  189. pr_debug("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
  190. temp[0], temp[1], temp[2],
  191. temp[3], temp[4], temp[5]);
  192. }
  193. return 0;
  194. }
  195. int cnss_utils_set_wlan_mac_address(const u8 *mac_list, const uint32_t len)
  196. {
  197. return set_wlan_mac_address(mac_list, len, CNSS_MAC_PROVISIONED);
  198. }
  199. EXPORT_SYMBOL(cnss_utils_set_wlan_mac_address);
  200. int cnss_utils_set_wlan_derived_mac_address(const u8 *mac_list,
  201. const uint32_t len)
  202. {
  203. return set_wlan_mac_address(mac_list, len, CNSS_MAC_DERIVED);
  204. }
  205. EXPORT_SYMBOL(cnss_utils_set_wlan_derived_mac_address);
  206. static u8 *get_wlan_mac_address(struct device *dev,
  207. u32 *num, enum mac_type type)
  208. {
  209. struct cnss_utils_priv *priv = cnss_utils_priv;
  210. struct cnss_wlan_mac_addr *addr = NULL;
  211. if (!priv)
  212. goto out;
  213. if (type == CNSS_MAC_PROVISIONED)
  214. addr = &priv->wlan_mac_addr;
  215. else
  216. addr = &priv->wlan_der_mac_addr;
  217. if (!addr->no_of_mac_addr_set) {
  218. pr_err("WLAN MAC address is not set, type %d\n", type);
  219. goto out;
  220. }
  221. *num = addr->no_of_mac_addr_set;
  222. return &addr->mac_addr[0][0];
  223. out:
  224. *num = 0;
  225. return NULL;
  226. }
  227. u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num)
  228. {
  229. return get_wlan_mac_address(dev, num, CNSS_MAC_PROVISIONED);
  230. }
  231. EXPORT_SYMBOL(cnss_utils_get_wlan_mac_address);
  232. u8 *cnss_utils_get_wlan_derived_mac_address(struct device *dev,
  233. uint32_t *num)
  234. {
  235. return get_wlan_mac_address(dev, num, CNSS_MAC_DERIVED);
  236. }
  237. EXPORT_SYMBOL(cnss_utils_get_wlan_derived_mac_address);
  238. void cnss_utils_set_cc_source(struct device *dev,
  239. enum cnss_utils_cc_src cc_source)
  240. {
  241. struct cnss_utils_priv *priv = cnss_utils_priv;
  242. if (!priv)
  243. return;
  244. priv->cc_source = cc_source;
  245. }
  246. EXPORT_SYMBOL(cnss_utils_set_cc_source);
  247. enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev)
  248. {
  249. struct cnss_utils_priv *priv = cnss_utils_priv;
  250. if (!priv)
  251. return -EINVAL;
  252. return priv->cc_source;
  253. }
  254. EXPORT_SYMBOL(cnss_utils_get_cc_source);
  255. static ssize_t cnss_utils_mac_write(struct file *fp,
  256. const char __user *user_buf,
  257. size_t count, loff_t *off)
  258. {
  259. struct cnss_utils_priv *priv =
  260. ((struct seq_file *)fp->private_data)->private;
  261. char buf[128];
  262. char *input, *mac_type, *mac_address;
  263. u8 *dest_mac;
  264. u8 val;
  265. const char *delim = "\n";
  266. size_t len = 0;
  267. char temp[3] = "";
  268. len = min_t(size_t, count, sizeof(buf) - 1);
  269. if (copy_from_user(buf, user_buf, len))
  270. return -EINVAL;
  271. buf[len] = '\0';
  272. input = buf;
  273. mac_type = strsep(&input, delim);
  274. if (!mac_type)
  275. return -EINVAL;
  276. if (!input)
  277. return -EINVAL;
  278. mac_address = strsep(&input, delim);
  279. if (!mac_address)
  280. return -EINVAL;
  281. if (strcmp("0x", mac_address)) {
  282. pr_err("Invalid MAC prefix\n");
  283. return -EINVAL;
  284. }
  285. len = strlen(mac_address);
  286. mac_address += MAC_PREFIX_LEN;
  287. len -= MAC_PREFIX_LEN;
  288. if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR ||
  289. len % (ETH_ALEN * 2) != 0) {
  290. pr_err("Invalid MAC address length %zu\n", len);
  291. return -EINVAL;
  292. }
  293. if (!strcmp("provisioned", mac_type)) {
  294. dest_mac = &priv->wlan_mac_addr.mac_addr[0][0];
  295. priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2);
  296. } else if (!strcmp("derived", mac_type)) {
  297. dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0];
  298. priv->wlan_der_mac_addr.no_of_mac_addr_set =
  299. len / (ETH_ALEN * 2);
  300. } else {
  301. pr_err("Invalid MAC address type %s\n", mac_type);
  302. return -EINVAL;
  303. }
  304. while (len--) {
  305. temp[0] = *mac_address++;
  306. temp[1] = *mac_address++;
  307. if (kstrtou8(temp, 16, &val))
  308. return -EINVAL;
  309. *dest_mac++ = val;
  310. }
  311. return count;
  312. }
  313. static int cnss_utils_mac_show(struct seq_file *s, void *data)
  314. {
  315. u8 mac[6];
  316. int i;
  317. struct cnss_utils_priv *priv = s->private;
  318. struct cnss_wlan_mac_addr *addr = NULL;
  319. addr = &priv->wlan_mac_addr;
  320. if (addr->no_of_mac_addr_set) {
  321. seq_puts(s, "\nProvisioned MAC addresseses\n");
  322. for (i = 0; i < addr->no_of_mac_addr_set; i++) {
  323. ether_addr_copy(mac, addr->mac_addr[i]);
  324. seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
  325. mac[0], mac[1], mac[2],
  326. mac[3], mac[4], mac[5]);
  327. }
  328. }
  329. addr = &priv->wlan_der_mac_addr;
  330. if (addr->no_of_mac_addr_set) {
  331. seq_puts(s, "\nDerived MAC addresseses\n");
  332. for (i = 0; i < addr->no_of_mac_addr_set; i++) {
  333. ether_addr_copy(mac, addr->mac_addr[i]);
  334. seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
  335. mac[0], mac[1], mac[2],
  336. mac[3], mac[4], mac[5]);
  337. }
  338. }
  339. return 0;
  340. }
  341. static int cnss_utils_mac_open(struct inode *inode, struct file *file)
  342. {
  343. return single_open(file, cnss_utils_mac_show, inode->i_private);
  344. }
  345. static const struct file_operations cnss_utils_mac_fops = {
  346. .read = seq_read,
  347. .write = cnss_utils_mac_write,
  348. .release = single_release,
  349. .open = cnss_utils_mac_open,
  350. .owner = THIS_MODULE,
  351. .llseek = seq_lseek,
  352. };
  353. static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv)
  354. {
  355. int ret = 0;
  356. struct dentry *root_dentry;
  357. root_dentry = debugfs_create_dir("cnss_utils", NULL);
  358. if (IS_ERR(root_dentry)) {
  359. ret = PTR_ERR(root_dentry);
  360. pr_err("Unable to create debugfs %d\n", ret);
  361. goto out;
  362. }
  363. priv->root_dentry = root_dentry;
  364. debugfs_create_file("mac_address", 0600, root_dentry, priv,
  365. &cnss_utils_mac_fops);
  366. out:
  367. return ret;
  368. }
  369. /**
  370. * cnss_utils_is_valid_dt_node_found - Check if valid device tree node present
  371. *
  372. * Valid device tree node means a node with "qcom,wlan" property present and
  373. * "status" property not disabled.
  374. *
  375. * Return: true if valid device tree node found, false if not found
  376. */
  377. static bool cnss_utils_is_valid_dt_node_found(void)
  378. {
  379. struct device_node *dn = NULL;
  380. for_each_node_with_property(dn, "qcom,wlan") {
  381. if (of_device_is_available(dn))
  382. break;
  383. }
  384. if (dn)
  385. return true;
  386. return false;
  387. }
  388. static int __init cnss_utils_init(void)
  389. {
  390. struct cnss_utils_priv *priv = NULL;
  391. if (!cnss_utils_is_valid_dt_node_found())
  392. return -ENODEV;
  393. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  394. if (!priv)
  395. return -ENOMEM;
  396. priv->cc_source = CNSS_UTILS_SOURCE_CORE;
  397. mutex_init(&priv->unsafe_channel_list_lock);
  398. spin_lock_init(&priv->dfs_nol_info_lock);
  399. cnss_utils_debugfs_create(priv);
  400. cnss_utils_priv = priv;
  401. return 0;
  402. }
  403. static void __exit cnss_utils_exit(void)
  404. {
  405. kfree(cnss_utils_priv);
  406. cnss_utils_priv = NULL;
  407. }
  408. module_init(cnss_utils_init);
  409. module_exit(cnss_utils_exit);
  410. MODULE_LICENSE("GPL v2");
  411. MODULE_DESCRIPTION("CNSS Utilities Driver");