1 | /* |
2 | * This file implement the Wireless Extensions proc API. |
3 | * |
4 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> |
5 | * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. |
6 | * |
7 | * (As all part of the Linux kernel, this file is GPL) |
8 | */ |
9 | |
10 | /* |
11 | * The /proc/net/wireless file is a human readable user-space interface |
12 | * exporting various wireless specific statistics from the wireless devices. |
13 | * This is the most popular part of the Wireless Extensions ;-) |
14 | * |
15 | * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). |
16 | * The content of the file is basically the content of "struct iw_statistics". |
17 | */ |
18 | |
19 | #include <linux/module.h> |
20 | #include <linux/proc_fs.h> |
21 | #include <linux/seq_file.h> |
22 | #include <linux/wireless.h> |
23 | #include <linux/netdevice.h> |
24 | #include <linux/rtnetlink.h> |
25 | #include <net/iw_handler.h> |
26 | #include <net/wext.h> |
27 | |
28 | |
29 | static void wireless_seq_printf_stats(struct seq_file *seq, |
30 | struct net_device *dev) |
31 | { |
32 | /* Get stats from the driver */ |
33 | struct iw_statistics *stats = get_wireless_stats(dev); |
34 | static struct iw_statistics nullstats = {}; |
35 | |
36 | /* show device if it's wireless regardless of current stats */ |
37 | if (!stats) { |
38 | #ifdef CONFIG_WIRELESS_EXT |
39 | if (dev->wireless_handlers) |
40 | stats = &nullstats; |
41 | #endif |
42 | #ifdef CONFIG_CFG80211 |
43 | if (dev->ieee80211_ptr) |
44 | stats = &nullstats; |
45 | #endif |
46 | } |
47 | |
48 | if (stats) { |
49 | seq_printf(m: seq, fmt: "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " |
50 | "%6d %6d %6d\n" , |
51 | dev->name, stats->status, stats->qual.qual, |
52 | stats->qual.updated & IW_QUAL_QUAL_UPDATED |
53 | ? '.' : ' ', |
54 | ((__s32) stats->qual.level) - |
55 | ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), |
56 | stats->qual.updated & IW_QUAL_LEVEL_UPDATED |
57 | ? '.' : ' ', |
58 | ((__s32) stats->qual.noise) - |
59 | ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), |
60 | stats->qual.updated & IW_QUAL_NOISE_UPDATED |
61 | ? '.' : ' ', |
62 | stats->discard.nwid, stats->discard.code, |
63 | stats->discard.fragment, stats->discard.retries, |
64 | stats->discard.misc, stats->miss.beacon); |
65 | |
66 | if (stats != &nullstats) |
67 | stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; |
68 | } |
69 | } |
70 | |
71 | /* ---------------------------------------------------------------- */ |
72 | /* |
73 | * Print info for /proc/net/wireless (print all entries) |
74 | */ |
75 | static int wireless_dev_seq_show(struct seq_file *seq, void *v) |
76 | { |
77 | might_sleep(); |
78 | |
79 | if (v == SEQ_START_TOKEN) |
80 | seq_printf(m: seq, fmt: "Inter-| sta-| Quality | Discarded " |
81 | "packets | Missed | WE\n" |
82 | " face | tus | link level noise | nwid " |
83 | "crypt frag retry misc | beacon | %d\n" , |
84 | WIRELESS_EXT); |
85 | else |
86 | wireless_seq_printf_stats(seq, dev: v); |
87 | return 0; |
88 | } |
89 | |
90 | static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) |
91 | { |
92 | struct net *net = seq_file_net(seq); |
93 | loff_t off; |
94 | struct net_device *dev; |
95 | |
96 | rtnl_lock(); |
97 | if (!*pos) |
98 | return SEQ_START_TOKEN; |
99 | |
100 | off = 1; |
101 | for_each_netdev(net, dev) |
102 | if (off++ == *pos) |
103 | return dev; |
104 | return NULL; |
105 | } |
106 | |
107 | static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
108 | { |
109 | struct net *net = seq_file_net(seq); |
110 | |
111 | ++*pos; |
112 | |
113 | return v == SEQ_START_TOKEN ? |
114 | first_net_device(net) : next_net_device(dev: v); |
115 | } |
116 | |
117 | static void wireless_dev_seq_stop(struct seq_file *seq, void *v) |
118 | { |
119 | rtnl_unlock(); |
120 | } |
121 | |
122 | static const struct seq_operations wireless_seq_ops = { |
123 | .start = wireless_dev_seq_start, |
124 | .next = wireless_dev_seq_next, |
125 | .stop = wireless_dev_seq_stop, |
126 | .show = wireless_dev_seq_show, |
127 | }; |
128 | |
129 | int __net_init wext_proc_init(struct net *net) |
130 | { |
131 | /* Create /proc/net/wireless entry */ |
132 | if (!proc_create_net("wireless" , 0444, net->proc_net, |
133 | &wireless_seq_ops, sizeof(struct seq_net_private))) |
134 | return -ENOMEM; |
135 | |
136 | return 0; |
137 | } |
138 | |
139 | void __net_exit wext_proc_exit(struct net *net) |
140 | { |
141 | remove_proc_entry("wireless" , net->proc_net); |
142 | } |
143 | |