linux/net/wireless/sysfs.c
<<
>>
Prefs
   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
  20static inline struct cfg80211_registered_device *dev_to_rdev(
  21        struct device *dev)
  22{
  23        return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
  24}
  25
  26#define SHOW_FMT(name, fmt, member)                                     \
  27static 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}                                                                       \
  33static DEVICE_ATTR_RO(name)
  34
  35SHOW_FMT(index, "%d", wiphy_idx);
  36SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
  37SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
  38
  39static 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        return sprintf(buf, "%s\n", wiphy_name(wiphy));
  46}
  47static DEVICE_ATTR_RO(name);
  48
  49static 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        if (!wiphy->addresses)
  58                return sprintf(buf, "%pM\n", wiphy->perm_addr);
  59
  60        for (i = 0; i < wiphy->n_addresses; i++)
  61                buf += sprintf(buf, "%pM\n", wiphy->addresses[i].addr);
  62
  63        return buf - start;
  64}
  65static DEVICE_ATTR_RO(addresses);
  66
  67static 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};
  75ATTRIBUTE_GROUPS(ieee80211);
  76
  77static void wiphy_dev_release(struct device *dev)
  78{
  79        struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
  80
  81        cfg80211_dev_free(rdev);
  82}
  83
  84static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
  85{
  86        /* TODO, we probably need stuff here */
  87        return 0;
  88}
  89
  90#ifdef CONFIG_PM_SLEEP
  91static 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
  99static 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
 126static 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
 142static 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
 148static const void *wiphy_namespace(struct device *d)
 149{
 150        struct wiphy *wiphy = container_of(d, struct wiphy, dev);
 151
 152        return wiphy_net(wiphy);
 153}
 154
 155struct 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
 166int wiphy_sysfs_init(void)
 167{
 168        return class_register(&ieee80211_class);
 169}
 170
 171void wiphy_sysfs_exit(void)
 172{
 173        class_unregister(&ieee80211_class);
 174}
 175