Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * This file provides /sys/class/ieee80211/<wiphy name>/
4 : : * and some default attributes.
5 : : *
6 : : * Copyright 2005-2006 Jiri Benc <jbenc@suse.cz>
7 : : * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
8 : : */
9 : :
10 : : #include <linux/device.h>
11 : : #include <linux/module.h>
12 : : #include <linux/netdevice.h>
13 : : #include <linux/nl80211.h>
14 : : #include <linux/rtnetlink.h>
15 : : #include <net/cfg80211.h>
16 : : #include "sysfs.h"
17 : : #include "core.h"
18 : : #include "rdev-ops.h"
19 : :
20 : : static inline struct cfg80211_registered_device *dev_to_rdev(
21 : : struct device *dev)
22 : : {
23 : 0 : return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
24 : : }
25 : :
26 : : #define SHOW_FMT(name, fmt, member) \
27 : : static ssize_t name ## _show(struct device *dev, \
28 : : struct device_attribute *attr, \
29 : : char *buf) \
30 : : { \
31 : : return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \
32 : : } \
33 : : static DEVICE_ATTR_RO(name)
34 : :
35 : 0 : SHOW_FMT(index, "%d", wiphy_idx);
36 : 0 : SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
37 : 0 : SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
38 : :
39 : 0 : static ssize_t name_show(struct device *dev,
40 : : struct device_attribute *attr,
41 : : char *buf)
42 : : {
43 : : struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
44 : :
45 : 0 : return sprintf(buf, "%s\n", wiphy_name(wiphy));
46 : : }
47 : : static DEVICE_ATTR_RO(name);
48 : :
49 : 0 : static ssize_t addresses_show(struct device *dev,
50 : : struct device_attribute *attr,
51 : : char *buf)
52 : : {
53 : : struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
54 : : char *start = buf;
55 : : int i;
56 : :
57 [ # # ]: 0 : if (!wiphy->addresses)
58 : 0 : return sprintf(buf, "%pM\n", wiphy->perm_addr);
59 : :
60 [ # # ]: 0 : for (i = 0; i < wiphy->n_addresses; i++)
61 : 0 : buf += sprintf(buf, "%pM\n", wiphy->addresses[i].addr);
62 : :
63 : 0 : return buf - start;
64 : : }
65 : : static DEVICE_ATTR_RO(addresses);
66 : :
67 : : static struct attribute *ieee80211_attrs[] = {
68 : : &dev_attr_index.attr,
69 : : &dev_attr_macaddress.attr,
70 : : &dev_attr_address_mask.attr,
71 : : &dev_attr_addresses.attr,
72 : : &dev_attr_name.attr,
73 : : NULL,
74 : : };
75 : : ATTRIBUTE_GROUPS(ieee80211);
76 : :
77 : 0 : static void wiphy_dev_release(struct device *dev)
78 : : {
79 : : struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
80 : :
81 : 0 : cfg80211_dev_free(rdev);
82 : 0 : }
83 : :
84 : 0 : static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
85 : : {
86 : : /* TODO, we probably need stuff here */
87 : 0 : return 0;
88 : : }
89 : :
90 : : #ifdef CONFIG_PM_SLEEP
91 : : static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
92 : : {
93 : : struct wireless_dev *wdev;
94 : :
95 : : list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
96 : : cfg80211_leave(rdev, wdev);
97 : : }
98 : :
99 : : static int wiphy_suspend(struct device *dev)
100 : : {
101 : : struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
102 : : int ret = 0;
103 : :
104 : : rdev->suspend_at = ktime_get_boottime_seconds();
105 : :
106 : : rtnl_lock();
107 : : if (rdev->wiphy.registered) {
108 : : if (!rdev->wiphy.wowlan_config) {
109 : : cfg80211_leave_all(rdev);
110 : : cfg80211_process_rdev_events(rdev);
111 : : }
112 : : if (rdev->ops->suspend)
113 : : ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config);
114 : : if (ret == 1) {
115 : : /* Driver refuse to configure wowlan */
116 : : cfg80211_leave_all(rdev);
117 : : cfg80211_process_rdev_events(rdev);
118 : : ret = rdev_suspend(rdev, NULL);
119 : : }
120 : : }
121 : : rtnl_unlock();
122 : :
123 : : return ret;
124 : : }
125 : :
126 : : static int wiphy_resume(struct device *dev)
127 : : {
128 : : struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
129 : : int ret = 0;
130 : :
131 : : /* Age scan results with time spent in suspend */
132 : : cfg80211_bss_age(rdev, ktime_get_boottime_seconds() - rdev->suspend_at);
133 : :
134 : : rtnl_lock();
135 : : if (rdev->wiphy.registered && rdev->ops->resume)
136 : : ret = rdev_resume(rdev);
137 : : rtnl_unlock();
138 : :
139 : : return ret;
140 : : }
141 : :
142 : : static SIMPLE_DEV_PM_OPS(wiphy_pm_ops, wiphy_suspend, wiphy_resume);
143 : : #define WIPHY_PM_OPS (&wiphy_pm_ops)
144 : : #else
145 : : #define WIPHY_PM_OPS NULL
146 : : #endif
147 : :
148 : 0 : static const void *wiphy_namespace(struct device *d)
149 : : {
150 : : struct wiphy *wiphy = container_of(d, struct wiphy, dev);
151 : :
152 : 0 : return wiphy_net(wiphy);
153 : : }
154 : :
155 : : struct class ieee80211_class = {
156 : : .name = "ieee80211",
157 : : .owner = THIS_MODULE,
158 : : .dev_release = wiphy_dev_release,
159 : : .dev_groups = ieee80211_groups,
160 : : .dev_uevent = wiphy_uevent,
161 : : .pm = WIPHY_PM_OPS,
162 : : .ns_type = &net_ns_type_operations,
163 : : .namespace = wiphy_namespace,
164 : : };
165 : :
166 : 404 : int wiphy_sysfs_init(void)
167 : : {
168 : 404 : return class_register(&ieee80211_class);
169 : : }
170 : :
171 : 0 : void wiphy_sysfs_exit(void)
172 : : {
173 : 0 : class_unregister(&ieee80211_class);
174 : 0 : }
|