diff options
Diffstat (limited to 'net/mac80211/debugfs_netdev.c')
| -rw-r--r-- | net/mac80211/debugfs_netdev.c | 216 |
1 files changed, 140 insertions, 76 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 472b2039906c..b4ddb2f83914 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
| @@ -41,6 +41,34 @@ 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; | ||
| 52 | |||
| 53 | buf = kmalloc(count, GFP_KERNEL); | ||
| 54 | if (!buf) | ||
| 55 | return -ENOMEM; | ||
| 56 | |||
| 57 | ret = -EFAULT; | ||
| 58 | if (copy_from_user(buf, userbuf, count)) | ||
| 59 | goto freebuf; | ||
| 60 | |||
| 61 | ret = -ENODEV; | ||
| 62 | rtnl_lock(); | ||
| 63 | if (sdata->dev->reg_state == NETREG_REGISTERED) | ||
| 64 | ret = (*write)(sdata, buf, count); | ||
| 65 | rtnl_unlock(); | ||
| 66 | |||
| 67 | freebuf: | ||
| 68 | kfree(buf); | ||
| 69 | return ret; | ||
| 70 | } | ||
| 71 | |||
| 44 | #define IEEE80211_IF_FMT(name, field, format_string) \ | 72 | #define IEEE80211_IF_FMT(name, field, format_string) \ |
| 45 | static ssize_t ieee80211_if_fmt_##name( \ | 73 | static ssize_t ieee80211_if_fmt_##name( \ |
| 46 | const struct ieee80211_sub_if_data *sdata, char *buf, \ | 74 | const struct ieee80211_sub_if_data *sdata, char *buf, \ |
| @@ -71,7 +99,7 @@ static ssize_t ieee80211_if_fmt_##name( \ | |||
| 71 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ | 99 | return scnprintf(buf, buflen, "%pM\n", sdata->field); \ |
| 72 | } | 100 | } |
| 73 | 101 | ||
| 74 | #define __IEEE80211_IF_FILE(name) \ | 102 | #define __IEEE80211_IF_FILE(name, _write) \ |
| 75 | static ssize_t ieee80211_if_read_##name(struct file *file, \ | 103 | static ssize_t ieee80211_if_read_##name(struct file *file, \ |
| 76 | char __user *userbuf, \ | 104 | char __user *userbuf, \ |
| 77 | size_t count, loff_t *ppos) \ | 105 | size_t count, loff_t *ppos) \ |
| @@ -82,22 +110,99 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ | |||
| 82 | } \ | 110 | } \ |
| 83 | static const struct file_operations name##_ops = { \ | 111 | static const struct file_operations name##_ops = { \ |
| 84 | .read = ieee80211_if_read_##name, \ | 112 | .read = ieee80211_if_read_##name, \ |
| 113 | .write = (_write), \ | ||
| 85 | .open = mac80211_open_file_generic, \ | 114 | .open = mac80211_open_file_generic, \ |
| 86 | } | 115 | } |
| 87 | 116 | ||
| 117 | #define __IEEE80211_IF_FILE_W(name) \ | ||
| 118 | static ssize_t ieee80211_if_write_##name(struct file *file, \ | ||
| 119 | const char __user *userbuf, \ | ||
| 120 | size_t count, loff_t *ppos) \ | ||
| 121 | { \ | ||
| 122 | return ieee80211_if_write(file->private_data, userbuf, count, \ | ||
| 123 | ppos, ieee80211_if_parse_##name); \ | ||
| 124 | } \ | ||
| 125 | __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) | ||
| 126 | |||
| 127 | |||
| 88 | #define IEEE80211_IF_FILE(name, field, format) \ | 128 | #define IEEE80211_IF_FILE(name, field, format) \ |
| 89 | IEEE80211_IF_FMT_##format(name, field) \ | 129 | IEEE80211_IF_FMT_##format(name, field) \ |
| 90 | __IEEE80211_IF_FILE(name) | 130 | __IEEE80211_IF_FILE(name, NULL) |
| 91 | 131 | ||
| 92 | /* common attributes */ | 132 | /* common attributes */ |
| 93 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 133 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
| 94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | 134 | IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], |
| 95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 135 | HEX); |
| 136 | IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], | ||
| 137 | HEX); | ||
| 96 | 138 | ||
| 97 | /* STA attributes */ | 139 | /* STA attributes */ |
| 98 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 140 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
| 99 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); | 141 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
| 100 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); | 142 | |
| 143 | static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, | ||
| 144 | enum ieee80211_smps_mode smps_mode) | ||
| 145 | { | ||
| 146 | struct ieee80211_local *local = sdata->local; | ||
| 147 | int err; | ||
| 148 | |||
| 149 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) && | ||
| 150 | smps_mode == IEEE80211_SMPS_STATIC) | ||
| 151 | return -EINVAL; | ||
| 152 | |||
| 153 | /* auto should be dynamic if in PS mode */ | ||
| 154 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) && | ||
| 155 | (smps_mode == IEEE80211_SMPS_DYNAMIC || | ||
| 156 | smps_mode == IEEE80211_SMPS_AUTOMATIC)) | ||
| 157 | return -EINVAL; | ||
| 158 | |||
| 159 | /* supported only on managed interfaces for now */ | ||
| 160 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 161 | return -EOPNOTSUPP; | ||
| 162 | |||
| 163 | mutex_lock(&local->iflist_mtx); | ||
| 164 | err = __ieee80211_request_smps(sdata, smps_mode); | ||
| 165 | mutex_unlock(&local->iflist_mtx); | ||
| 166 | |||
| 167 | return err; | ||
| 168 | } | ||
| 169 | |||
| 170 | static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { | ||
| 171 | [IEEE80211_SMPS_AUTOMATIC] = "auto", | ||
| 172 | [IEEE80211_SMPS_OFF] = "off", | ||
| 173 | [IEEE80211_SMPS_STATIC] = "static", | ||
| 174 | [IEEE80211_SMPS_DYNAMIC] = "dynamic", | ||
| 175 | }; | ||
| 176 | |||
| 177 | static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, | ||
| 178 | char *buf, int buflen) | ||
| 179 | { | ||
| 180 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 181 | return -EOPNOTSUPP; | ||
| 182 | |||
| 183 | return snprintf(buf, buflen, "request: %s\nused: %s\n", | ||
| 184 | smps_modes[sdata->u.mgd.req_smps], | ||
| 185 | smps_modes[sdata->u.mgd.ap_smps]); | ||
| 186 | } | ||
| 187 | |||
| 188 | static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, | ||
| 189 | const char *buf, int buflen) | ||
| 190 | { | ||
| 191 | enum ieee80211_smps_mode mode; | ||
| 192 | |||
| 193 | for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) { | ||
| 194 | if (strncmp(buf, smps_modes[mode], buflen) == 0) { | ||
| 195 | int err = ieee80211_set_smps(sdata, mode); | ||
| 196 | if (!err) | ||
| 197 | return buflen; | ||
| 198 | return err; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | return -EINVAL; | ||
| 203 | } | ||
| 204 | |||
| 205 | __IEEE80211_IF_FILE_W(smps); | ||
| 101 | 206 | ||
| 102 | /* AP attributes */ | 207 | /* AP attributes */ |
| 103 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 208 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); |
| @@ -109,7 +214,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast( | |||
| 109 | return scnprintf(buf, buflen, "%u\n", | 214 | return scnprintf(buf, buflen, "%u\n", |
| 110 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | 215 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); |
| 111 | } | 216 | } |
| 112 | __IEEE80211_IF_FILE(num_buffered_multicast); | 217 | __IEEE80211_IF_FILE(num_buffered_multicast, NULL); |
| 113 | 218 | ||
| 114 | /* WDS attributes */ | 219 | /* WDS attributes */ |
| 115 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 220 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
| @@ -154,46 +259,50 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
| 154 | #endif | 259 | #endif |
| 155 | 260 | ||
| 156 | 261 | ||
| 157 | #define DEBUGFS_ADD(name, type) \ | 262 | #define DEBUGFS_ADD(name) \ |
| 158 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ | 263 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ |
| 159 | sdata, &name##_ops); | 264 | sdata, &name##_ops); |
| 160 | 265 | ||
| 266 | #define DEBUGFS_ADD_MODE(name, mode) \ | ||
| 267 | debugfs_create_file(#name, mode, sdata->debugfs.dir, \ | ||
| 268 | sdata, &name##_ops); | ||
| 269 | |||
| 161 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 270 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
| 162 | { | 271 | { |
| 163 | DEBUGFS_ADD(drop_unencrypted, sta); | 272 | DEBUGFS_ADD(drop_unencrypted); |
| 164 | DEBUGFS_ADD(force_unicast_rateidx, sta); | 273 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 165 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); | 274 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 166 | 275 | ||
| 167 | DEBUGFS_ADD(bssid, sta); | 276 | DEBUGFS_ADD(bssid); |
| 168 | DEBUGFS_ADD(aid, sta); | 277 | DEBUGFS_ADD(aid); |
| 169 | DEBUGFS_ADD(capab, sta); | 278 | DEBUGFS_ADD_MODE(smps, 0600); |
| 170 | } | 279 | } |
| 171 | 280 | ||
| 172 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 281 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
| 173 | { | 282 | { |
| 174 | DEBUGFS_ADD(drop_unencrypted, ap); | 283 | DEBUGFS_ADD(drop_unencrypted); |
| 175 | DEBUGFS_ADD(force_unicast_rateidx, ap); | 284 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 176 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | 285 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 177 | 286 | ||
| 178 | DEBUGFS_ADD(num_sta_ps, ap); | 287 | DEBUGFS_ADD(num_sta_ps); |
| 179 | DEBUGFS_ADD(dtim_count, ap); | 288 | DEBUGFS_ADD(dtim_count); |
| 180 | DEBUGFS_ADD(num_buffered_multicast, ap); | 289 | DEBUGFS_ADD(num_buffered_multicast); |
| 181 | } | 290 | } |
| 182 | 291 | ||
| 183 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 292 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
| 184 | { | 293 | { |
| 185 | DEBUGFS_ADD(drop_unencrypted, wds); | 294 | DEBUGFS_ADD(drop_unencrypted); |
| 186 | DEBUGFS_ADD(force_unicast_rateidx, wds); | 295 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 187 | DEBUGFS_ADD(max_ratectrl_rateidx, wds); | 296 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 188 | 297 | ||
| 189 | DEBUGFS_ADD(peer, wds); | 298 | DEBUGFS_ADD(peer); |
| 190 | } | 299 | } |
| 191 | 300 | ||
| 192 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | 301 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) |
| 193 | { | 302 | { |
| 194 | DEBUGFS_ADD(drop_unencrypted, vlan); | 303 | DEBUGFS_ADD(drop_unencrypted); |
| 195 | DEBUGFS_ADD(force_unicast_rateidx, vlan); | 304 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
| 196 | DEBUGFS_ADD(max_ratectrl_rateidx, vlan); | 305 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 197 | } | 306 | } |
| 198 | 307 | ||
| 199 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | 308 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) |
| @@ -280,16 +389,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
| 280 | } | 389 | } |
| 281 | } | 390 | } |
| 282 | 391 | ||
| 283 | static int notif_registered; | ||
| 284 | |||
| 285 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) | 392 | void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) |
| 286 | { | 393 | { |
| 287 | char buf[10+IFNAMSIZ]; | 394 | char buf[10+IFNAMSIZ]; |
| 288 | 395 | ||
| 289 | if (!notif_registered) | 396 | 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, | 397 | sdata->debugfs.dir = debugfs_create_dir(buf, |
| 294 | sdata->local->hw.wiphy->debugfsdir); | 398 | sdata->local->hw.wiphy->debugfsdir); |
| 295 | add_files(sdata); | 399 | add_files(sdata); |
| @@ -304,58 +408,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) | |||
| 304 | sdata->debugfs.dir = NULL; | 408 | sdata->debugfs.dir = NULL; |
| 305 | } | 409 | } |
| 306 | 410 | ||
| 307 | static int netdev_notify(struct notifier_block *nb, | 411 | void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) |
| 308 | unsigned long state, | ||
| 309 | void *ndev) | ||
| 310 | { | 412 | { |
| 311 | struct net_device *dev = ndev; | ||
| 312 | struct dentry *dir; | 413 | struct dentry *dir; |
| 313 | struct ieee80211_sub_if_data *sdata; | 414 | 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 | 415 | ||
| 327 | dir = sdata->debugfs.dir; | 416 | dir = sdata->debugfs.dir; |
| 328 | 417 | ||
| 329 | if (!dir) | 418 | if (!dir) |
| 330 | return 0; | 419 | return; |
| 331 | 420 | ||
| 332 | sprintf(buf, "netdev:%s", dev->name); | 421 | sprintf(buf, "netdev:%s", sdata->name); |
| 333 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) | 422 | if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) |
| 334 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " | 423 | printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs " |
| 335 | "dir to %s\n", buf); | 424 | "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 | } | 425 | } |
