cnss_utils.c 13 KB

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