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