summaryrefslogtreecommitdiffstats
path: root/package/mac80211/src/wireless/sysfs.c
blob: 374d16db7315ff3ac9e60f33c9619d7d483a6ecc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * This file provides /sys/class/ieee80211/<wiphy name>/
 * and some default attributes.
 *
 * Copyright 2005-2006	Jiri Benc <jbenc@suse.cz>
 * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
 *
 * This file is GPLv2 as found in COPYING.
 */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include "sysfs.h"
#include "core.h"

static inline struct cfg80211_registered_device *dev_to_rdev(
	struct device *dev)
{
	return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
}

static ssize_t _show_index(struct device *dev, struct device_attribute *attr,
			   char *buf)
{
	return sprintf(buf, "%d\n", dev_to_rdev(dev)->idx);
}

static ssize_t _show_permaddr(struct device *dev,
			      struct device_attribute *attr,
			      char *buf)
{
	unsigned char *addr = dev_to_rdev(dev)->wiphy.perm_addr;

	return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
		       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}

static ssize_t _store_add_iface(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t len)
{
	struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
	int res;

	if (len > IFNAMSIZ)
		return -EINVAL;

	if (!rdev->ops->add_virtual_intf)
		return -ENOSYS;

	rtnl_lock();
	res = rdev->ops->add_virtual_intf(&rdev->wiphy, (char*)buf,
					  NL80211_IFTYPE_UNSPECIFIED);
	rtnl_unlock();

	return res ? res : len;
}

static ssize_t _store_remove_iface(struct device *dev,
				   struct device_attribute *attr,
				   const char *buf, size_t len)
{
	struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
	int res, ifidx;
	struct net_device *netdev;

	if (len > IFNAMSIZ)
		return -EINVAL;

	if (!rdev->ops->del_virtual_intf)
		return -ENOSYS;

	netdev = dev_get_by_name(buf);
	if (!netdev)
		return -ENODEV;
	ifidx = netdev->ifindex;
	dev_put(netdev);

	rtnl_lock();
	res = rdev->ops->del_virtual_intf(&rdev->wiphy, ifidx);
	rtnl_unlock();

	return res ? res : len;
}

static struct device_attribute ieee80211_dev_attrs[] = {
	__ATTR(index, S_IRUGO, _show_index, NULL),
	__ATTR(macaddress, S_IRUGO, _show_permaddr, NULL),
	__ATTR(add_iface, S_IWUGO, NULL, _store_add_iface),
	__ATTR(remove_iface, S_IWUGO, NULL, _store_remove_iface),
	{}
};

static void wiphy_dev_release(struct device *dev)
{
	struct cfg80211_registered_device *rdev = dev_to_rdev(dev);

	cfg80211_dev_free(rdev);
}

static int wiphy_uevent(struct device *dev, char **envp,
			int num_envp, char *buf, int size)
{
	/* TODO, we probably need stuff here */
	return 0;
}

struct class ieee80211_class = {
	.name = "ieee80211",
	.owner = THIS_MODULE,
	.dev_release = wiphy_dev_release,
	.dev_attrs = ieee80211_dev_attrs,
#ifdef CONFIG_HOTPLUG
	.dev_uevent = wiphy_uevent,
#endif
};

int wiphy_sysfs_init(void)
{
	return class_register(&ieee80211_class);
}

void wiphy_sysfs_exit(void)
{
	class_unregister(&ieee80211_class);
}