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