diff options
Diffstat (limited to 'net/mac80211/debugfs_netdev.c')
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 166 |
1 files changed, 113 insertions, 53 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 472b2039906c..355983503885 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -41,6 +41,30 @@ static ssize_t ieee80211_if_read( | |||
41 | return ret; | 41 | return ret; |
42 | } | 42 | } |
43 | 43 | ||
44 | static ssize_t ieee80211_if_write( | ||
45 | struct ieee80211_sub_if_data *sdata, | ||
46 | const char __user *userbuf, | ||
47 | size_t count, loff_t *ppos, | ||
48 | ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int)) | ||
49 | { | ||
50 | u8 *buf; | ||
51 | ssize_t ret = -ENODEV; | ||
52 | |||
53 | buf = kzalloc(count, GFP_KERNEL); | ||
54 | if (!buf) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | if (copy_from_user(buf, userbuf, count)) | ||
58 | return -EFAULT; | ||
59 | |||
60 | rtnl_lock(); | ||
61 | if (sdata->dev->reg_state == NETREG_REGISTERED) | ||
62 | ret = (*write)(sdata, buf, count); | ||
63 | rtnl_unlock(); | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
44 | #define IEEE80211_IF_FMT(name, field, format_string) \ | 68 | #define IEEE80211_IF_FMT(name, field, format_string) \ |
45 | static ssize_t ieee80211_if_fmt_##name( \ | 69 | static ssize_t ieee80211_if_fmt_##name( \ |
46 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | 70 | const struct ieee80211_sub_if_data *sdata, char *buf, \ |
@@ -71,7 +95,7 @@ static ssize_t ieee80211_if_fmt_##name( \ | |||
71 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ | 95 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ |
72 | } | 96 | } |
73 | 97 | ||
74 | #define __IEEE80211_IF_FILE(name) \ | 98 | #define __IEEE80211_IF_FILE(name, _write) \ |
75 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | 99 | static ssize_t ieee80211_if_read_##name(struct file *file, \ |
76 | char __user *userbuf, \ | 100 | char __user *userbuf, \ |
77 | size_t count, loff_t *ppos) \ | 101 | size_t count, loff_t *ppos) \ |
@@ -82,12 +106,24 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ | |||
82 | } \ | 106 | } \ |
83 | static const struct file_operations name##_ops = { \ | 107 | static const struct file_operations name##_ops = { \ |
84 | .read = ieee80211_if_read_##name, \ | 108 | .read = ieee80211_if_read_##name, \ |
109 | .write = (_write), \ | ||
85 | .open = mac80211_open_file_generic, \ | 110 | .open = mac80211_open_file_generic, \ |
86 | } | 111 | } |
87 | 112 | ||
113 | #define __IEEE80211_IF_FILE_W(name) \ | ||
114 | static ssize_t ieee80211_if_write_##name(struct file *file, \ | ||
115 | const char __user *userbuf, \ | ||
116 | size_t count, loff_t *ppos) \ | ||
117 | { \ | ||
118 | return ieee80211_if_write(file->private_data, userbuf, count, \ | ||
119 | ppos, ieee80211_if_parse_##name); \ | ||
120 | } \ | ||
121 | __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) | ||
122 | |||
123 | |||
88 | #define IEEE80211_IF_FILE(name, field, format) \ | 124 | #define IEEE80211_IF_FILE(name, field, format) \ |
89 | IEEE80211_IF_FMT_##format(name, field) \ | 125 | IEEE80211_IF_FMT_##format(name, field) \ |
90 | __IEEE80211_IF_FILE(name) | 126 | __IEEE80211_IF_FILE(name, NULL) |
91 | 127 | ||
92 | /* common attributes */ | 128 | /* common attributes */ |
93 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 129 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
@@ -99,6 +135,70 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | |||
99 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); | 135 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
100 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); | 136 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); |
101 | 137 | ||
138 | static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, | ||
139 | enum ieee80211_smps_mode smps_mode) | ||
140 | { | ||
141 | struct ieee80211_local *local = sdata->local; | ||
142 | int err; | ||
143 | |||
144 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) && | ||
145 | smps_mode == IEEE80211_SMPS_STATIC) | ||
146 | return -EINVAL; | ||
147 | |||
148 | /* auto should be dynamic if in PS mode */ | ||
149 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) && | ||
150 | (smps_mode == IEEE80211_SMPS_DYNAMIC || | ||
151 | smps_mode == IEEE80211_SMPS_AUTOMATIC)) | ||
152 | return -EINVAL; | ||
153 | |||
154 | /* supported only on managed interfaces for now */ | ||
155 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
156 | return -EOPNOTSUPP; | ||
157 | |||
158 | mutex_lock(&local->iflist_mtx); | ||
159 | err = __ieee80211_request_smps(sdata, smps_mode); | ||
160 | mutex_unlock(&local->iflist_mtx); | ||
161 | |||
162 | return err; | ||
163 | } | ||
164 | |||
165 | static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { | ||
166 | [IEEE80211_SMPS_AUTOMATIC] = "auto", | ||
167 | [IEEE80211_SMPS_OFF] = "off", | ||
168 | [IEEE80211_SMPS_STATIC] = "static", | ||
169 | [IEEE80211_SMPS_DYNAMIC] = "dynamic", | ||
170 | }; | ||
171 | |||
172 | static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, | ||
173 | char *buf, int buflen) | ||
174 | { | ||
175 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
176 | return -EOPNOTSUPP; | ||
177 | |||
178 | return snprintf(buf, buflen, "request: %s\nused: %s\n", | ||
179 | smps_modes[sdata->u.mgd.req_smps], | ||
180 | smps_modes[sdata->u.mgd.ap_smps]); | ||
181 | } | ||
182 | |||
183 | static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, | ||
184 | const char *buf, int buflen) | ||
185 | { | ||
186 | enum ieee80211_smps_mode mode; | ||
187 | |||
188 | for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) { | ||
189 | if (strncmp(buf, smps_modes[mode], buflen) == 0) { | ||
190 | int err = ieee80211_set_smps(sdata, mode); | ||
191 | if (!err) | ||
192 | return buflen; | ||
193 | return err; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | __IEEE80211_IF_FILE_W(smps); | ||
201 | |||
102 | /* AP attributes */ | 202 | /* AP attributes */ |
103 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 203 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); |
104 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); | 204 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); |
@@ -109,7 +209,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |||
109 | return scnprintf(buf, buflen, "%u\n", | 209 | return scnprintf(buf, buflen, "%u\n", |
110 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | 210 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); |
111 | } | 211 | } |
112 | __IEEE80211_IF_FILE(num_buffered_multicast); | 212 | __IEEE80211_IF_FILE(num_buffered_multicast, NULL); |
113 | 213 | ||
114 | /* WDS attributes */ | 214 | /* WDS attributes */ |
115 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 215 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
@@ -158,6 +258,10 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
158 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ | 258 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ |
159 | sdata, &name##_ops); | 259 | sdata, &name##_ops); |
160 | 260 | ||
261 | #define DEBUGFS_ADD_MODE(name, mode) \ | ||
262 | debugfs_create_file(#name, mode, sdata->debugfs.dir, \ | ||
263 | sdata, &name##_ops); | ||
264 | |||
161 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 265 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
162 | { | 266 | { |
163 | DEBUGFS_ADD(drop_unencrypted, sta); | 267 | DEBUGFS_ADD(drop_unencrypted, sta); |
@@ -167,6 +271,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |||
167 | DEBUGFS_ADD(bssid, sta); | 271 | DEBUGFS_ADD(bssid, sta); |
168 | DEBUGFS_ADD(aid, sta); | 272 | DEBUGFS_ADD(aid, sta); |
169 | DEBUGFS_ADD(capab, sta); | 273 | DEBUGFS_ADD(capab, sta); |
274 | DEBUGFS_ADD_MODE(smps, 0600); | ||
170 | } | 275 | } |
171 | 276 | ||
172 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 277 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
@@ -280,16 +385,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
280 | } | 385 | } |
281 | } | 386 | } |
282 | 387 | ||
283 | static int notif_registered; | ||
284 | |||
285 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | 388 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) |
286 | { | 389 | { |
287 | char buf[10+IFNAMSIZ]; | 390 | char buf[10+IFNAMSIZ]; |
288 | 391 | ||
289 | if (!notif_registered) | 392 | sprintf(buf, "netdev:%s", sdata->name); |
290 | return; | ||
291 | |||
292 | sprintf(buf, "netdev:%s", sdata->dev->name); | ||
293 | sdata->debugfs.dir = debugfs_create_dir(buf, | 393 | sdata->debugfs.dir = debugfs_create_dir(buf, |
294 | sdata->local->hw.wiphy->debugfsdir); | 394 | sdata->local->hw.wiphy->debugfsdir); |
295 | add_files(sdata); | 395 | add_files(sdata); |
@@ -304,58 +404,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) | |||
304 | sdata->debugfs.dir = NULL; | 404 | sdata->debugfs.dir = NULL; |
305 | } | 405 | } |
306 | 406 | ||
307 | static int netdev_notify(struct notifier_block *nb, | 407 | void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) |
308 | unsigned long state, | ||
309 | void *ndev) | ||
310 | { | 408 | { |
311 | struct net_device *dev = ndev; | ||
312 | struct dentry *dir; | 409 | struct dentry *dir; |
313 | struct ieee80211_sub_if_data *sdata; | 410 | char buf[10 + IFNAMSIZ]; |
314 | char buf[10+IFNAMSIZ]; | ||
315 | |||
316 | if (state != NETDEV_CHANGENAME) | ||
317 | return 0; | ||
318 | |||
319 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | ||
320 | return 0; | ||
321 | |||
322 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | ||
323 | return 0; | ||
324 | |||
325 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
326 | 411 | ||
327 | dir = sdata->debugfs.dir; | 412 | dir = sdata->debugfs.dir; |
328 | 413 | ||
329 | if (!dir) | 414 | if (!dir) |
330 | return 0; | 415 | return; |
331 | 416 | ||
332 | sprintf(buf, "netdev:%s", dev->name); | 417 | sprintf(buf, "netdev:%s", sdata->name); |
333 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) | 418 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) |
334 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " | 419 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " |
335 | "dir to %s\n", buf); | 420 | "dir to %s\n", buf); |
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static struct notifier_block mac80211_debugfs_netdev_notifier = { | ||
341 | .notifier_call = netdev_notify, | ||
342 | }; | ||
343 | |||
344 | void ieee80211_debugfs_netdev_init(void) | ||
345 | { | ||
346 | int err; | ||
347 | |||
348 | err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
349 | if (err) { | ||
350 | printk(KERN_ERR | ||
351 | "mac80211: failed to install netdev notifier," | ||
352 | " disabling per-netdev debugfs!\n"); | ||
353 | } else | ||
354 | notif_registered = 1; | ||
355 | } | ||
356 | |||
357 | void ieee80211_debugfs_netdev_exit(void) | ||
358 | { | ||
359 | unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | ||
360 | notif_registered = 0; | ||
361 | } | 421 | } |