13d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/* 23d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * This file implement the Wireless Extensions proc API. 33d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * 43d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> 53d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. 63d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * 73d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * (As all part of the Linux kernel, this file is GPL) 83d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg */ 93d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 103d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/* 113d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * The /proc/net/wireless file is a human readable user-space interface 123d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * exporting various wireless specific statistics from the wireless devices. 133d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * This is the most popular part of the Wireless Extensions ;-) 143d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * 153d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). 163d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * The content of the file is basically the content of "struct iw_statistics". 173d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg */ 183d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 193d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/module.h> 203d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/proc_fs.h> 213d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/seq_file.h> 223d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/wireless.h> 233d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/netdevice.h> 243d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <linux/rtnetlink.h> 253d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <net/iw_handler.h> 263d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#include <net/wext.h> 273d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 283d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 293d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic void wireless_seq_printf_stats(struct seq_file *seq, 303d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg struct net_device *dev) 313d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 323d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg /* Get stats from the driver */ 333d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg struct iw_statistics *stats = get_wireless_stats(dev); 343d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg static struct iw_statistics nullstats = {}; 353d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 363d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg /* show device if it's wireless regardless of current stats */ 373d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (!stats) { 383d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#ifdef CONFIG_WIRELESS_EXT 393d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (dev->wireless_handlers) 403d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats = &nullstats; 413d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#endif 423d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#ifdef CONFIG_CFG80211 433d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (dev->ieee80211_ptr) 443d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats = &nullstats; 453d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg#endif 463d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg } 473d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 483d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (stats) { 493d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 503d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg "%6d %6d %6d\n", 513d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg dev->name, stats->status, stats->qual.qual, 523d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->qual.updated & IW_QUAL_QUAL_UPDATED 533d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ? '.' : ' ', 543d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ((__s32) stats->qual.level) - 553d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 563d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->qual.updated & IW_QUAL_LEVEL_UPDATED 573d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ? '.' : ' ', 583d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ((__s32) stats->qual.noise) - 593d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 603d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->qual.updated & IW_QUAL_NOISE_UPDATED 613d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ? '.' : ' ', 623d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->discard.nwid, stats->discard.code, 633d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->discard.fragment, stats->discard.retries, 643d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->discard.misc, stats->miss.beacon); 653d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 663d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (stats != &nullstats) 673d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 683d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg } 693d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 703d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 713d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/* ---------------------------------------------------------------- */ 723d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg/* 733d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg * Print info for /proc/net/wireless (print all entries) 743d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg */ 753d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic int wireless_dev_seq_show(struct seq_file *seq, void *v) 763d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 773d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg might_sleep(); 783d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 793d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (v == SEQ_START_TOKEN) 803d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg seq_printf(seq, "Inter-| sta-| Quality | Discarded " 813d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg "packets | Missed | WE\n" 823d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg " face | tus | link level noise | nwid " 833d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg "crypt frag retry misc | beacon | %d\n", 843d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg WIRELESS_EXT); 853d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg else 863d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg wireless_seq_printf_stats(seq, v); 873d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return 0; 883d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 893d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 903d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) 913d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 923d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg struct net *net = seq_file_net(seq); 933d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg loff_t off; 943d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg struct net_device *dev; 953d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 963d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg rtnl_lock(); 973d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (!*pos) 983d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return SEQ_START_TOKEN; 993d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1003d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg off = 1; 1013d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg for_each_netdev(net, dev) 1023d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg if (off++ == *pos) 1033d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return dev; 1043d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return NULL; 1053d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 1063d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1073d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 1083d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 1093d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg struct net *net = seq_file_net(seq); 1103d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1113d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg ++*pos; 1123d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1133d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return v == SEQ_START_TOKEN ? 1143d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg first_net_device(net) : next_net_device(v); 1153d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 1163d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1173d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic void wireless_dev_seq_stop(struct seq_file *seq, void *v) 1183d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 1193d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg rtnl_unlock(); 1203d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 1213d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1223d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic const struct seq_operations wireless_seq_ops = { 1233d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .start = wireless_dev_seq_start, 1243d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .next = wireless_dev_seq_next, 1253d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .stop = wireless_dev_seq_stop, 1263d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .show = wireless_dev_seq_show, 1273d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}; 1283d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1293d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic int seq_open_wireless(struct inode *inode, struct file *file) 1303d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 1313d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return seq_open_net(inode, file, &wireless_seq_ops, 1323d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg sizeof(struct seq_net_private)); 1333d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 1343d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1353d23e349d807177eaf519d444677cee86b1a04cfJohannes Bergstatic const struct file_operations wireless_seq_fops = { 1363d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .owner = THIS_MODULE, 1373d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .open = seq_open_wireless, 1383d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .read = seq_read, 1393d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .llseek = seq_lseek, 1403d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg .release = seq_release_net, 1413d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg}; 1423d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1432c8c1e7297e19bdef3c178c3ea41d898a7716e3eAlexey Dobriyanint __net_init wext_proc_init(struct net *net) 1443d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 1453d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg /* Create /proc/net/wireless entry */ 146d4beaa66add8aebf83ab16d2fde4e4de8dac36dfGao feng if (!proc_create("wireless", S_IRUGO, net->proc_net, 147d4beaa66add8aebf83ab16d2fde4e4de8dac36dfGao feng &wireless_seq_fops)) 1483d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return -ENOMEM; 1493d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1503d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg return 0; 1513d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 1523d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg 1532c8c1e7297e19bdef3c178c3ea41d898a7716e3eAlexey Dobriyanvoid __net_exit wext_proc_exit(struct net *net) 1543d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg{ 155ece31ffd539e8e2b586b1ca5f50bc4f4591e3893Gao feng remove_proc_entry("wireless", net->proc_net); 1563d23e349d807177eaf519d444677cee86b1a04cfJohannes Berg} 157