aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-01 15:27:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:52 -0400
commit8990646d2fafeacfacba4a4b1073a4216662089a (patch)
tree357fcf85f7e982b9f06aaac9e7c3468c6af0333f /net
parent9930380f0bd8405fa6a51d644f3de88c30666519 (diff)
cfg80211: implement get_wireless_stats
By dropping the noise reporting, we can implement wireless stats in cfg80211. We also make the handler return NULL if we have no information, which is possible thanks to the recent wext change. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/wext.c69
-rw-r--r--net/wireless/wext-compat.c59
2 files changed, 60 insertions, 68 deletions
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 244d830f5cfb..5acb8140ee58 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -165,73 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
165} 165}
166 166
167 167
168/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
169static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
170{
171 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
172 struct iw_statistics *wstats = &local->wstats;
173 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
174 struct sta_info *sta = NULL;
175
176 rcu_read_lock();
177
178 if (sdata->vif.type == NL80211_IFTYPE_STATION)
179 sta = sta_info_get(local, sdata->u.mgd.bssid);
180
181 if (!sta) {
182 wstats->discard.fragment = 0;
183 wstats->discard.misc = 0;
184 wstats->qual.qual = 0;
185 wstats->qual.level = 0;
186 wstats->qual.noise = 0;
187 wstats->qual.updated = IW_QUAL_ALL_INVALID;
188 } else {
189 wstats->qual.updated = 0;
190 /*
191 * mirror what cfg80211 does for iwrange/scan results,
192 * otherwise userspace gets confused.
193 */
194 if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
195 IEEE80211_HW_SIGNAL_DBM)) {
196 wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED;
197 wstats->qual.updated |= IW_QUAL_QUAL_UPDATED;
198 } else {
199 wstats->qual.updated |= IW_QUAL_LEVEL_INVALID;
200 wstats->qual.updated |= IW_QUAL_QUAL_INVALID;
201 }
202
203 if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
204 wstats->qual.level = sta->last_signal;
205 wstats->qual.qual = sta->last_signal;
206 } else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
207 int sig = sta->last_signal;
208
209 wstats->qual.updated |= IW_QUAL_DBM;
210 wstats->qual.level = sig;
211 if (sig < -110)
212 sig = -110;
213 else if (sig > -40)
214 sig = -40;
215 wstats->qual.qual = sig + 110;
216 }
217
218 if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
219 /*
220 * This assumes that if driver reports noise, it also
221 * reports signal in dBm.
222 */
223 wstats->qual.noise = sta->last_noise;
224 wstats->qual.updated |= IW_QUAL_NOISE_UPDATED;
225 } else {
226 wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
227 }
228 }
229
230 rcu_read_unlock();
231
232 return wstats;
233}
234
235/* Structures to export the Wireless Handlers */ 168/* Structures to export the Wireless Handlers */
236 169
237static const iw_handler ieee80211_handler[] = 170static const iw_handler ieee80211_handler[] =
@@ -298,5 +231,5 @@ const struct iw_handler_def ieee80211_iw_handler_def =
298{ 231{
299 .num_standard = ARRAY_SIZE(ieee80211_handler), 232 .num_standard = ARRAY_SIZE(ieee80211_handler),
300 .standard = (iw_handler *) ieee80211_handler, 233 .standard = (iw_handler *) ieee80211_handler,
301 .get_wireless_stats = ieee80211_get_wireless_stats, 234 .get_wireless_stats = cfg80211_wireless_stats,
302}; 235};
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 3a5f999703f1..226cf8609079 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -1156,3 +1156,62 @@ int cfg80211_wext_giwrate(struct net_device *dev,
1156 return 0; 1156 return 0;
1157} 1157}
1158EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); 1158EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate);
1159
1160/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
1161struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
1162{
1163 struct wireless_dev *wdev = dev->ieee80211_ptr;
1164 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
1165 /* we are under RTNL - globally locked - so can use static structs */
1166 static struct iw_statistics wstats;
1167 static struct station_info sinfo;
1168 u8 *addr;
1169
1170 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
1171 return NULL;
1172
1173 if (!rdev->ops->get_station)
1174 return NULL;
1175
1176 addr = wdev->wext.connect.bssid;
1177 if (!addr)
1178 return NULL;
1179
1180 if (rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo))
1181 return NULL;
1182
1183 memset(&wstats, 0, sizeof(wstats));
1184
1185 switch (rdev->wiphy.signal_type) {
1186 case CFG80211_SIGNAL_TYPE_MBM:
1187 if (sinfo.filled & STATION_INFO_SIGNAL) {
1188 int sig = sinfo.signal;
1189 wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
1190 wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
1191 wstats.qual.updated |= IW_QUAL_DBM;
1192 wstats.qual.level = sig;
1193 if (sig < -110)
1194 sig = -110;
1195 else if (sig > -40)
1196 sig = -40;
1197 wstats.qual.qual = sig + 110;
1198 break;
1199 }
1200 case CFG80211_SIGNAL_TYPE_UNSPEC:
1201 if (sinfo.filled & STATION_INFO_SIGNAL) {
1202 wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
1203 wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
1204 wstats.qual.level = sinfo.signal;
1205 wstats.qual.qual = sinfo.signal;
1206 break;
1207 }
1208 default:
1209 wstats.qual.updated |= IW_QUAL_LEVEL_INVALID;
1210 wstats.qual.updated |= IW_QUAL_QUAL_INVALID;
1211 }
1212
1213 wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
1214
1215 return &wstats;
1216}
1217EXPORT_SYMBOL_GPL(cfg80211_wireless_stats);