diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-09-20 13:09:35 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:52:14 -0400 |
commit | 556829657397b9b05baec6691ead4e22ee8d1567 (patch) | |
tree | 44242431553e5e22c0bceaab7a06d9d7bf0dd2f6 /net/wireless/core.c | |
parent | 0800f170263d19b882e519441156c5f6ed190fc1 (diff) |
[NL80211]: add netlink interface to cfg80211
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 9771451eae21..febc33bc9c09 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <net/genetlink.h> | 16 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
18 | #include <net/wireless.h> | 18 | #include <net/wireless.h> |
19 | #include "nl80211.h" | ||
19 | #include "core.h" | 20 | #include "core.h" |
20 | #include "sysfs.h" | 21 | #include "sysfs.h" |
21 | 22 | ||
@@ -36,6 +37,146 @@ static int wiphy_counter; | |||
36 | /* for debugfs */ | 37 | /* for debugfs */ |
37 | static struct dentry *ieee80211_debugfs_dir; | 38 | static struct dentry *ieee80211_debugfs_dir; |
38 | 39 | ||
40 | /* requires cfg80211_drv_mutex to be held! */ | ||
41 | static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy) | ||
42 | { | ||
43 | struct cfg80211_registered_device *result = NULL, *drv; | ||
44 | |||
45 | list_for_each_entry(drv, &cfg80211_drv_list, list) { | ||
46 | if (drv->idx == wiphy) { | ||
47 | result = drv; | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | return result; | ||
53 | } | ||
54 | |||
55 | /* requires cfg80211_drv_mutex to be held! */ | ||
56 | static struct cfg80211_registered_device * | ||
57 | __cfg80211_drv_from_info(struct genl_info *info) | ||
58 | { | ||
59 | int ifindex; | ||
60 | struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL; | ||
61 | struct net_device *dev; | ||
62 | int err = -EINVAL; | ||
63 | |||
64 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
65 | bywiphy = cfg80211_drv_by_wiphy( | ||
66 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); | ||
67 | err = -ENODEV; | ||
68 | } | ||
69 | |||
70 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | ||
71 | ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | ||
72 | dev = dev_get_by_index(&init_net, ifindex); | ||
73 | if (dev) { | ||
74 | if (dev->ieee80211_ptr) | ||
75 | byifidx = | ||
76 | wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
77 | dev_put(dev); | ||
78 | } | ||
79 | err = -ENODEV; | ||
80 | } | ||
81 | |||
82 | if (bywiphy && byifidx) { | ||
83 | if (bywiphy != byifidx) | ||
84 | return ERR_PTR(-EINVAL); | ||
85 | else | ||
86 | return bywiphy; /* == byifidx */ | ||
87 | } | ||
88 | if (bywiphy) | ||
89 | return bywiphy; | ||
90 | |||
91 | if (byifidx) | ||
92 | return byifidx; | ||
93 | |||
94 | return ERR_PTR(err); | ||
95 | } | ||
96 | |||
97 | struct cfg80211_registered_device * | ||
98 | cfg80211_get_dev_from_info(struct genl_info *info) | ||
99 | { | ||
100 | struct cfg80211_registered_device *drv; | ||
101 | |||
102 | mutex_lock(&cfg80211_drv_mutex); | ||
103 | drv = __cfg80211_drv_from_info(info); | ||
104 | |||
105 | /* if it is not an error we grab the lock on | ||
106 | * it to assure it won't be going away while | ||
107 | * we operate on it */ | ||
108 | if (!IS_ERR(drv)) | ||
109 | mutex_lock(&drv->mtx); | ||
110 | |||
111 | mutex_unlock(&cfg80211_drv_mutex); | ||
112 | |||
113 | return drv; | ||
114 | } | ||
115 | |||
116 | struct cfg80211_registered_device * | ||
117 | cfg80211_get_dev_from_ifindex(int ifindex) | ||
118 | { | ||
119 | struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); | ||
120 | struct net_device *dev; | ||
121 | |||
122 | mutex_lock(&cfg80211_drv_mutex); | ||
123 | dev = dev_get_by_index(&init_net, ifindex); | ||
124 | if (!dev) | ||
125 | goto out; | ||
126 | if (dev->ieee80211_ptr) { | ||
127 | drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
128 | mutex_lock(&drv->mtx); | ||
129 | } else | ||
130 | drv = ERR_PTR(-ENODEV); | ||
131 | dev_put(dev); | ||
132 | out: | ||
133 | mutex_unlock(&cfg80211_drv_mutex); | ||
134 | return drv; | ||
135 | } | ||
136 | |||
137 | void cfg80211_put_dev(struct cfg80211_registered_device *drv) | ||
138 | { | ||
139 | BUG_ON(IS_ERR(drv)); | ||
140 | mutex_unlock(&drv->mtx); | ||
141 | } | ||
142 | |||
143 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | ||
144 | char *newname) | ||
145 | { | ||
146 | int idx, taken = -1, result, digits; | ||
147 | |||
148 | /* prohibit calling the thing phy%d when %d is not its number */ | ||
149 | sscanf(newname, PHY_NAME "%d%n", &idx, &taken); | ||
150 | if (taken == strlen(newname) && idx != rdev->idx) { | ||
151 | /* count number of places needed to print idx */ | ||
152 | digits = 1; | ||
153 | while (idx /= 10) | ||
154 | digits++; | ||
155 | /* | ||
156 | * deny the name if it is phy<idx> where <idx> is printed | ||
157 | * without leading zeroes. taken == strlen(newname) here | ||
158 | */ | ||
159 | if (taken == strlen(PHY_NAME) + digits) | ||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | /* this will check for collisions */ | ||
164 | result = device_rename(&rdev->wiphy.dev, newname); | ||
165 | if (result) | ||
166 | return result; | ||
167 | |||
168 | if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent, | ||
169 | rdev->wiphy.debugfsdir, | ||
170 | rdev->wiphy.debugfsdir->d_parent, | ||
171 | newname)) | ||
172 | printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", | ||
173 | newname); | ||
174 | |||
175 | nl80211_notify_dev_rename(rdev); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
39 | /* exported functions */ | 180 | /* exported functions */ |
40 | 181 | ||
41 | struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) | 182 | struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) |
@@ -204,10 +345,16 @@ static int cfg80211_init(void) | |||
204 | if (err) | 345 | if (err) |
205 | goto out_fail_notifier; | 346 | goto out_fail_notifier; |
206 | 347 | ||
348 | err = nl80211_init(); | ||
349 | if (err) | ||
350 | goto out_fail_nl80211; | ||
351 | |||
207 | ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); | 352 | ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL); |
208 | 353 | ||
209 | return 0; | 354 | return 0; |
210 | 355 | ||
356 | out_fail_nl80211: | ||
357 | unregister_netdevice_notifier(&cfg80211_netdev_notifier); | ||
211 | out_fail_notifier: | 358 | out_fail_notifier: |
212 | wiphy_sysfs_exit(); | 359 | wiphy_sysfs_exit(); |
213 | out_fail_sysfs: | 360 | out_fail_sysfs: |
@@ -218,6 +365,7 @@ subsys_initcall(cfg80211_init); | |||
218 | static void cfg80211_exit(void) | 365 | static void cfg80211_exit(void) |
219 | { | 366 | { |
220 | debugfs_remove(ieee80211_debugfs_dir); | 367 | debugfs_remove(ieee80211_debugfs_dir); |
368 | nl80211_exit(); | ||
221 | unregister_netdevice_notifier(&cfg80211_netdev_notifier); | 369 | unregister_netdevice_notifier(&cfg80211_netdev_notifier); |
222 | wiphy_sysfs_exit(); | 370 | wiphy_sysfs_exit(); |
223 | } | 371 | } |