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 #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 { \ 71 return scnprintf(buf, buflen, "%pM\n", sdata->field); \ 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 */ 93 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); 94 IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); 95 IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); 96 97 /* STA attributes */ 98 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); 99 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); 100 IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); 101 102 /* AP attributes */ 103 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); 104 IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); 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 114 /* WDS attributes */ 115 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); 116 117 #ifdef CONFIG_MAC80211_MESH 118 /* Mesh stats attributes */ 119 IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); 120 IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); 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); 123 IEEE80211_IF_FILE(dropped_frames_no_route, 124 u.mesh.mshstats.dropped_frames_no_route, DEC); 125 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); 126 127 /* Mesh parameters */ 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); 152 IEEE80211_IF_FILE(dot11MeshHWMPRootMode, 153 u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); 154 #endif 155 156 157 #define DEBUGFS_ADD(name, type) \ 158 debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ 159 sdata, &name##_ops); 160 161 static void add_sta_files(struct ieee80211_sub_if_data *sdata) 162 { 163 DEBUGFS_ADD(drop_unencrypted, sta); 164 DEBUGFS_ADD(force_unicast_rateidx, sta); 165 DEBUGFS_ADD(max_ratectrl_rateidx, sta); 166 167 DEBUGFS_ADD(bssid, sta); 168 DEBUGFS_ADD(aid, sta); 169 DEBUGFS_ADD(capab, sta); 170 } 171 172 static void add_ap_files(struct ieee80211_sub_if_data *sdata) 173 { 174 DEBUGFS_ADD(drop_unencrypted, ap); 175 DEBUGFS_ADD(force_unicast_rateidx, ap); 176 DEBUGFS_ADD(max_ratectrl_rateidx, ap); 177 178 DEBUGFS_ADD(num_sta_ps, ap); 179 DEBUGFS_ADD(dtim_count, ap); 180 DEBUGFS_ADD(num_buffered_multicast, ap); 181 } 182 183 static void add_wds_files(struct ieee80211_sub_if_data *sdata) 184 { 185 DEBUGFS_ADD(drop_unencrypted, wds); 186 DEBUGFS_ADD(force_unicast_rateidx, wds); 187 DEBUGFS_ADD(max_ratectrl_rateidx, wds); 188 189 DEBUGFS_ADD(peer, wds); 190 } 191 192 static void add_vlan_files(struct ieee80211_sub_if_data *sdata) 193 { 194 DEBUGFS_ADD(drop_unencrypted, vlan); 195 DEBUGFS_ADD(force_unicast_rateidx, vlan); 196 DEBUGFS_ADD(max_ratectrl_rateidx, vlan); 197 } 198 199 static void add_monitor_files(struct ieee80211_sub_if_data *sdata) 200 { 201 } 202 203 #ifdef CONFIG_MAC80211_MESH 204 205 static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) 206 { 207 struct dentry *dir = debugfs_create_dir("mesh_stats", 208 sdata->debugfs.dir); 209 210 #define MESHSTATS_ADD(name)\ 211 debugfs_create_file(#name, 0400, dir, sdata, &name##_ops); 212 213 MESHSTATS_ADD(fwded_mcast); 214 MESHSTATS_ADD(fwded_unicast); 215 MESHSTATS_ADD(fwded_frames); 216 MESHSTATS_ADD(dropped_frames_ttl); 217 MESHSTATS_ADD(dropped_frames_no_route); 218 MESHSTATS_ADD(estab_plinks); 219 #undef MESHSTATS_ADD 220 } 221 222 static void add_mesh_config(struct ieee80211_sub_if_data *sdata) 223 { 224 struct dentry *dir = debugfs_create_dir("mesh_config", 225 sdata->debugfs.dir); 226 227 #define MESHPARAMS_ADD(name) \ 228 debugfs_create_file(#name, 0600, dir, sdata, &name##_ops); 229 230 MESHPARAMS_ADD(dot11MeshMaxRetries); 231 MESHPARAMS_ADD(dot11MeshRetryTimeout); 232 MESHPARAMS_ADD(dot11MeshConfirmTimeout); 233 MESHPARAMS_ADD(dot11MeshHoldingTimeout); 234 MESHPARAMS_ADD(dot11MeshTTL); 235 MESHPARAMS_ADD(auto_open_plinks); 236 MESHPARAMS_ADD(dot11MeshMaxPeerLinks); 237 MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); 238 MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval); 239 MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime); 240 MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); 241 MESHPARAMS_ADD(path_refresh_time); 242 MESHPARAMS_ADD(min_discovery_timeout); 243 244 #undef MESHPARAMS_ADD 245 } 246 #endif 247 248 static void add_files(struct ieee80211_sub_if_data *sdata) 249 { 250 if (!sdata->debugfs.dir) 251 return; 252 253 switch (sdata->vif.type) { 254 case NL80211_IFTYPE_MESH_POINT: 255 #ifdef CONFIG_MAC80211_MESH 256 add_mesh_stats(sdata); 257 add_mesh_config(sdata); 258 #endif 259 break; 260 case NL80211_IFTYPE_STATION: 261 add_sta_files(sdata); 262 break; 263 case NL80211_IFTYPE_ADHOC: 264 /* XXX */ 265 break; 266 case NL80211_IFTYPE_AP: 267 add_ap_files(sdata); 268 break; 269 case NL80211_IFTYPE_WDS: 270 add_wds_files(sdata); 271 break; 272 case NL80211_IFTYPE_MONITOR: 273 add_monitor_files(sdata); 274 break; 275 case NL80211_IFTYPE_AP_VLAN: 276 add_vlan_files(sdata); 277 break; 278 default: 279 break; 280 } 281 } 282 283 static int notif_registered; 284 285 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) 286 { 287 char buf[10+IFNAMSIZ]; 288 289 if (!notif_registered) 290 return; 291 292 sprintf(buf, "netdev:%s", sdata->dev->name); 293 sdata->debugfs.dir = debugfs_create_dir(buf, 294 sdata->local->hw.wiphy->debugfsdir); 295 add_files(sdata); 296 } 297 298 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) 299 { 300 if (!sdata->debugfs.dir) 301 return; 302 303 debugfs_remove_recursive(sdata->debugfs.dir); 304 sdata->debugfs.dir = NULL; 305 } 306 307 static int netdev_notify(struct notifier_block *nb, 308 unsigned long state, 309 void *ndev) 310 { 311 struct net_device *dev = ndev; 312 struct dentry *dir; 313 struct ieee80211_sub_if_data *sdata; 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 327 dir = sdata->debugfs.dir; 328 329 if (!dir) 330 return 0; 331 332 sprintf(buf, "netdev:%s", dev->name); 333 if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) 334 printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " 335 "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 } 362