Commit | Line | Data |
---|---|---|
e9f207f0 JB |
1 | /* |
2 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | |
3 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/device.h> | |
12 | #include <linux/if.h> | |
13 | #include <linux/interrupt.h> | |
14 | #include <linux/netdevice.h> | |
15 | #include <linux/rtnetlink.h> | |
16 | #include <linux/notifier.h> | |
17 | #include <net/mac80211.h> | |
18 | #include <net/cfg80211.h> | |
19 | #include "ieee80211_i.h" | |
2c8dccc7 | 20 | #include "rate.h" |
e9f207f0 JB |
21 | #include "debugfs.h" |
22 | #include "debugfs_netdev.h" | |
23 | ||
24 | static ssize_t ieee80211_if_read( | |
25 | struct ieee80211_sub_if_data *sdata, | |
26 | char __user *userbuf, | |
27 | size_t count, loff_t *ppos, | |
28 | ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int)) | |
29 | { | |
30 | char buf[70]; | |
31 | ssize_t ret = -EINVAL; | |
32 | ||
33 | read_lock(&dev_base_lock); | |
73bb3e4a | 34 | if (sdata->dev->reg_state == NETREG_REGISTERED) |
e9f207f0 | 35 | ret = (*format)(sdata, buf, sizeof(buf)); |
e9f207f0 | 36 | read_unlock(&dev_base_lock); |
73bb3e4a LCC |
37 | |
38 | if (ret != -EINVAL) | |
39 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); | |
40 | ||
e9f207f0 JB |
41 | return ret; |
42 | } | |
43 | ||
44 | #define IEEE80211_IF_FMT(name, field, format_string) \ | |
45 | static ssize_t ieee80211_if_fmt_##name( \ | |
46 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | |
47 | int buflen) \ | |
48 | { \ | |
49 | return scnprintf(buf, buflen, format_string, sdata->field); \ | |
50 | } | |
51 | #define IEEE80211_IF_FMT_DEC(name, field) \ | |
52 | IEEE80211_IF_FMT(name, field, "%d\n") | |
53 | #define IEEE80211_IF_FMT_HEX(name, field) \ | |
54 | IEEE80211_IF_FMT(name, field, "%#x\n") | |
55 | #define IEEE80211_IF_FMT_SIZE(name, field) \ | |
56 | IEEE80211_IF_FMT(name, field, "%zd\n") | |
57 | ||
58 | #define IEEE80211_IF_FMT_ATOMIC(name, field) \ | |
59 | static ssize_t ieee80211_if_fmt_##name( \ | |
60 | const struct ieee80211_sub_if_data *sdata, \ | |
61 | char *buf, int buflen) \ | |
62 | { \ | |
63 | return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\ | |
64 | } | |
65 | ||
66 | #define IEEE80211_IF_FMT_MAC(name, field) \ | |
67 | static ssize_t ieee80211_if_fmt_##name( \ | |
68 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | |
69 | int buflen) \ | |
70 | { \ | |
0c68ae26 | 71 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ |
e9f207f0 JB |
72 | } |
73 | ||
74 | #define __IEEE80211_IF_FILE(name) \ | |
75 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | |
76 | char __user *userbuf, \ | |
77 | size_t count, loff_t *ppos) \ | |
78 | { \ | |
79 | return ieee80211_if_read(file->private_data, \ | |
80 | userbuf, count, ppos, \ | |
81 | ieee80211_if_fmt_##name); \ | |
82 | } \ | |
83 | static const struct file_operations name##_ops = { \ | |
84 | .read = ieee80211_if_read_##name, \ | |
85 | .open = mac80211_open_file_generic, \ | |
86 | } | |
87 | ||
88 | #define IEEE80211_IF_FILE(name, field, format) \ | |
89 | IEEE80211_IF_FMT_##format(name, field) \ | |
90 | __IEEE80211_IF_FILE(name) | |
91 | ||
92 | /* common attributes */ | |
e9f207f0 | 93 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
3e122be0 JB |
94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); |
95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | |
e9f207f0 | 96 | |
46900298 | 97 | /* STA attributes */ |
46900298 | 98 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
46900298 | 99 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
46900298 | 100 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); |
e9f207f0 JB |
101 | |
102 | /* AP attributes */ | |
103 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | |
e9f207f0 | 104 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); |
e9f207f0 JB |
105 | |
106 | static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |
107 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | |
108 | { | |
109 | return scnprintf(buf, buflen, "%u\n", | |
110 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | |
111 | } | |
112 | __IEEE80211_IF_FILE(num_buffered_multicast); | |
113 | ||
e9f207f0 JB |
114 | /* WDS attributes */ |
115 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | |
116 | ||
9f42f607 LCC |
117 | #ifdef CONFIG_MAC80211_MESH |
118 | /* Mesh stats attributes */ | |
c8a61a7d DW |
119 | IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); |
120 | IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); | |
472dbc45 JB |
121 | IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); |
122 | IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); | |
9f42f607 | 123 | IEEE80211_IF_FILE(dropped_frames_no_route, |
472dbc45 JB |
124 | u.mesh.mshstats.dropped_frames_no_route, DEC); |
125 | IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); | |
9f42f607 LCC |
126 | |
127 | /* Mesh parameters */ | |
36ff382d JB |
128 | IEEE80211_IF_FILE(dot11MeshMaxRetries, |
129 | u.mesh.mshcfg.dot11MeshMaxRetries, DEC); | |
130 | IEEE80211_IF_FILE(dot11MeshRetryTimeout, | |
131 | u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); | |
132 | IEEE80211_IF_FILE(dot11MeshConfirmTimeout, | |
133 | u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); | |
134 | IEEE80211_IF_FILE(dot11MeshHoldingTimeout, | |
135 | u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); | |
136 | IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); | |
137 | IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); | |
138 | IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, | |
139 | u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); | |
140 | IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout, | |
141 | u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); | |
142 | IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, | |
143 | u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); | |
144 | IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, | |
145 | u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); | |
146 | IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, | |
147 | u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); | |
148 | IEEE80211_IF_FILE(path_refresh_time, | |
149 | u.mesh.mshcfg.path_refresh_time, DEC); | |
150 | IEEE80211_IF_FILE(min_discovery_timeout, | |
151 | u.mesh.mshcfg.min_discovery_timeout, DEC); | |
9f42f607 LCC |
152 | #endif |
153 | ||
154 | ||
e9f207f0 | 155 | #define DEBUGFS_ADD(name, type)\ |
bebb8a5e | 156 | sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\ |
e9f207f0 JB |
157 | sdata->debugfsdir, sdata, &name##_ops); |
158 | ||
159 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |
160 | { | |
e9f207f0 | 161 | DEBUGFS_ADD(drop_unencrypted, sta); |
93015f0f JM |
162 | DEBUGFS_ADD(force_unicast_rateidx, sta); |
163 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); | |
3e122be0 | 164 | |
e9f207f0 | 165 | DEBUGFS_ADD(bssid, sta); |
e9f207f0 | 166 | DEBUGFS_ADD(aid, sta); |
e9f207f0 | 167 | DEBUGFS_ADD(capab, sta); |
e9f207f0 JB |
168 | } |
169 | ||
170 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | |
171 | { | |
e9f207f0 | 172 | DEBUGFS_ADD(drop_unencrypted, ap); |
3e122be0 JB |
173 | DEBUGFS_ADD(force_unicast_rateidx, ap); |
174 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | |
175 | ||
e9f207f0 | 176 | DEBUGFS_ADD(num_sta_ps, ap); |
e9f207f0 | 177 | DEBUGFS_ADD(dtim_count, ap); |
e9f207f0 | 178 | DEBUGFS_ADD(num_buffered_multicast, ap); |
e9f207f0 JB |
179 | } |
180 | ||
181 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | |
182 | { | |
e9f207f0 | 183 | DEBUGFS_ADD(drop_unencrypted, wds); |
93015f0f JM |
184 | DEBUGFS_ADD(force_unicast_rateidx, wds); |
185 | DEBUGFS_ADD(max_ratectrl_rateidx, wds); | |
3e122be0 | 186 | |
e9f207f0 JB |
187 | DEBUGFS_ADD(peer, wds); |
188 | } | |
189 | ||
190 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | |
191 | { | |
e9f207f0 | 192 | DEBUGFS_ADD(drop_unencrypted, vlan); |
93015f0f JM |
193 | DEBUGFS_ADD(force_unicast_rateidx, vlan); |
194 | DEBUGFS_ADD(max_ratectrl_rateidx, vlan); | |
e9f207f0 JB |
195 | } |
196 | ||
197 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | |
198 | { | |
e9f207f0 JB |
199 | } |
200 | ||
9f42f607 LCC |
201 | #ifdef CONFIG_MAC80211_MESH |
202 | #define MESHSTATS_ADD(name)\ | |
bebb8a5e | 203 | sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\ |
9f42f607 LCC |
204 | sdata->mesh_stats_dir, sdata, &name##_ops); |
205 | ||
206 | static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) | |
207 | { | |
208 | sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", | |
209 | sdata->debugfsdir); | |
c8a61a7d DW |
210 | MESHSTATS_ADD(fwded_mcast); |
211 | MESHSTATS_ADD(fwded_unicast); | |
9f42f607 LCC |
212 | MESHSTATS_ADD(fwded_frames); |
213 | MESHSTATS_ADD(dropped_frames_ttl); | |
214 | MESHSTATS_ADD(dropped_frames_no_route); | |
215 | MESHSTATS_ADD(estab_plinks); | |
216 | } | |
217 | ||
218 | #define MESHPARAMS_ADD(name)\ | |
bebb8a5e | 219 | sdata->mesh_config.name = debugfs_create_file(#name, 0600,\ |
9f42f607 LCC |
220 | sdata->mesh_config_dir, sdata, &name##_ops); |
221 | ||
222 | static void add_mesh_config(struct ieee80211_sub_if_data *sdata) | |
223 | { | |
224 | sdata->mesh_config_dir = debugfs_create_dir("mesh_config", | |
225 | sdata->debugfsdir); | |
226 | MESHPARAMS_ADD(dot11MeshMaxRetries); | |
227 | MESHPARAMS_ADD(dot11MeshRetryTimeout); | |
228 | MESHPARAMS_ADD(dot11MeshConfirmTimeout); | |
229 | MESHPARAMS_ADD(dot11MeshHoldingTimeout); | |
230 | MESHPARAMS_ADD(dot11MeshTTL); | |
231 | MESHPARAMS_ADD(auto_open_plinks); | |
232 | MESHPARAMS_ADD(dot11MeshMaxPeerLinks); | |
233 | MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); | |
234 | MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval); | |
235 | MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime); | |
236 | MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); | |
237 | MESHPARAMS_ADD(path_refresh_time); | |
238 | MESHPARAMS_ADD(min_discovery_timeout); | |
239 | } | |
240 | #endif | |
241 | ||
e9f207f0 JB |
242 | static void add_files(struct ieee80211_sub_if_data *sdata) |
243 | { | |
244 | if (!sdata->debugfsdir) | |
245 | return; | |
246 | ||
51fb61e7 | 247 | switch (sdata->vif.type) { |
05c914fe | 248 | case NL80211_IFTYPE_MESH_POINT: |
9f42f607 LCC |
249 | #ifdef CONFIG_MAC80211_MESH |
250 | add_mesh_stats(sdata); | |
251 | add_mesh_config(sdata); | |
252 | #endif | |
472dbc45 | 253 | break; |
05c914fe | 254 | case NL80211_IFTYPE_STATION: |
e9f207f0 JB |
255 | add_sta_files(sdata); |
256 | break; | |
46900298 JB |
257 | case NL80211_IFTYPE_ADHOC: |
258 | /* XXX */ | |
259 | break; | |
05c914fe | 260 | case NL80211_IFTYPE_AP: |
e9f207f0 JB |
261 | add_ap_files(sdata); |
262 | break; | |
05c914fe | 263 | case NL80211_IFTYPE_WDS: |
e9f207f0 JB |
264 | add_wds_files(sdata); |
265 | break; | |
05c914fe | 266 | case NL80211_IFTYPE_MONITOR: |
e9f207f0 JB |
267 | add_monitor_files(sdata); |
268 | break; | |
05c914fe | 269 | case NL80211_IFTYPE_AP_VLAN: |
e9f207f0 JB |
270 | add_vlan_files(sdata); |
271 | break; | |
272 | default: | |
273 | break; | |
274 | } | |
275 | } | |
276 | ||
21887b2f ZY |
277 | #define DEBUGFS_DEL(name, type) \ |
278 | do { \ | |
279 | debugfs_remove(sdata->debugfs.type.name); \ | |
280 | sdata->debugfs.type.name = NULL; \ | |
281 | } while (0) | |
e9f207f0 JB |
282 | |
283 | static void del_sta_files(struct ieee80211_sub_if_data *sdata) | |
284 | { | |
e9f207f0 | 285 | DEBUGFS_DEL(drop_unencrypted, sta); |
93015f0f JM |
286 | DEBUGFS_DEL(force_unicast_rateidx, sta); |
287 | DEBUGFS_DEL(max_ratectrl_rateidx, sta); | |
3e122be0 | 288 | |
e9f207f0 | 289 | DEBUGFS_DEL(bssid, sta); |
e9f207f0 | 290 | DEBUGFS_DEL(aid, sta); |
e9f207f0 | 291 | DEBUGFS_DEL(capab, sta); |
e9f207f0 JB |
292 | } |
293 | ||
294 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) | |
295 | { | |
e9f207f0 | 296 | DEBUGFS_DEL(drop_unencrypted, ap); |
3e122be0 JB |
297 | DEBUGFS_DEL(force_unicast_rateidx, ap); |
298 | DEBUGFS_DEL(max_ratectrl_rateidx, ap); | |
299 | ||
e9f207f0 | 300 | DEBUGFS_DEL(num_sta_ps, ap); |
e9f207f0 | 301 | DEBUGFS_DEL(dtim_count, ap); |
e9f207f0 | 302 | DEBUGFS_DEL(num_buffered_multicast, ap); |
e9f207f0 JB |
303 | } |
304 | ||
305 | static void del_wds_files(struct ieee80211_sub_if_data *sdata) | |
306 | { | |
e9f207f0 | 307 | DEBUGFS_DEL(drop_unencrypted, wds); |
93015f0f JM |
308 | DEBUGFS_DEL(force_unicast_rateidx, wds); |
309 | DEBUGFS_DEL(max_ratectrl_rateidx, wds); | |
3e122be0 | 310 | |
e9f207f0 JB |
311 | DEBUGFS_DEL(peer, wds); |
312 | } | |
313 | ||
314 | static void del_vlan_files(struct ieee80211_sub_if_data *sdata) | |
315 | { | |
e9f207f0 | 316 | DEBUGFS_DEL(drop_unencrypted, vlan); |
93015f0f JM |
317 | DEBUGFS_DEL(force_unicast_rateidx, vlan); |
318 | DEBUGFS_DEL(max_ratectrl_rateidx, vlan); | |
e9f207f0 JB |
319 | } |
320 | ||
321 | static void del_monitor_files(struct ieee80211_sub_if_data *sdata) | |
322 | { | |
e9f207f0 JB |
323 | } |
324 | ||
9f42f607 LCC |
325 | #ifdef CONFIG_MAC80211_MESH |
326 | #define MESHSTATS_DEL(name) \ | |
327 | do { \ | |
328 | debugfs_remove(sdata->mesh_stats.name); \ | |
329 | sdata->mesh_stats.name = NULL; \ | |
330 | } while (0) | |
331 | ||
332 | static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) | |
333 | { | |
c8a61a7d DW |
334 | MESHSTATS_DEL(fwded_mcast); |
335 | MESHSTATS_DEL(fwded_unicast); | |
9f42f607 LCC |
336 | MESHSTATS_DEL(fwded_frames); |
337 | MESHSTATS_DEL(dropped_frames_ttl); | |
338 | MESHSTATS_DEL(dropped_frames_no_route); | |
339 | MESHSTATS_DEL(estab_plinks); | |
340 | debugfs_remove(sdata->mesh_stats_dir); | |
341 | sdata->mesh_stats_dir = NULL; | |
342 | } | |
343 | ||
344 | #define MESHPARAMS_DEL(name) \ | |
345 | do { \ | |
346 | debugfs_remove(sdata->mesh_config.name); \ | |
347 | sdata->mesh_config.name = NULL; \ | |
348 | } while (0) | |
349 | ||
350 | static void del_mesh_config(struct ieee80211_sub_if_data *sdata) | |
351 | { | |
352 | MESHPARAMS_DEL(dot11MeshMaxRetries); | |
353 | MESHPARAMS_DEL(dot11MeshRetryTimeout); | |
354 | MESHPARAMS_DEL(dot11MeshConfirmTimeout); | |
355 | MESHPARAMS_DEL(dot11MeshHoldingTimeout); | |
356 | MESHPARAMS_DEL(dot11MeshTTL); | |
357 | MESHPARAMS_DEL(auto_open_plinks); | |
358 | MESHPARAMS_DEL(dot11MeshMaxPeerLinks); | |
359 | MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout); | |
360 | MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval); | |
361 | MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime); | |
362 | MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries); | |
363 | MESHPARAMS_DEL(path_refresh_time); | |
364 | MESHPARAMS_DEL(min_discovery_timeout); | |
365 | debugfs_remove(sdata->mesh_config_dir); | |
366 | sdata->mesh_config_dir = NULL; | |
367 | } | |
368 | #endif | |
369 | ||
75636525 | 370 | static void del_files(struct ieee80211_sub_if_data *sdata) |
e9f207f0 JB |
371 | { |
372 | if (!sdata->debugfsdir) | |
373 | return; | |
374 | ||
75636525 | 375 | switch (sdata->vif.type) { |
05c914fe | 376 | case NL80211_IFTYPE_MESH_POINT: |
9f42f607 LCC |
377 | #ifdef CONFIG_MAC80211_MESH |
378 | del_mesh_stats(sdata); | |
379 | del_mesh_config(sdata); | |
380 | #endif | |
472dbc45 | 381 | break; |
05c914fe | 382 | case NL80211_IFTYPE_STATION: |
e9f207f0 JB |
383 | del_sta_files(sdata); |
384 | break; | |
46900298 JB |
385 | case NL80211_IFTYPE_ADHOC: |
386 | /* XXX */ | |
387 | break; | |
05c914fe | 388 | case NL80211_IFTYPE_AP: |
e9f207f0 JB |
389 | del_ap_files(sdata); |
390 | break; | |
05c914fe | 391 | case NL80211_IFTYPE_WDS: |
e9f207f0 JB |
392 | del_wds_files(sdata); |
393 | break; | |
05c914fe | 394 | case NL80211_IFTYPE_MONITOR: |
e9f207f0 JB |
395 | del_monitor_files(sdata); |
396 | break; | |
05c914fe | 397 | case NL80211_IFTYPE_AP_VLAN: |
e9f207f0 JB |
398 | del_vlan_files(sdata); |
399 | break; | |
400 | default: | |
401 | break; | |
402 | } | |
403 | } | |
404 | ||
405 | static int notif_registered; | |
406 | ||
407 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | |
408 | { | |
409 | char buf[10+IFNAMSIZ]; | |
410 | ||
411 | if (!notif_registered) | |
412 | return; | |
413 | ||
414 | sprintf(buf, "netdev:%s", sdata->dev->name); | |
415 | sdata->debugfsdir = debugfs_create_dir(buf, | |
416 | sdata->local->hw.wiphy->debugfsdir); | |
75636525 | 417 | add_files(sdata); |
e9f207f0 JB |
418 | } |
419 | ||
420 | void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) | |
421 | { | |
75636525 | 422 | del_files(sdata); |
e9f207f0 JB |
423 | debugfs_remove(sdata->debugfsdir); |
424 | sdata->debugfsdir = NULL; | |
425 | } | |
426 | ||
988c0f72 | 427 | static int netdev_notify(struct notifier_block *nb, |
e9f207f0 JB |
428 | unsigned long state, |
429 | void *ndev) | |
430 | { | |
431 | struct net_device *dev = ndev; | |
7c8081eb | 432 | struct dentry *dir; |
3e122be0 | 433 | struct ieee80211_sub_if_data *sdata; |
e9f207f0 JB |
434 | char buf[10+IFNAMSIZ]; |
435 | ||
436 | if (state != NETDEV_CHANGENAME) | |
437 | return 0; | |
438 | ||
439 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | |
440 | return 0; | |
441 | ||
442 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | |
443 | return 0; | |
444 | ||
3e122be0 JB |
445 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
446 | ||
7c8081eb | 447 | dir = sdata->debugfsdir; |
c74e90a9 JB |
448 | |
449 | if (!dir) | |
450 | return 0; | |
451 | ||
452 | sprintf(buf, "netdev:%s", dev->name); | |
7c8081eb JB |
453 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) |
454 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " | |
455 | "dir to %s\n", buf); | |
e9f207f0 JB |
456 | |
457 | return 0; | |
458 | } | |
459 | ||
460 | static struct notifier_block mac80211_debugfs_netdev_notifier = { | |
461 | .notifier_call = netdev_notify, | |
462 | }; | |
463 | ||
464 | void ieee80211_debugfs_netdev_init(void) | |
465 | { | |
466 | int err; | |
467 | ||
468 | err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | |
469 | if (err) { | |
470 | printk(KERN_ERR | |
471 | "mac80211: failed to install netdev notifier," | |
472 | " disabling per-netdev debugfs!\n"); | |
473 | } else | |
474 | notif_registered = 1; | |
475 | } | |
476 | ||
477 | void ieee80211_debugfs_netdev_exit(void) | |
478 | { | |
479 | unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier); | |
480 | notif_registered = 0; | |
481 | } |