xref: /openbmc/linux/net/mac80211/debugfs_netdev.c (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
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"
20 #include "rate.h"
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);
34 	if (sdata->dev->reg_state == NETREG_REGISTERED)
35 		ret = (*format)(sdata, buf, sizeof(buf));
36 	read_unlock(&dev_base_lock);
37 
38 	if (ret != -EINVAL)
39 		ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
40 
41 	return ret;
42 }
43 
44 #ifdef CONFIG_MAC80211_MESH
45 static ssize_t ieee80211_if_write(
46 	struct ieee80211_sub_if_data *sdata,
47 	char const __user *userbuf,
48 	size_t count, loff_t *ppos,
49 	int (*format)(struct ieee80211_sub_if_data *, char *))
50 {
51 	char buf[10];
52 	int buf_size;
53 
54 	memset(buf, 0x00, sizeof(buf));
55 	buf_size = min(count, (sizeof(buf)-1));
56 	if (copy_from_user(buf, userbuf, buf_size))
57 		return count;
58 	read_lock(&dev_base_lock);
59 	if (sdata->dev->reg_state == NETREG_REGISTERED)
60 		(*format)(sdata, buf);
61 	read_unlock(&dev_base_lock);
62 
63 	return count;
64 }
65 #endif
66 
67 #define IEEE80211_IF_FMT(name, field, format_string)			\
68 static ssize_t ieee80211_if_fmt_##name(					\
69 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
70 	int buflen)							\
71 {									\
72 	return scnprintf(buf, buflen, format_string, sdata->field);	\
73 }
74 #define IEEE80211_IF_WFMT(name, field, type)				\
75 static int ieee80211_if_wfmt_##name(					\
76 	struct ieee80211_sub_if_data *sdata, char *buf)			\
77 {									\
78 	unsigned long tmp;						\
79 	char *endp;							\
80 									\
81 	tmp = simple_strtoul(buf, &endp, 0);				\
82 	if ((endp == buf) || ((type)tmp != tmp))			\
83 		return -EINVAL;						\
84 	sdata->field = tmp;						\
85 	return 0;							\
86 }
87 #define IEEE80211_IF_FMT_DEC(name, field)				\
88 		IEEE80211_IF_FMT(name, field, "%d\n")
89 #define IEEE80211_IF_FMT_HEX(name, field)				\
90 		IEEE80211_IF_FMT(name, field, "%#x\n")
91 #define IEEE80211_IF_FMT_SIZE(name, field)				\
92 		IEEE80211_IF_FMT(name, field, "%zd\n")
93 
94 #define IEEE80211_IF_FMT_ATOMIC(name, field)				\
95 static ssize_t ieee80211_if_fmt_##name(					\
96 	const struct ieee80211_sub_if_data *sdata,			\
97 	char *buf, int buflen)						\
98 {									\
99 	return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
100 }
101 
102 #define IEEE80211_IF_FMT_MAC(name, field)				\
103 static ssize_t ieee80211_if_fmt_##name(					\
104 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
105 	int buflen)							\
106 {									\
107 	DECLARE_MAC_BUF(mac);						\
108 	return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\
109 }
110 
111 #define __IEEE80211_IF_FILE(name)					\
112 static ssize_t ieee80211_if_read_##name(struct file *file,		\
113 					char __user *userbuf,		\
114 					size_t count, loff_t *ppos)	\
115 {									\
116 	return ieee80211_if_read(file->private_data,			\
117 				 userbuf, count, ppos,			\
118 				 ieee80211_if_fmt_##name);		\
119 }									\
120 static const struct file_operations name##_ops = {			\
121 	.read = ieee80211_if_read_##name,				\
122 	.open = mac80211_open_file_generic,				\
123 }
124 
125 #define IEEE80211_IF_FILE(name, field, format)				\
126 		IEEE80211_IF_FMT_##format(name, field)			\
127 		__IEEE80211_IF_FILE(name)
128 
129 #define __IEEE80211_IF_WFILE(name)					\
130 static ssize_t ieee80211_if_read_##name(struct file *file,		\
131 					char __user *userbuf,		\
132 					size_t count, loff_t *ppos)	\
133 {									\
134 	return ieee80211_if_read(file->private_data,			\
135 				 userbuf, count, ppos,			\
136 				 ieee80211_if_fmt_##name);		\
137 }									\
138 static ssize_t ieee80211_if_write_##name(struct file *file,		\
139 					const char __user *userbuf,	\
140 					size_t count, loff_t *ppos)	\
141 {									\
142 	return ieee80211_if_write(file->private_data,			\
143 				 userbuf, count, ppos,			\
144 				 ieee80211_if_wfmt_##name);		\
145 }									\
146 static const struct file_operations name##_ops = {			\
147 	.read = ieee80211_if_read_##name,				\
148 	.write = ieee80211_if_write_##name,				\
149 	.open = mac80211_open_file_generic,				\
150 }
151 
152 #define IEEE80211_IF_WFILE(name, field, format, type)			\
153 		IEEE80211_IF_FMT_##format(name, field)			\
154 		IEEE80211_IF_WFMT(name, field, type)			\
155 		__IEEE80211_IF_WFILE(name)
156 
157 /* common attributes */
158 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
159 IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
160 IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
161 
162 /* STA/IBSS attributes */
163 IEEE80211_IF_FILE(state, u.sta.state, DEC);
164 IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC);
165 IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC);
166 IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE);
167 IEEE80211_IF_FILE(aid, u.sta.aid, DEC);
168 IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX);
169 IEEE80211_IF_FILE(capab, u.sta.capab, HEX);
170 IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE);
171 IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC);
172 IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
173 IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
174 IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
175 IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
176 
177 static ssize_t ieee80211_if_fmt_flags(
178 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
179 {
180 	return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
181 		 sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
182 		 sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
183 		 sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
184 		 sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
185 		 sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
186 		 sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
187 		 sdata->bss_conf.use_cts_prot ? "CTS prot\n" : "");
188 }
189 __IEEE80211_IF_FILE(flags);
190 
191 /* AP attributes */
192 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
193 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
194 
195 static ssize_t ieee80211_if_fmt_num_buffered_multicast(
196 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
197 {
198 	return scnprintf(buf, buflen, "%u\n",
199 			 skb_queue_len(&sdata->u.ap.ps_bc_buf));
200 }
201 __IEEE80211_IF_FILE(num_buffered_multicast);
202 
203 /* WDS attributes */
204 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
205 
206 #ifdef CONFIG_MAC80211_MESH
207 /* Mesh stats attributes */
208 IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
209 IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
210 IEEE80211_IF_FILE(dropped_frames_no_route,
211 		u.mesh.mshstats.dropped_frames_no_route, DEC);
212 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
213 
214 /* Mesh parameters */
215 IEEE80211_IF_WFILE(dot11MeshMaxRetries,
216 		u.mesh.mshcfg.dot11MeshMaxRetries, DEC, u8);
217 IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
218 		u.mesh.mshcfg.dot11MeshRetryTimeout, DEC, u16);
219 IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
220 		u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
221 IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
222 		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
223 IEEE80211_IF_WFILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC, u8);
224 IEEE80211_IF_WFILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC, u8);
225 IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
226 		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
227 IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
228 		u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
229 IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
230 		u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
231 IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
232 		u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
233 IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
234 		u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
235 IEEE80211_IF_WFILE(path_refresh_time,
236 		u.mesh.mshcfg.path_refresh_time, DEC, u32);
237 IEEE80211_IF_WFILE(min_discovery_timeout,
238 		u.mesh.mshcfg.min_discovery_timeout, DEC, u16);
239 #endif
240 
241 
242 #define DEBUGFS_ADD(name, type)\
243 	sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\
244 		sdata->debugfsdir, sdata, &name##_ops);
245 
246 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
247 {
248 	DEBUGFS_ADD(drop_unencrypted, sta);
249 	DEBUGFS_ADD(force_unicast_rateidx, sta);
250 	DEBUGFS_ADD(max_ratectrl_rateidx, sta);
251 
252 	DEBUGFS_ADD(state, sta);
253 	DEBUGFS_ADD(bssid, sta);
254 	DEBUGFS_ADD(prev_bssid, sta);
255 	DEBUGFS_ADD(ssid_len, sta);
256 	DEBUGFS_ADD(aid, sta);
257 	DEBUGFS_ADD(ap_capab, sta);
258 	DEBUGFS_ADD(capab, sta);
259 	DEBUGFS_ADD(extra_ie_len, sta);
260 	DEBUGFS_ADD(auth_tries, sta);
261 	DEBUGFS_ADD(assoc_tries, sta);
262 	DEBUGFS_ADD(auth_algs, sta);
263 	DEBUGFS_ADD(auth_alg, sta);
264 	DEBUGFS_ADD(auth_transaction, sta);
265 	DEBUGFS_ADD(flags, sta);
266 }
267 
268 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
269 {
270 	DEBUGFS_ADD(drop_unencrypted, ap);
271 	DEBUGFS_ADD(force_unicast_rateidx, ap);
272 	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
273 
274 	DEBUGFS_ADD(num_sta_ps, ap);
275 	DEBUGFS_ADD(dtim_count, ap);
276 	DEBUGFS_ADD(num_buffered_multicast, ap);
277 }
278 
279 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
280 {
281 	DEBUGFS_ADD(drop_unencrypted, wds);
282 	DEBUGFS_ADD(force_unicast_rateidx, wds);
283 	DEBUGFS_ADD(max_ratectrl_rateidx, wds);
284 
285 	DEBUGFS_ADD(peer, wds);
286 }
287 
288 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
289 {
290 	DEBUGFS_ADD(drop_unencrypted, vlan);
291 	DEBUGFS_ADD(force_unicast_rateidx, vlan);
292 	DEBUGFS_ADD(max_ratectrl_rateidx, vlan);
293 }
294 
295 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
296 {
297 }
298 
299 #ifdef CONFIG_MAC80211_MESH
300 #define MESHSTATS_ADD(name)\
301 	sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\
302 		sdata->mesh_stats_dir, sdata, &name##_ops);
303 
304 static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
305 {
306 	sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
307 				sdata->debugfsdir);
308 	MESHSTATS_ADD(fwded_frames);
309 	MESHSTATS_ADD(dropped_frames_ttl);
310 	MESHSTATS_ADD(dropped_frames_no_route);
311 	MESHSTATS_ADD(estab_plinks);
312 }
313 
314 #define MESHPARAMS_ADD(name)\
315 	sdata->mesh_config.name = debugfs_create_file(#name, 0600,\
316 		sdata->mesh_config_dir, sdata, &name##_ops);
317 
318 static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
319 {
320 	sdata->mesh_config_dir = debugfs_create_dir("mesh_config",
321 				sdata->debugfsdir);
322 	MESHPARAMS_ADD(dot11MeshMaxRetries);
323 	MESHPARAMS_ADD(dot11MeshRetryTimeout);
324 	MESHPARAMS_ADD(dot11MeshConfirmTimeout);
325 	MESHPARAMS_ADD(dot11MeshHoldingTimeout);
326 	MESHPARAMS_ADD(dot11MeshTTL);
327 	MESHPARAMS_ADD(auto_open_plinks);
328 	MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
329 	MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
330 	MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
331 	MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
332 	MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
333 	MESHPARAMS_ADD(path_refresh_time);
334 	MESHPARAMS_ADD(min_discovery_timeout);
335 }
336 #endif
337 
338 static void add_files(struct ieee80211_sub_if_data *sdata)
339 {
340 	if (!sdata->debugfsdir)
341 		return;
342 
343 	switch (sdata->vif.type) {
344 	case NL80211_IFTYPE_MESH_POINT:
345 #ifdef CONFIG_MAC80211_MESH
346 		add_mesh_stats(sdata);
347 		add_mesh_config(sdata);
348 #endif
349 		break;
350 	case NL80211_IFTYPE_STATION:
351 	case NL80211_IFTYPE_ADHOC:
352 		add_sta_files(sdata);
353 		break;
354 	case NL80211_IFTYPE_AP:
355 		add_ap_files(sdata);
356 		break;
357 	case NL80211_IFTYPE_WDS:
358 		add_wds_files(sdata);
359 		break;
360 	case NL80211_IFTYPE_MONITOR:
361 		add_monitor_files(sdata);
362 		break;
363 	case NL80211_IFTYPE_AP_VLAN:
364 		add_vlan_files(sdata);
365 		break;
366 	default:
367 		break;
368 	}
369 }
370 
371 #define DEBUGFS_DEL(name, type)					\
372 	do {							\
373 		debugfs_remove(sdata->debugfs.type.name);	\
374 		sdata->debugfs.type.name = NULL;		\
375 	} while (0)
376 
377 static void del_sta_files(struct ieee80211_sub_if_data *sdata)
378 {
379 	DEBUGFS_DEL(drop_unencrypted, sta);
380 	DEBUGFS_DEL(force_unicast_rateidx, sta);
381 	DEBUGFS_DEL(max_ratectrl_rateidx, sta);
382 
383 	DEBUGFS_DEL(state, sta);
384 	DEBUGFS_DEL(bssid, sta);
385 	DEBUGFS_DEL(prev_bssid, sta);
386 	DEBUGFS_DEL(ssid_len, sta);
387 	DEBUGFS_DEL(aid, sta);
388 	DEBUGFS_DEL(ap_capab, sta);
389 	DEBUGFS_DEL(capab, sta);
390 	DEBUGFS_DEL(extra_ie_len, sta);
391 	DEBUGFS_DEL(auth_tries, sta);
392 	DEBUGFS_DEL(assoc_tries, sta);
393 	DEBUGFS_DEL(auth_algs, sta);
394 	DEBUGFS_DEL(auth_alg, sta);
395 	DEBUGFS_DEL(auth_transaction, sta);
396 	DEBUGFS_DEL(flags, sta);
397 }
398 
399 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
400 {
401 	DEBUGFS_DEL(drop_unencrypted, ap);
402 	DEBUGFS_DEL(force_unicast_rateidx, ap);
403 	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
404 
405 	DEBUGFS_DEL(num_sta_ps, ap);
406 	DEBUGFS_DEL(dtim_count, ap);
407 	DEBUGFS_DEL(num_buffered_multicast, ap);
408 }
409 
410 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
411 {
412 	DEBUGFS_DEL(drop_unencrypted, wds);
413 	DEBUGFS_DEL(force_unicast_rateidx, wds);
414 	DEBUGFS_DEL(max_ratectrl_rateidx, wds);
415 
416 	DEBUGFS_DEL(peer, wds);
417 }
418 
419 static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
420 {
421 	DEBUGFS_DEL(drop_unencrypted, vlan);
422 	DEBUGFS_DEL(force_unicast_rateidx, vlan);
423 	DEBUGFS_DEL(max_ratectrl_rateidx, vlan);
424 }
425 
426 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
427 {
428 }
429 
430 #ifdef CONFIG_MAC80211_MESH
431 #define MESHSTATS_DEL(name)			\
432 	do {						\
433 		debugfs_remove(sdata->mesh_stats.name);	\
434 		sdata->mesh_stats.name = NULL;		\
435 	} while (0)
436 
437 static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
438 {
439 	MESHSTATS_DEL(fwded_frames);
440 	MESHSTATS_DEL(dropped_frames_ttl);
441 	MESHSTATS_DEL(dropped_frames_no_route);
442 	MESHSTATS_DEL(estab_plinks);
443 	debugfs_remove(sdata->mesh_stats_dir);
444 	sdata->mesh_stats_dir = NULL;
445 }
446 
447 #define MESHPARAMS_DEL(name)			\
448 	do {						\
449 		debugfs_remove(sdata->mesh_config.name);	\
450 		sdata->mesh_config.name = NULL;		\
451 	} while (0)
452 
453 static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
454 {
455 	MESHPARAMS_DEL(dot11MeshMaxRetries);
456 	MESHPARAMS_DEL(dot11MeshRetryTimeout);
457 	MESHPARAMS_DEL(dot11MeshConfirmTimeout);
458 	MESHPARAMS_DEL(dot11MeshHoldingTimeout);
459 	MESHPARAMS_DEL(dot11MeshTTL);
460 	MESHPARAMS_DEL(auto_open_plinks);
461 	MESHPARAMS_DEL(dot11MeshMaxPeerLinks);
462 	MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout);
463 	MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval);
464 	MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime);
465 	MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries);
466 	MESHPARAMS_DEL(path_refresh_time);
467 	MESHPARAMS_DEL(min_discovery_timeout);
468 	debugfs_remove(sdata->mesh_config_dir);
469 	sdata->mesh_config_dir = NULL;
470 }
471 #endif
472 
473 static void del_files(struct ieee80211_sub_if_data *sdata)
474 {
475 	if (!sdata->debugfsdir)
476 		return;
477 
478 	switch (sdata->vif.type) {
479 	case NL80211_IFTYPE_MESH_POINT:
480 #ifdef CONFIG_MAC80211_MESH
481 		del_mesh_stats(sdata);
482 		del_mesh_config(sdata);
483 #endif
484 		break;
485 	case NL80211_IFTYPE_STATION:
486 	case NL80211_IFTYPE_ADHOC:
487 		del_sta_files(sdata);
488 		break;
489 	case NL80211_IFTYPE_AP:
490 		del_ap_files(sdata);
491 		break;
492 	case NL80211_IFTYPE_WDS:
493 		del_wds_files(sdata);
494 		break;
495 	case NL80211_IFTYPE_MONITOR:
496 		del_monitor_files(sdata);
497 		break;
498 	case NL80211_IFTYPE_AP_VLAN:
499 		del_vlan_files(sdata);
500 		break;
501 	default:
502 		break;
503 	}
504 }
505 
506 static int notif_registered;
507 
508 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
509 {
510 	char buf[10+IFNAMSIZ];
511 
512 	if (!notif_registered)
513 		return;
514 
515 	sprintf(buf, "netdev:%s", sdata->dev->name);
516 	sdata->debugfsdir = debugfs_create_dir(buf,
517 		sdata->local->hw.wiphy->debugfsdir);
518 	add_files(sdata);
519 }
520 
521 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
522 {
523 	del_files(sdata);
524 	debugfs_remove(sdata->debugfsdir);
525 	sdata->debugfsdir = NULL;
526 }
527 
528 static int netdev_notify(struct notifier_block *nb,
529 			 unsigned long state,
530 			 void *ndev)
531 {
532 	struct net_device *dev = ndev;
533 	struct dentry *dir;
534 	struct ieee80211_sub_if_data *sdata;
535 	char buf[10+IFNAMSIZ];
536 
537 	if (state != NETDEV_CHANGENAME)
538 		return 0;
539 
540 	if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
541 		return 0;
542 
543 	if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
544 		return 0;
545 
546 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
547 
548 	dir = sdata->debugfsdir;
549 
550 	if (!dir)
551 		return 0;
552 
553 	sprintf(buf, "netdev:%s", dev->name);
554 	if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
555 		printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
556 		       "dir to %s\n", buf);
557 
558 	return 0;
559 }
560 
561 static struct notifier_block mac80211_debugfs_netdev_notifier = {
562 	.notifier_call = netdev_notify,
563 };
564 
565 void ieee80211_debugfs_netdev_init(void)
566 {
567 	int err;
568 
569 	err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
570 	if (err) {
571 		printk(KERN_ERR
572 		       "mac80211: failed to install netdev notifier,"
573 		       " disabling per-netdev debugfs!\n");
574 	} else
575 		notif_registered = 1;
576 }
577 
578 void ieee80211_debugfs_netdev_exit(void)
579 {
580 	unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
581 	notif_registered = 0;
582 }
583