From b1ab79255c539ebe740baa89f8a44ab139381e1c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 23 Apr 2012 12:50:30 -0700 Subject: mac80211: Support getting sta_info stats via ethtool. This lets ethtool print out stats related to stations connected to the interface. Does not yet get stats from the underlying driver. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'net/mac80211/cfg.c') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 70b2af2315a6..31023ca17575 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -450,6 +450,94 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); } +static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "rx_bytes", "wep_weak_iv_count", + "rx_duplicates", "rx_fragments", "rx_dropped", + "tx_packets", "tx_bytes", "tx_fragments", + "tx_filtered", "tx_retry_failed", "tx_retries", + "beacon_loss" +}; +#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) + +static int ieee80211_get_et_sset_count(struct wiphy *wiphy, + struct net_device *dev, + int sset) +{ + if (sset == ETH_SS_STATS) + return STA_STATS_LEN; + + return -EOPNOTSUPP; +} + +static void ieee80211_get_et_stats(struct wiphy *wiphy, + struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sta_info *sta; + struct ieee80211_local *local = sdata->local; + int i; + + memset(data, 0, sizeof(u64) * STA_STATS_LEN); + +#define ADD_STA_STATS(sta) \ + do { \ + data[i++] += sta->rx_packets; \ + data[i++] += sta->rx_bytes; \ + data[i++] += sta->wep_weak_iv_count; \ + data[i++] += sta->num_duplicates; \ + data[i++] += sta->rx_fragments; \ + data[i++] += sta->rx_dropped; \ + \ + data[i++] += sta->tx_packets; \ + data[i++] += sta->tx_bytes; \ + data[i++] += sta->tx_fragments; \ + data[i++] += sta->tx_filtered_count; \ + data[i++] += sta->tx_retry_failed; \ + data[i++] += sta->tx_retry_count; \ + data[i++] += sta->beacon_loss_count; \ + } while (0) + + /* For Managed stations, find the single station based on BSSID + * and use that. For interface types, iterate through all available + * stations and add stats for any station that is assigned to this + * network device. + */ + + rcu_read_lock(); + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); + if (sta && !WARN_ON(sta->sdata->dev != dev)) { + i = 0; + ADD_STA_STATS(sta); + BUG_ON(i != STA_STATS_LEN); + } + } else { + list_for_each_entry_rcu(sta, &local->sta_list, list) { + /* Make sure this station belongs to the proper dev */ + if (sta->sdata->dev != dev) + continue; + + i = 0; + ADD_STA_STATS(sta); + BUG_ON(i != STA_STATS_LEN); + } + } + + rcu_read_unlock(); +} + +static void ieee80211_get_et_strings(struct wiphy *wiphy, + struct net_device *dev, + u32 sset, u8 *data) +{ + if (sset == ETH_SS_STATS) { + int sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); + memcpy(data, *ieee80211_gstrings_sta_stats, sz_sta_stats); + } +} static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) @@ -2794,4 +2882,7 @@ struct cfg80211_ops mac80211_config_ops = { #ifdef CONFIG_PM .set_wakeup = ieee80211_set_wakeup, #endif + .get_et_sset_count = ieee80211_get_et_sset_count, + .get_et_stats = ieee80211_get_et_stats, + .get_et_strings = ieee80211_get_et_strings, }; -- cgit v1.2.3 From e352114fd62f6d568ca0cb18f589cb8df710cf02 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 23 Apr 2012 12:50:31 -0700 Subject: mac80211: Framework to get wifi-driver stats via ethtool. This adds hooks to call into the driver to get additional stats for the ethtool API. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'net/mac80211/cfg.c') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 31023ca17575..a38b26730652 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -463,10 +463,17 @@ static int ieee80211_get_et_sset_count(struct wiphy *wiphy, struct net_device *dev, int sset) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int rv = 0; + if (sset == ETH_SS_STATS) - return STA_STATS_LEN; + rv += STA_STATS_LEN; - return -EOPNOTSUPP; + rv += drv_get_et_sset_count(sdata, sset); + + if (rv == 0) + return -EOPNOTSUPP; + return rv; } static void ieee80211_get_et_stats(struct wiphy *wiphy, @@ -527,16 +534,22 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, } rcu_read_unlock(); + + drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); } static void ieee80211_get_et_strings(struct wiphy *wiphy, struct net_device *dev, u32 sset, u8 *data) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int sz_sta_stats = 0; + if (sset == ETH_SS_STATS) { - int sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); + sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); memcpy(data, *ieee80211_gstrings_sta_stats, sz_sta_stats); } + drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); } static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, -- cgit v1.2.3 From 3073a7c20cea0b7a9946fe61f09d43aa61deb9ea Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 23 Apr 2012 12:50:32 -0700 Subject: mac80211: Add more ethtools stats: survey, rates, etc The signal and noise are forced to be positive since ethtool deals in unsigned 64-bit values and this number should be human readable. This gives easy access to some of the data formerly exposed in the deprecated /proc/net/wireless file. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 8 deletions(-) (limited to 'net/mac80211/cfg.c') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a38b26730652..39b1fffb24f4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -455,7 +455,9 @@ static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { "rx_duplicates", "rx_fragments", "rx_dropped", "tx_packets", "tx_bytes", "tx_fragments", "tx_filtered", "tx_retry_failed", "tx_retries", - "beacon_loss" + "beacon_loss", "sta_state", "txrate", "rxrate", "signal", + "channel", "noise", "ch_time", "ch_time_busy", + "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" }; #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) @@ -484,7 +486,10 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; struct ieee80211_local *local = sdata->local; - int i; + struct station_info sinfo; + struct survey_info survey; + int i, q; +#define STA_STATS_SURVEY_LEN 7 memset(data, 0, sizeof(u64) * STA_STATS_LEN); @@ -516,11 +521,30 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, if (sdata->vif.type == NL80211_IFTYPE_STATION) { sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); - if (sta && !WARN_ON(sta->sdata->dev != dev)) { - i = 0; - ADD_STA_STATS(sta); - BUG_ON(i != STA_STATS_LEN); - } + + if (!(sta && !WARN_ON(sta->sdata->dev != dev))) + goto do_survey; + + i = 0; + ADD_STA_STATS(sta); + + data[i++] = sta->sta_state; + + sinfo.filled = 0; + sta_set_sinfo(sta, &sinfo); + + if (sinfo.filled | STATION_INFO_TX_BITRATE) + data[i] = 100000 * + cfg80211_calculate_bitrate(&sinfo.txrate); + i++; + if (sinfo.filled | STATION_INFO_RX_BITRATE) + data[i] = 100000 * + cfg80211_calculate_bitrate(&sinfo.rxrate); + i++; + + if (sinfo.filled | STATION_INFO_SIGNAL_AVG) + data[i] = (u8)sinfo.signal_avg; + i++; } else { list_for_each_entry_rcu(sta, &local->sta_list, list) { /* Make sure this station belongs to the proper dev */ @@ -529,12 +553,61 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, i = 0; ADD_STA_STATS(sta); - BUG_ON(i != STA_STATS_LEN); } } +do_survey: + i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; + /* Get survey stats for current channel */ + q = 0; + while (true) { + survey.filled = 0; + if (drv_get_survey(local, q, &survey) != 0) { + survey.filled = 0; + break; + } + + if (survey.channel && + (local->oper_channel->center_freq == + survey.channel->center_freq)) + break; + q++; + } + + if (survey.filled) + data[i++] = survey.channel->center_freq; + else + data[i++] = 0; + if (survey.filled & SURVEY_INFO_NOISE_DBM) + data[i++] = (u8)survey.noise; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME) + data[i++] = survey.channel_time; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) + data[i++] = survey.channel_time_busy; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) + data[i++] = survey.channel_time_ext_busy; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) + data[i++] = survey.channel_time_rx; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) + data[i++] = survey.channel_time_tx; + else + data[i++] = -1LL; + rcu_read_unlock(); + if (WARN_ON(i != STA_STATS_LEN)) + return; + drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); } -- cgit v1.2.3 From 70c33eaae79e53f9e48324736c0cb85534d3f093 Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Mon, 30 Apr 2012 14:20:32 -0700 Subject: {nl,cfg,mac}80211: Allow user to see/configure HT protection mode This patch introduces a new mesh configuration parameter "ht_opmode" and will allow user to check the current HT protection mode selected. Users could configure the protection mode by the command "iw mesh_iface set mesh_param mesh_ht_protection_mode=2". The default protection mode of mesh is set to non-HT mixed mode. Signed-off-by: Ashok Nagarajan Reviewed-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/mac80211/cfg.c') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 39b1fffb24f4..0221270c0ddf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1538,6 +1538,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, return -ENOTSUPP; conf->rssi_threshold = nconf->rssi_threshold; } + if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) { + conf->ht_opmode = nconf->ht_opmode; + sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); + } return 0; } -- cgit v1.2.3