18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file provides /sys/class/ieee80211/<wiphy name>/ 48c2ecf20Sopenharmony_ci * and some default attributes. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2005-2006 Jiri Benc <jbenc@suse.cz> 78c2ecf20Sopenharmony_ci * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/nl80211.h> 148c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 158c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 168c2ecf20Sopenharmony_ci#include "sysfs.h" 178c2ecf20Sopenharmony_ci#include "core.h" 188c2ecf20Sopenharmony_ci#include "rdev-ops.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic inline struct cfg80211_registered_device *dev_to_rdev( 218c2ecf20Sopenharmony_ci struct device *dev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci return container_of(dev, struct cfg80211_registered_device, wiphy.dev); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define SHOW_FMT(name, fmt, member) \ 278c2ecf20Sopenharmony_cistatic ssize_t name ## _show(struct device *dev, \ 288c2ecf20Sopenharmony_ci struct device_attribute *attr, \ 298c2ecf20Sopenharmony_ci char *buf) \ 308c2ecf20Sopenharmony_ci{ \ 318c2ecf20Sopenharmony_ci return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ 328c2ecf20Sopenharmony_ci} \ 338c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciSHOW_FMT(index, "%d", wiphy_idx); 368c2ecf20Sopenharmony_ciSHOW_FMT(macaddress, "%pM", wiphy.perm_addr); 378c2ecf20Sopenharmony_ciSHOW_FMT(address_mask, "%pM", wiphy.addr_mask); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, 408c2ecf20Sopenharmony_ci struct device_attribute *attr, 418c2ecf20Sopenharmony_ci char *buf) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", wiphy_name(wiphy)); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic ssize_t addresses_show(struct device *dev, 508c2ecf20Sopenharmony_ci struct device_attribute *attr, 518c2ecf20Sopenharmony_ci char *buf) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; 548c2ecf20Sopenharmony_ci char *start = buf; 558c2ecf20Sopenharmony_ci int i; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!wiphy->addresses) 588c2ecf20Sopenharmony_ci return sprintf(buf, "%pM\n", wiphy->perm_addr); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci for (i = 0; i < wiphy->n_addresses; i++) 618c2ecf20Sopenharmony_ci buf += sprintf(buf, "%pM\n", wiphy->addresses[i].addr); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return buf - start; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(addresses); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct attribute *ieee80211_attrs[] = { 688c2ecf20Sopenharmony_ci &dev_attr_index.attr, 698c2ecf20Sopenharmony_ci &dev_attr_macaddress.attr, 708c2ecf20Sopenharmony_ci &dev_attr_address_mask.attr, 718c2ecf20Sopenharmony_ci &dev_attr_addresses.attr, 728c2ecf20Sopenharmony_ci &dev_attr_name.attr, 738c2ecf20Sopenharmony_ci NULL, 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(ieee80211); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void wiphy_dev_release(struct device *dev) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = dev_to_rdev(dev); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci cfg80211_dev_free(rdev); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci /* TODO, we probably need stuff here */ 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 918c2ecf20Sopenharmony_cistatic void cfg80211_leave_all(struct cfg80211_registered_device *rdev) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct wireless_dev *wdev; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) 968c2ecf20Sopenharmony_ci cfg80211_leave(rdev, wdev); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int wiphy_suspend(struct device *dev) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = dev_to_rdev(dev); 1028c2ecf20Sopenharmony_ci int ret = 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci rdev->suspend_at = ktime_get_boottime_seconds(); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci rtnl_lock(); 1078c2ecf20Sopenharmony_ci if (rdev->wiphy.registered) { 1088c2ecf20Sopenharmony_ci if (!rdev->wiphy.wowlan_config) { 1098c2ecf20Sopenharmony_ci cfg80211_leave_all(rdev); 1108c2ecf20Sopenharmony_ci cfg80211_process_rdev_events(rdev); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci if (rdev->ops->suspend) 1138c2ecf20Sopenharmony_ci ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); 1148c2ecf20Sopenharmony_ci if (ret == 1) { 1158c2ecf20Sopenharmony_ci /* Driver refuse to configure wowlan */ 1168c2ecf20Sopenharmony_ci cfg80211_leave_all(rdev); 1178c2ecf20Sopenharmony_ci cfg80211_process_rdev_events(rdev); 1188c2ecf20Sopenharmony_ci ret = rdev_suspend(rdev, NULL); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci rtnl_unlock(); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int wiphy_resume(struct device *dev) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = dev_to_rdev(dev); 1298c2ecf20Sopenharmony_ci int ret = 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Age scan results with time spent in suspend */ 1328c2ecf20Sopenharmony_ci cfg80211_bss_age(rdev, ktime_get_boottime_seconds() - rdev->suspend_at); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci rtnl_lock(); 1358c2ecf20Sopenharmony_ci if (rdev->wiphy.registered && rdev->ops->resume) 1368c2ecf20Sopenharmony_ci ret = rdev_resume(rdev); 1378c2ecf20Sopenharmony_ci rtnl_unlock(); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(wiphy_pm_ops, wiphy_suspend, wiphy_resume); 1438c2ecf20Sopenharmony_ci#define WIPHY_PM_OPS (&wiphy_pm_ops) 1448c2ecf20Sopenharmony_ci#else 1458c2ecf20Sopenharmony_ci#define WIPHY_PM_OPS NULL 1468c2ecf20Sopenharmony_ci#endif 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const void *wiphy_namespace(struct device *d) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct wiphy *wiphy = container_of(d, struct wiphy, dev); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return wiphy_net(wiphy); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistruct class ieee80211_class = { 1568c2ecf20Sopenharmony_ci .name = "ieee80211", 1578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1588c2ecf20Sopenharmony_ci .dev_release = wiphy_dev_release, 1598c2ecf20Sopenharmony_ci .dev_groups = ieee80211_groups, 1608c2ecf20Sopenharmony_ci .dev_uevent = wiphy_uevent, 1618c2ecf20Sopenharmony_ci .pm = WIPHY_PM_OPS, 1628c2ecf20Sopenharmony_ci .ns_type = &net_ns_type_operations, 1638c2ecf20Sopenharmony_ci .namespace = wiphy_namespace, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciint wiphy_sysfs_init(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci return class_register(&ieee80211_class); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_civoid wiphy_sysfs_exit(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci class_unregister(&ieee80211_class); 1748c2ecf20Sopenharmony_ci} 175