diff options
author | Toke Høiland-Jørgensen <toke@toke.dk> | 2018-05-08 07:03:50 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2018-05-08 07:19:24 -0400 |
commit | 52539ca89f365d3db530535fbffa88a3cca4d2ec (patch) | |
tree | 5bfc75ba1383976149d0c99a3f87bb9ef69af4e8 | |
parent | cc60dbbfed8ff0bd4c530ee48e9e915333a35470 (diff) |
cfg80211: Expose TXQ stats and parameters to userspace
This adds support for exporting the mac80211 TXQ stats via nl80211 by
way of a nested TXQ stats attribute, as well as for configuring the
quantum and limits that were previously only changeable through debugfs.
This commit adds just the nl80211 API, a subsequent commit adds support to
mac80211 itself.
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/cfg80211.h | 50 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 58 | ||||
-rw-r--r-- | net/mac80211/ethtool.c | 32 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 202 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 12 | ||||
-rw-r--r-- | net/wireless/trace.h | 14 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 23 |
7 files changed, 343 insertions, 48 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5e888ec62811..8db6071b6063 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1080,6 +1080,37 @@ struct sta_bss_parameters { | |||
1080 | }; | 1080 | }; |
1081 | 1081 | ||
1082 | /** | 1082 | /** |
1083 | * struct cfg80211_txq_stats - TXQ statistics for this TID | ||
1084 | * @filled: bitmap of flags using the bits of &enum nl80211_txq_stats to | ||
1085 | * indicate the relevant values in this struct are filled | ||
1086 | * @backlog_bytes: total number of bytes currently backlogged | ||
1087 | * @backlog_packets: total number of packets currently backlogged | ||
1088 | * @flows: number of new flows seen | ||
1089 | * @drops: total number of packets dropped | ||
1090 | * @ecn_marks: total number of packets marked with ECN CE | ||
1091 | * @overlimit: number of drops due to queue space overflow | ||
1092 | * @overmemory: number of drops due to memory limit overflow | ||
1093 | * @collisions: number of hash collisions | ||
1094 | * @tx_bytes: total number of bytes dequeued | ||
1095 | * @tx_packets: total number of packets dequeued | ||
1096 | * @max_flows: maximum number of flows supported | ||
1097 | */ | ||
1098 | struct cfg80211_txq_stats { | ||
1099 | u32 filled; | ||
1100 | u32 backlog_bytes; | ||
1101 | u32 backlog_packets; | ||
1102 | u32 flows; | ||
1103 | u32 drops; | ||
1104 | u32 ecn_marks; | ||
1105 | u32 overlimit; | ||
1106 | u32 overmemory; | ||
1107 | u32 collisions; | ||
1108 | u32 tx_bytes; | ||
1109 | u32 tx_packets; | ||
1110 | u32 max_flows; | ||
1111 | }; | ||
1112 | |||
1113 | /** | ||
1083 | * struct cfg80211_tid_stats - per-TID statistics | 1114 | * struct cfg80211_tid_stats - per-TID statistics |
1084 | * @filled: bitmap of flags using the bits of &enum nl80211_tid_stats to | 1115 | * @filled: bitmap of flags using the bits of &enum nl80211_tid_stats to |
1085 | * indicate the relevant values in this struct are filled | 1116 | * indicate the relevant values in this struct are filled |
@@ -1088,6 +1119,7 @@ struct sta_bss_parameters { | |||
1088 | * @tx_msdu_retries: number of retries (not counting the first) for | 1119 | * @tx_msdu_retries: number of retries (not counting the first) for |
1089 | * transmitted MSDUs | 1120 | * transmitted MSDUs |
1090 | * @tx_msdu_failed: number of failed transmitted MSDUs | 1121 | * @tx_msdu_failed: number of failed transmitted MSDUs |
1122 | * @txq_stats: TXQ statistics | ||
1091 | */ | 1123 | */ |
1092 | struct cfg80211_tid_stats { | 1124 | struct cfg80211_tid_stats { |
1093 | u32 filled; | 1125 | u32 filled; |
@@ -1095,6 +1127,7 @@ struct cfg80211_tid_stats { | |||
1095 | u64 tx_msdu; | 1127 | u64 tx_msdu; |
1096 | u64 tx_msdu_retries; | 1128 | u64 tx_msdu_retries; |
1097 | u64 tx_msdu_failed; | 1129 | u64 tx_msdu_failed; |
1130 | struct cfg80211_txq_stats txq_stats; | ||
1098 | }; | 1131 | }; |
1099 | 1132 | ||
1100 | #define IEEE80211_MAX_CHAINS 4 | 1133 | #define IEEE80211_MAX_CHAINS 4 |
@@ -2204,6 +2237,9 @@ enum cfg80211_connect_params_changed { | |||
2204 | * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed | 2237 | * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed |
2205 | * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed | 2238 | * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed |
2206 | * @WIPHY_PARAM_DYN_ACK: dynack has been enabled | 2239 | * @WIPHY_PARAM_DYN_ACK: dynack has been enabled |
2240 | * @WIPHY_PARAM_TXQ_LIMIT: TXQ packet limit has been changed | ||
2241 | * @WIPHY_PARAM_TXQ_MEMORY_LIMIT: TXQ memory limit has been changed | ||
2242 | * @WIPHY_PARAM_TXQ_QUANTUM: TXQ scheduler quantum | ||
2207 | */ | 2243 | */ |
2208 | enum wiphy_params_flags { | 2244 | enum wiphy_params_flags { |
2209 | WIPHY_PARAM_RETRY_SHORT = 1 << 0, | 2245 | WIPHY_PARAM_RETRY_SHORT = 1 << 0, |
@@ -2212,6 +2248,9 @@ enum wiphy_params_flags { | |||
2212 | WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, | 2248 | WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, |
2213 | WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, | 2249 | WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, |
2214 | WIPHY_PARAM_DYN_ACK = 1 << 5, | 2250 | WIPHY_PARAM_DYN_ACK = 1 << 5, |
2251 | WIPHY_PARAM_TXQ_LIMIT = 1 << 6, | ||
2252 | WIPHY_PARAM_TXQ_MEMORY_LIMIT = 1 << 7, | ||
2253 | WIPHY_PARAM_TXQ_QUANTUM = 1 << 8, | ||
2215 | }; | 2254 | }; |
2216 | 2255 | ||
2217 | /** | 2256 | /** |
@@ -2964,6 +3003,9 @@ struct cfg80211_external_auth_params { | |||
2964 | * | 3003 | * |
2965 | * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS | 3004 | * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS |
2966 | * | 3005 | * |
3006 | * @get_txq_stats: Get TXQ stats for interface or phy. If wdev is %NULL, this | ||
3007 | * function should return phy stats, and interface stats otherwise. | ||
3008 | * | ||
2967 | * @set_pmk: configure the PMK to be used for offloaded 802.1X 4-Way handshake. | 3009 | * @set_pmk: configure the PMK to be used for offloaded 802.1X 4-Way handshake. |
2968 | * If not deleted through @del_pmk the PMK remains valid until disconnect | 3010 | * If not deleted through @del_pmk the PMK remains valid until disconnect |
2969 | * upon which the driver should clear it. | 3011 | * upon which the driver should clear it. |
@@ -3265,6 +3307,10 @@ struct cfg80211_ops { | |||
3265 | struct net_device *dev, | 3307 | struct net_device *dev, |
3266 | const bool enabled); | 3308 | const bool enabled); |
3267 | 3309 | ||
3310 | int (*get_txq_stats)(struct wiphy *wiphy, | ||
3311 | struct wireless_dev *wdev, | ||
3312 | struct cfg80211_txq_stats *txqstats); | ||
3313 | |||
3268 | int (*set_pmk)(struct wiphy *wiphy, struct net_device *dev, | 3314 | int (*set_pmk)(struct wiphy *wiphy, struct net_device *dev, |
3269 | const struct cfg80211_pmk_conf *conf); | 3315 | const struct cfg80211_pmk_conf *conf); |
3270 | int (*del_pmk)(struct wiphy *wiphy, struct net_device *dev, | 3316 | int (*del_pmk)(struct wiphy *wiphy, struct net_device *dev, |
@@ -3943,6 +3989,10 @@ struct wiphy { | |||
3943 | 3989 | ||
3944 | u8 nan_supported_bands; | 3990 | u8 nan_supported_bands; |
3945 | 3991 | ||
3992 | u32 txq_limit; | ||
3993 | u32 txq_memory_limit; | ||
3994 | u32 txq_quantum; | ||
3995 | |||
3946 | char priv[0] __aligned(NETDEV_ALIGN); | 3996 | char priv[0] __aligned(NETDEV_ALIGN); |
3947 | }; | 3997 | }; |
3948 | 3998 | ||
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8e55b63ed3ff..5e67e3444aba 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -2226,6 +2226,16 @@ enum nl80211_commands { | |||
2226 | * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this | 2226 | * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this |
2227 | * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. | 2227 | * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. |
2228 | * | 2228 | * |
2229 | * @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum | ||
2230 | * nl80211_txq_stats) | ||
2231 | * @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy. | ||
2232 | * The smaller of this and the memory limit is enforced. | ||
2233 | * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the | ||
2234 | * TXQ queues for this phy. The smaller of this and the packet limit is | ||
2235 | * enforced. | ||
2236 | * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes | ||
2237 | * a flow is assigned on each round of the DRR scheduler. | ||
2238 | * | ||
2229 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available | 2239 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
2230 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 2240 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
2231 | * @__NL80211_ATTR_AFTER_LAST: internal use | 2241 | * @__NL80211_ATTR_AFTER_LAST: internal use |
@@ -2660,6 +2670,11 @@ enum nl80211_attrs { | |||
2660 | 2670 | ||
2661 | NL80211_ATTR_CONTROL_PORT_OVER_NL80211, | 2671 | NL80211_ATTR_CONTROL_PORT_OVER_NL80211, |
2662 | 2672 | ||
2673 | NL80211_ATTR_TXQ_STATS, | ||
2674 | NL80211_ATTR_TXQ_LIMIT, | ||
2675 | NL80211_ATTR_TXQ_MEMORY_LIMIT, | ||
2676 | NL80211_ATTR_TXQ_QUANTUM, | ||
2677 | |||
2663 | /* add attributes here, update the policy in nl80211.c */ | 2678 | /* add attributes here, update the policy in nl80211.c */ |
2664 | 2679 | ||
2665 | __NL80211_ATTR_AFTER_LAST, | 2680 | __NL80211_ATTR_AFTER_LAST, |
@@ -3040,6 +3055,7 @@ enum nl80211_sta_info { | |||
3040 | * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted | 3055 | * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted |
3041 | * MSDUs (u64) | 3056 | * MSDUs (u64) |
3042 | * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment | 3057 | * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment |
3058 | * @NL80211_TID_STATS_TXQ_STATS: TXQ stats (nested attribute) | ||
3043 | * @NUM_NL80211_TID_STATS: number of attributes here | 3059 | * @NUM_NL80211_TID_STATS: number of attributes here |
3044 | * @NL80211_TID_STATS_MAX: highest numbered attribute here | 3060 | * @NL80211_TID_STATS_MAX: highest numbered attribute here |
3045 | */ | 3061 | */ |
@@ -3050,6 +3066,7 @@ enum nl80211_tid_stats { | |||
3050 | NL80211_TID_STATS_TX_MSDU_RETRIES, | 3066 | NL80211_TID_STATS_TX_MSDU_RETRIES, |
3051 | NL80211_TID_STATS_TX_MSDU_FAILED, | 3067 | NL80211_TID_STATS_TX_MSDU_FAILED, |
3052 | NL80211_TID_STATS_PAD, | 3068 | NL80211_TID_STATS_PAD, |
3069 | NL80211_TID_STATS_TXQ_STATS, | ||
3053 | 3070 | ||
3054 | /* keep last */ | 3071 | /* keep last */ |
3055 | NUM_NL80211_TID_STATS, | 3072 | NUM_NL80211_TID_STATS, |
@@ -3057,6 +3074,44 @@ enum nl80211_tid_stats { | |||
3057 | }; | 3074 | }; |
3058 | 3075 | ||
3059 | /** | 3076 | /** |
3077 | * enum nl80211_txq_stats - per TXQ statistics attributes | ||
3078 | * @__NL80211_TXQ_STATS_INVALID: attribute number 0 is reserved | ||
3079 | * @NUM_NL80211_TXQ_STATS: number of attributes here | ||
3080 | * @NL80211_TXQ_STATS_BACKLOG_BYTES: number of bytes currently backlogged | ||
3081 | * @NL80211_TXQ_STATS_BACKLOG_PACKETS: number of packets currently | ||
3082 | * backlogged | ||
3083 | * @NL80211_TXQ_STATS_FLOWS: total number of new flows seen | ||
3084 | * @NL80211_TXQ_STATS_DROPS: total number of packet drops | ||
3085 | * @NL80211_TXQ_STATS_ECN_MARKS: total number of packet ECN marks | ||
3086 | * @NL80211_TXQ_STATS_OVERLIMIT: number of drops due to queue space overflow | ||
3087 | * @NL80211_TXQ_STATS_OVERMEMORY: number of drops due to memory limit overflow | ||
3088 | * (only for per-phy stats) | ||
3089 | * @NL80211_TXQ_STATS_COLLISIONS: number of hash collisions | ||
3090 | * @NL80211_TXQ_STATS_TX_BYTES: total number of bytes dequeued from TXQ | ||
3091 | * @NL80211_TXQ_STATS_TX_PACKETS: total number of packets dequeued from TXQ | ||
3092 | * @NL80211_TXQ_STATS_MAX_FLOWS: number of flow buckets for PHY | ||
3093 | * @NL80211_TXQ_STATS_MAX: highest numbered attribute here | ||
3094 | */ | ||
3095 | enum nl80211_txq_stats { | ||
3096 | __NL80211_TXQ_STATS_INVALID, | ||
3097 | NL80211_TXQ_STATS_BACKLOG_BYTES, | ||
3098 | NL80211_TXQ_STATS_BACKLOG_PACKETS, | ||
3099 | NL80211_TXQ_STATS_FLOWS, | ||
3100 | NL80211_TXQ_STATS_DROPS, | ||
3101 | NL80211_TXQ_STATS_ECN_MARKS, | ||
3102 | NL80211_TXQ_STATS_OVERLIMIT, | ||
3103 | NL80211_TXQ_STATS_OVERMEMORY, | ||
3104 | NL80211_TXQ_STATS_COLLISIONS, | ||
3105 | NL80211_TXQ_STATS_TX_BYTES, | ||
3106 | NL80211_TXQ_STATS_TX_PACKETS, | ||
3107 | NL80211_TXQ_STATS_MAX_FLOWS, | ||
3108 | |||
3109 | /* keep last */ | ||
3110 | NUM_NL80211_TXQ_STATS, | ||
3111 | NL80211_TXQ_STATS_MAX = NUM_NL80211_TXQ_STATS - 1 | ||
3112 | }; | ||
3113 | |||
3114 | /** | ||
3060 | * enum nl80211_mpath_flags - nl80211 mesh path flags | 3115 | * enum nl80211_mpath_flags - nl80211 mesh path flags |
3061 | * | 3116 | * |
3062 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active | 3117 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active |
@@ -5072,6 +5127,8 @@ enum nl80211_feature_flags { | |||
5072 | * @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack | 5127 | * @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack |
5073 | * rssi if firmware support, this flag is to intimate about ack rssi | 5128 | * rssi if firmware support, this flag is to intimate about ack rssi |
5074 | * support to nl80211. | 5129 | * support to nl80211. |
5130 | * @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate | ||
5131 | * TXQs. | ||
5075 | * | 5132 | * |
5076 | * @NUM_NL80211_EXT_FEATURES: number of extended features. | 5133 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
5077 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. | 5134 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
@@ -5105,6 +5162,7 @@ enum nl80211_ext_feature_index { | |||
5105 | NL80211_EXT_FEATURE_DFS_OFFLOAD, | 5162 | NL80211_EXT_FEATURE_DFS_OFFLOAD, |
5106 | NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, | 5163 | NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, |
5107 | NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT, | 5164 | NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT, |
5165 | NL80211_EXT_FEATURE_TXQS, | ||
5108 | 5166 | ||
5109 | /* add new features before the definition below */ | 5167 | /* add new features before the definition below */ |
5110 | NUM_NL80211_EXT_FEATURES, | 5168 | NUM_NL80211_EXT_FEATURES, |
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c index 08408520c3f8..1afeff94af8b 100644 --- a/net/mac80211/ethtool.c +++ b/net/mac80211/ethtool.c | |||
@@ -71,11 +71,15 @@ static void ieee80211_get_stats(struct net_device *dev, | |||
71 | struct ieee80211_channel *channel; | 71 | struct ieee80211_channel *channel; |
72 | struct sta_info *sta; | 72 | struct sta_info *sta; |
73 | struct ieee80211_local *local = sdata->local; | 73 | struct ieee80211_local *local = sdata->local; |
74 | struct station_info sinfo; | 74 | struct station_info *sinfo; |
75 | struct survey_info survey; | 75 | struct survey_info survey; |
76 | int i, q; | 76 | int i, q; |
77 | #define STA_STATS_SURVEY_LEN 7 | 77 | #define STA_STATS_SURVEY_LEN 7 |
78 | 78 | ||
79 | sinfo = kmalloc(sizeof(*sinfo), GFP_KERNEL); | ||
80 | if (!sinfo) | ||
81 | return; | ||
82 | |||
79 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); | 83 | memset(data, 0, sizeof(u64) * STA_STATS_LEN); |
80 | 84 | ||
81 | #define ADD_STA_STATS(sta) \ | 85 | #define ADD_STA_STATS(sta) \ |
@@ -86,8 +90,8 @@ static void ieee80211_get_stats(struct net_device *dev, | |||
86 | data[i++] += sta->rx_stats.fragments; \ | 90 | data[i++] += sta->rx_stats.fragments; \ |
87 | data[i++] += sta->rx_stats.dropped; \ | 91 | data[i++] += sta->rx_stats.dropped; \ |
88 | \ | 92 | \ |
89 | data[i++] += sinfo.tx_packets; \ | 93 | data[i++] += sinfo->tx_packets; \ |
90 | data[i++] += sinfo.tx_bytes; \ | 94 | data[i++] += sinfo->tx_bytes; \ |
91 | data[i++] += sta->status_stats.filtered; \ | 95 | data[i++] += sta->status_stats.filtered; \ |
92 | data[i++] += sta->status_stats.retry_failed; \ | 96 | data[i++] += sta->status_stats.retry_failed; \ |
93 | data[i++] += sta->status_stats.retry_count; \ | 97 | data[i++] += sta->status_stats.retry_count; \ |
@@ -107,8 +111,8 @@ static void ieee80211_get_stats(struct net_device *dev, | |||
107 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) | 111 | if (!(sta && !WARN_ON(sta->sdata->dev != dev))) |
108 | goto do_survey; | 112 | goto do_survey; |
109 | 113 | ||
110 | memset(&sinfo, 0, sizeof(sinfo)); | 114 | memset(sinfo, 0, sizeof(*sinfo)); |
111 | sta_set_sinfo(sta, &sinfo); | 115 | sta_set_sinfo(sta, sinfo); |
112 | 116 | ||
113 | i = 0; | 117 | i = 0; |
114 | ADD_STA_STATS(sta); | 118 | ADD_STA_STATS(sta); |
@@ -116,17 +120,17 @@ static void ieee80211_get_stats(struct net_device *dev, | |||
116 | data[i++] = sta->sta_state; | 120 | data[i++] = sta->sta_state; |
117 | 121 | ||
118 | 122 | ||
119 | if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) | 123 | if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) |
120 | data[i] = 100000 * | 124 | data[i] = 100000 * |
121 | cfg80211_calculate_bitrate(&sinfo.txrate); | 125 | cfg80211_calculate_bitrate(&sinfo->txrate); |
122 | i++; | 126 | i++; |
123 | if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE)) | 127 | if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) |
124 | data[i] = 100000 * | 128 | data[i] = 100000 * |
125 | cfg80211_calculate_bitrate(&sinfo.rxrate); | 129 | cfg80211_calculate_bitrate(&sinfo->rxrate); |
126 | i++; | 130 | i++; |
127 | 131 | ||
128 | if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG)) | 132 | if (sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG)) |
129 | data[i] = (u8)sinfo.signal_avg; | 133 | data[i] = (u8)sinfo->signal_avg; |
130 | i++; | 134 | i++; |
131 | } else { | 135 | } else { |
132 | list_for_each_entry(sta, &local->sta_list, list) { | 136 | list_for_each_entry(sta, &local->sta_list, list) { |
@@ -134,14 +138,16 @@ static void ieee80211_get_stats(struct net_device *dev, | |||
134 | if (sta->sdata->dev != dev) | 138 | if (sta->sdata->dev != dev) |
135 | continue; | 139 | continue; |
136 | 140 | ||
137 | memset(&sinfo, 0, sizeof(sinfo)); | 141 | memset(sinfo, 0, sizeof(*sinfo)); |
138 | sta_set_sinfo(sta, &sinfo); | 142 | sta_set_sinfo(sta, sinfo); |
139 | i = 0; | 143 | i = 0; |
140 | ADD_STA_STATS(sta); | 144 | ADD_STA_STATS(sta); |
141 | } | 145 | } |
142 | } | 146 | } |
143 | 147 | ||
144 | do_survey: | 148 | do_survey: |
149 | kfree(sinfo); | ||
150 | |||
145 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | 151 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; |
146 | /* Get survey stats for current channel */ | 152 | /* Get survey stats for current channel */ |
147 | survey.filled = 0; | 153 | survey.filled = 0; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6b942a68d1c8..f7715b85fd2b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -424,6 +424,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
424 | [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN }, | 424 | [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN }, |
425 | [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG }, | 425 | [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG }, |
426 | [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG }, | 426 | [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG }, |
427 | |||
428 | [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 }, | ||
429 | [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 }, | ||
430 | [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 }, | ||
427 | }; | 431 | }; |
428 | 432 | ||
429 | /* policy for the key attributes */ | 433 | /* policy for the key attributes */ |
@@ -774,6 +778,39 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy, | |||
774 | return -ENOBUFS; | 778 | return -ENOBUFS; |
775 | } | 779 | } |
776 | 780 | ||
781 | static bool nl80211_put_txq_stats(struct sk_buff *msg, | ||
782 | struct cfg80211_txq_stats *txqstats, | ||
783 | int attrtype) | ||
784 | { | ||
785 | struct nlattr *txqattr; | ||
786 | |||
787 | #define PUT_TXQVAL_U32(attr, memb) do { \ | ||
788 | if (txqstats->filled & BIT(NL80211_TXQ_STATS_ ## attr) && \ | ||
789 | nla_put_u32(msg, NL80211_TXQ_STATS_ ## attr, txqstats->memb)) \ | ||
790 | return false; \ | ||
791 | } while (0) | ||
792 | |||
793 | txqattr = nla_nest_start(msg, attrtype); | ||
794 | if (!txqattr) | ||
795 | return false; | ||
796 | |||
797 | PUT_TXQVAL_U32(BACKLOG_BYTES, backlog_bytes); | ||
798 | PUT_TXQVAL_U32(BACKLOG_PACKETS, backlog_packets); | ||
799 | PUT_TXQVAL_U32(FLOWS, flows); | ||
800 | PUT_TXQVAL_U32(DROPS, drops); | ||
801 | PUT_TXQVAL_U32(ECN_MARKS, ecn_marks); | ||
802 | PUT_TXQVAL_U32(OVERLIMIT, overlimit); | ||
803 | PUT_TXQVAL_U32(OVERMEMORY, overmemory); | ||
804 | PUT_TXQVAL_U32(COLLISIONS, collisions); | ||
805 | PUT_TXQVAL_U32(TX_BYTES, tx_bytes); | ||
806 | PUT_TXQVAL_U32(TX_PACKETS, tx_packets); | ||
807 | PUT_TXQVAL_U32(MAX_FLOWS, max_flows); | ||
808 | nla_nest_end(msg, txqattr); | ||
809 | |||
810 | #undef PUT_TXQVAL_U32 | ||
811 | return true; | ||
812 | } | ||
813 | |||
777 | /* netlink command implementations */ | 814 | /* netlink command implementations */ |
778 | 815 | ||
779 | struct key_parse { | 816 | struct key_parse { |
@@ -1973,6 +2010,28 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1973 | rdev->wiphy.nan_supported_bands)) | 2010 | rdev->wiphy.nan_supported_bands)) |
1974 | goto nla_put_failure; | 2011 | goto nla_put_failure; |
1975 | 2012 | ||
2013 | if (wiphy_ext_feature_isset(&rdev->wiphy, | ||
2014 | NL80211_EXT_FEATURE_TXQS)) { | ||
2015 | struct cfg80211_txq_stats txqstats = {}; | ||
2016 | int res; | ||
2017 | |||
2018 | res = rdev_get_txq_stats(rdev, NULL, &txqstats); | ||
2019 | if (!res && | ||
2020 | !nl80211_put_txq_stats(msg, &txqstats, | ||
2021 | NL80211_ATTR_TXQ_STATS)) | ||
2022 | goto nla_put_failure; | ||
2023 | |||
2024 | if (nla_put_u32(msg, NL80211_ATTR_TXQ_LIMIT, | ||
2025 | rdev->wiphy.txq_limit)) | ||
2026 | goto nla_put_failure; | ||
2027 | if (nla_put_u32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, | ||
2028 | rdev->wiphy.txq_memory_limit)) | ||
2029 | goto nla_put_failure; | ||
2030 | if (nla_put_u32(msg, NL80211_ATTR_TXQ_QUANTUM, | ||
2031 | rdev->wiphy.txq_quantum)) | ||
2032 | goto nla_put_failure; | ||
2033 | } | ||
2034 | |||
1976 | /* done */ | 2035 | /* done */ |
1977 | state->split_start = 0; | 2036 | state->split_start = 0; |
1978 | break; | 2037 | break; |
@@ -2350,6 +2409,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2350 | u8 retry_short = 0, retry_long = 0; | 2409 | u8 retry_short = 0, retry_long = 0; |
2351 | u32 frag_threshold = 0, rts_threshold = 0; | 2410 | u32 frag_threshold = 0, rts_threshold = 0; |
2352 | u8 coverage_class = 0; | 2411 | u8 coverage_class = 0; |
2412 | u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0; | ||
2353 | 2413 | ||
2354 | ASSERT_RTNL(); | 2414 | ASSERT_RTNL(); |
2355 | 2415 | ||
@@ -2556,10 +2616,38 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2556 | changed |= WIPHY_PARAM_DYN_ACK; | 2616 | changed |= WIPHY_PARAM_DYN_ACK; |
2557 | } | 2617 | } |
2558 | 2618 | ||
2619 | if (info->attrs[NL80211_ATTR_TXQ_LIMIT]) { | ||
2620 | if (!wiphy_ext_feature_isset(&rdev->wiphy, | ||
2621 | NL80211_EXT_FEATURE_TXQS)) | ||
2622 | return -EOPNOTSUPP; | ||
2623 | txq_limit = nla_get_u32( | ||
2624 | info->attrs[NL80211_ATTR_TXQ_LIMIT]); | ||
2625 | changed |= WIPHY_PARAM_TXQ_LIMIT; | ||
2626 | } | ||
2627 | |||
2628 | if (info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) { | ||
2629 | if (!wiphy_ext_feature_isset(&rdev->wiphy, | ||
2630 | NL80211_EXT_FEATURE_TXQS)) | ||
2631 | return -EOPNOTSUPP; | ||
2632 | txq_memory_limit = nla_get_u32( | ||
2633 | info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]); | ||
2634 | changed |= WIPHY_PARAM_TXQ_MEMORY_LIMIT; | ||
2635 | } | ||
2636 | |||
2637 | if (info->attrs[NL80211_ATTR_TXQ_QUANTUM]) { | ||
2638 | if (!wiphy_ext_feature_isset(&rdev->wiphy, | ||
2639 | NL80211_EXT_FEATURE_TXQS)) | ||
2640 | return -EOPNOTSUPP; | ||
2641 | txq_quantum = nla_get_u32( | ||
2642 | info->attrs[NL80211_ATTR_TXQ_QUANTUM]); | ||
2643 | changed |= WIPHY_PARAM_TXQ_QUANTUM; | ||
2644 | } | ||
2645 | |||
2559 | if (changed) { | 2646 | if (changed) { |
2560 | u8 old_retry_short, old_retry_long; | 2647 | u8 old_retry_short, old_retry_long; |
2561 | u32 old_frag_threshold, old_rts_threshold; | 2648 | u32 old_frag_threshold, old_rts_threshold; |
2562 | u8 old_coverage_class; | 2649 | u8 old_coverage_class; |
2650 | u32 old_txq_limit, old_txq_memory_limit, old_txq_quantum; | ||
2563 | 2651 | ||
2564 | if (!rdev->ops->set_wiphy_params) | 2652 | if (!rdev->ops->set_wiphy_params) |
2565 | return -EOPNOTSUPP; | 2653 | return -EOPNOTSUPP; |
@@ -2569,6 +2657,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2569 | old_frag_threshold = rdev->wiphy.frag_threshold; | 2657 | old_frag_threshold = rdev->wiphy.frag_threshold; |
2570 | old_rts_threshold = rdev->wiphy.rts_threshold; | 2658 | old_rts_threshold = rdev->wiphy.rts_threshold; |
2571 | old_coverage_class = rdev->wiphy.coverage_class; | 2659 | old_coverage_class = rdev->wiphy.coverage_class; |
2660 | old_txq_limit = rdev->wiphy.txq_limit; | ||
2661 | old_txq_memory_limit = rdev->wiphy.txq_memory_limit; | ||
2662 | old_txq_quantum = rdev->wiphy.txq_quantum; | ||
2572 | 2663 | ||
2573 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 2664 | if (changed & WIPHY_PARAM_RETRY_SHORT) |
2574 | rdev->wiphy.retry_short = retry_short; | 2665 | rdev->wiphy.retry_short = retry_short; |
@@ -2580,6 +2671,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2580 | rdev->wiphy.rts_threshold = rts_threshold; | 2671 | rdev->wiphy.rts_threshold = rts_threshold; |
2581 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) | 2672 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) |
2582 | rdev->wiphy.coverage_class = coverage_class; | 2673 | rdev->wiphy.coverage_class = coverage_class; |
2674 | if (changed & WIPHY_PARAM_TXQ_LIMIT) | ||
2675 | rdev->wiphy.txq_limit = txq_limit; | ||
2676 | if (changed & WIPHY_PARAM_TXQ_MEMORY_LIMIT) | ||
2677 | rdev->wiphy.txq_memory_limit = txq_memory_limit; | ||
2678 | if (changed & WIPHY_PARAM_TXQ_QUANTUM) | ||
2679 | rdev->wiphy.txq_quantum = txq_quantum; | ||
2583 | 2680 | ||
2584 | result = rdev_set_wiphy_params(rdev, changed); | 2681 | result = rdev_set_wiphy_params(rdev, changed); |
2585 | if (result) { | 2682 | if (result) { |
@@ -2588,6 +2685,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2588 | rdev->wiphy.frag_threshold = old_frag_threshold; | 2685 | rdev->wiphy.frag_threshold = old_frag_threshold; |
2589 | rdev->wiphy.rts_threshold = old_rts_threshold; | 2686 | rdev->wiphy.rts_threshold = old_rts_threshold; |
2590 | rdev->wiphy.coverage_class = old_coverage_class; | 2687 | rdev->wiphy.coverage_class = old_coverage_class; |
2688 | rdev->wiphy.txq_limit = old_txq_limit; | ||
2689 | rdev->wiphy.txq_memory_limit = old_txq_memory_limit; | ||
2690 | rdev->wiphy.txq_quantum = old_txq_quantum; | ||
2591 | return result; | 2691 | return result; |
2592 | } | 2692 | } |
2593 | } | 2693 | } |
@@ -2709,6 +2809,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
2709 | } | 2809 | } |
2710 | wdev_unlock(wdev); | 2810 | wdev_unlock(wdev); |
2711 | 2811 | ||
2812 | if (rdev->ops->get_txq_stats) { | ||
2813 | struct cfg80211_txq_stats txqstats = {}; | ||
2814 | int ret = rdev_get_txq_stats(rdev, wdev, &txqstats); | ||
2815 | |||
2816 | if (ret == 0 && | ||
2817 | !nl80211_put_txq_stats(msg, &txqstats, | ||
2818 | NL80211_ATTR_TXQ_STATS)) | ||
2819 | goto nla_put_failure; | ||
2820 | } | ||
2821 | |||
2712 | genlmsg_end(msg, hdr); | 2822 | genlmsg_end(msg, hdr); |
2713 | return 0; | 2823 | return 0; |
2714 | 2824 | ||
@@ -4582,6 +4692,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, | |||
4582 | PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed); | 4692 | PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed); |
4583 | 4693 | ||
4584 | #undef PUT_TIDVAL_U64 | 4694 | #undef PUT_TIDVAL_U64 |
4695 | if ((tidstats->filled & | ||
4696 | BIT(NL80211_TID_STATS_TXQ_STATS)) && | ||
4697 | !nl80211_put_txq_stats(msg, &tidstats->txq_stats, | ||
4698 | NL80211_TID_STATS_TXQ_STATS)) | ||
4699 | goto nla_put_failure; | ||
4700 | |||
4585 | nla_nest_end(msg, tidattr); | 4701 | nla_nest_end(msg, tidattr); |
4586 | } | 4702 | } |
4587 | 4703 | ||
@@ -4606,13 +4722,17 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, | |||
4606 | static int nl80211_dump_station(struct sk_buff *skb, | 4722 | static int nl80211_dump_station(struct sk_buff *skb, |
4607 | struct netlink_callback *cb) | 4723 | struct netlink_callback *cb) |
4608 | { | 4724 | { |
4609 | struct station_info sinfo; | 4725 | struct station_info *sinfo; |
4610 | struct cfg80211_registered_device *rdev; | 4726 | struct cfg80211_registered_device *rdev; |
4611 | struct wireless_dev *wdev; | 4727 | struct wireless_dev *wdev; |
4612 | u8 mac_addr[ETH_ALEN]; | 4728 | u8 mac_addr[ETH_ALEN]; |
4613 | int sta_idx = cb->args[2]; | 4729 | int sta_idx = cb->args[2]; |
4614 | int err; | 4730 | int err; |
4615 | 4731 | ||
4732 | sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); | ||
4733 | if (!sinfo) | ||
4734 | return -ENOMEM; | ||
4735 | |||
4616 | rtnl_lock(); | 4736 | rtnl_lock(); |
4617 | err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); | 4737 | err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); |
4618 | if (err) | 4738 | if (err) |
@@ -4629,9 +4749,9 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
4629 | } | 4749 | } |
4630 | 4750 | ||
4631 | while (1) { | 4751 | while (1) { |
4632 | memset(&sinfo, 0, sizeof(sinfo)); | 4752 | memset(sinfo, 0, sizeof(*sinfo)); |
4633 | err = rdev_dump_station(rdev, wdev->netdev, sta_idx, | 4753 | err = rdev_dump_station(rdev, wdev->netdev, sta_idx, |
4634 | mac_addr, &sinfo); | 4754 | mac_addr, sinfo); |
4635 | if (err == -ENOENT) | 4755 | if (err == -ENOENT) |
4636 | break; | 4756 | break; |
4637 | if (err) | 4757 | if (err) |
@@ -4641,7 +4761,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
4641 | NETLINK_CB(cb->skb).portid, | 4761 | NETLINK_CB(cb->skb).portid, |
4642 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 4762 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
4643 | rdev, wdev->netdev, mac_addr, | 4763 | rdev, wdev->netdev, mac_addr, |
4644 | &sinfo) < 0) | 4764 | sinfo) < 0) |
4645 | goto out; | 4765 | goto out; |
4646 | 4766 | ||
4647 | sta_idx++; | 4767 | sta_idx++; |
@@ -4652,6 +4772,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
4652 | err = skb->len; | 4772 | err = skb->len; |
4653 | out_err: | 4773 | out_err: |
4654 | rtnl_unlock(); | 4774 | rtnl_unlock(); |
4775 | kfree(sinfo); | ||
4655 | 4776 | ||
4656 | return err; | 4777 | return err; |
4657 | } | 4778 | } |
@@ -4660,37 +4781,49 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
4660 | { | 4781 | { |
4661 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4782 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4662 | struct net_device *dev = info->user_ptr[1]; | 4783 | struct net_device *dev = info->user_ptr[1]; |
4663 | struct station_info sinfo; | 4784 | struct station_info *sinfo; |
4664 | struct sk_buff *msg; | 4785 | struct sk_buff *msg; |
4665 | u8 *mac_addr = NULL; | 4786 | u8 *mac_addr = NULL; |
4666 | int err; | 4787 | int err; |
4667 | 4788 | ||
4668 | memset(&sinfo, 0, sizeof(sinfo)); | 4789 | sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); |
4790 | if (!sinfo) | ||
4791 | return -ENOMEM; | ||
4669 | 4792 | ||
4670 | if (!info->attrs[NL80211_ATTR_MAC]) | 4793 | if (!info->attrs[NL80211_ATTR_MAC]) { |
4671 | return -EINVAL; | 4794 | err = -EINVAL; |
4795 | goto out; | ||
4796 | } | ||
4672 | 4797 | ||
4673 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 4798 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4674 | 4799 | ||
4675 | if (!rdev->ops->get_station) | 4800 | if (!rdev->ops->get_station) { |
4676 | return -EOPNOTSUPP; | 4801 | err = -EOPNOTSUPP; |
4802 | goto out; | ||
4803 | } | ||
4677 | 4804 | ||
4678 | err = rdev_get_station(rdev, dev, mac_addr, &sinfo); | 4805 | err = rdev_get_station(rdev, dev, mac_addr, sinfo); |
4679 | if (err) | 4806 | if (err) |
4680 | return err; | 4807 | goto out; |
4681 | 4808 | ||
4682 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4809 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4683 | if (!msg) | 4810 | if (!msg) { |
4684 | return -ENOMEM; | 4811 | err = -ENOMEM; |
4812 | goto out; | ||
4813 | } | ||
4685 | 4814 | ||
4686 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, | 4815 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, |
4687 | info->snd_portid, info->snd_seq, 0, | 4816 | info->snd_portid, info->snd_seq, 0, |
4688 | rdev, dev, mac_addr, &sinfo) < 0) { | 4817 | rdev, dev, mac_addr, sinfo) < 0) { |
4689 | nlmsg_free(msg); | 4818 | nlmsg_free(msg); |
4690 | return -ENOBUFS; | 4819 | err = -ENOBUFS; |
4820 | goto out; | ||
4691 | } | 4821 | } |
4692 | 4822 | ||
4693 | return genlmsg_reply(msg, info); | 4823 | err = genlmsg_reply(msg, info); |
4824 | out: | ||
4825 | kfree(sinfo); | ||
4826 | return err; | ||
4694 | } | 4827 | } |
4695 | 4828 | ||
4696 | int cfg80211_check_station_change(struct wiphy *wiphy, | 4829 | int cfg80211_check_station_change(struct wiphy *wiphy, |
@@ -9954,18 +10087,26 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev, | |||
9954 | */ | 10087 | */ |
9955 | if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss && | 10088 | if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss && |
9956 | rdev->ops->get_station) { | 10089 | rdev->ops->get_station) { |
9957 | struct station_info sinfo = {}; | 10090 | struct station_info *sinfo; |
9958 | u8 *mac_addr; | 10091 | u8 *mac_addr; |
9959 | 10092 | ||
10093 | sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); | ||
10094 | if (!sinfo) | ||
10095 | return -ENOMEM; | ||
10096 | |||
9960 | mac_addr = wdev->current_bss->pub.bssid; | 10097 | mac_addr = wdev->current_bss->pub.bssid; |
9961 | 10098 | ||
9962 | err = rdev_get_station(rdev, dev, mac_addr, &sinfo); | 10099 | err = rdev_get_station(rdev, dev, mac_addr, sinfo); |
9963 | if (err) | 10100 | if (err) { |
10101 | kfree(sinfo); | ||
9964 | return err; | 10102 | return err; |
10103 | } | ||
9965 | 10104 | ||
9966 | if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG)) | 10105 | if (sinfo->filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG)) |
9967 | wdev->cqm_config->last_rssi_event_value = | 10106 | wdev->cqm_config->last_rssi_event_value = |
9968 | (s8) sinfo.rx_beacon_signal_avg; | 10107 | (s8)sinfo->rx_beacon_signal_avg; |
10108 | |||
10109 | kfree(sinfo); | ||
9969 | } | 10110 | } |
9970 | 10111 | ||
9971 | last = wdev->cqm_config->last_rssi_event_value; | 10112 | last = wdev->cqm_config->last_rssi_event_value; |
@@ -14499,25 +14640,32 @@ void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr, | |||
14499 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 14640 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
14500 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 14641 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
14501 | struct sk_buff *msg; | 14642 | struct sk_buff *msg; |
14502 | struct station_info empty_sinfo = {}; | 14643 | struct station_info *empty_sinfo = NULL; |
14503 | 14644 | ||
14504 | if (!sinfo) | 14645 | if (!sinfo) { |
14505 | sinfo = &empty_sinfo; | 14646 | empty_sinfo = kzalloc(sizeof(*empty_sinfo), GFP_KERNEL); |
14647 | if (!empty_sinfo) | ||
14648 | return; | ||
14649 | sinfo = empty_sinfo; | ||
14650 | } | ||
14506 | 14651 | ||
14507 | trace_cfg80211_del_sta(dev, mac_addr); | 14652 | trace_cfg80211_del_sta(dev, mac_addr); |
14508 | 14653 | ||
14509 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 14654 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
14510 | if (!msg) | 14655 | if (!msg) |
14511 | return; | 14656 | goto out; |
14512 | 14657 | ||
14513 | if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0, | 14658 | if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0, |
14514 | rdev, dev, mac_addr, sinfo) < 0) { | 14659 | rdev, dev, mac_addr, sinfo) < 0) { |
14515 | nlmsg_free(msg); | 14660 | nlmsg_free(msg); |
14516 | return; | 14661 | goto out; |
14517 | } | 14662 | } |
14518 | 14663 | ||
14519 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 14664 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
14520 | NL80211_MCGRP_MLME, gfp); | 14665 | NL80211_MCGRP_MLME, gfp); |
14666 | |||
14667 | out: | ||
14668 | kfree(empty_sinfo); | ||
14521 | } | 14669 | } |
14522 | EXPORT_SYMBOL(cfg80211_del_sta_sinfo); | 14670 | EXPORT_SYMBOL(cfg80211_del_sta_sinfo); |
14523 | 14671 | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 87479a53411b..364f5d67f05b 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -586,6 +586,18 @@ rdev_set_multicast_to_unicast(struct cfg80211_registered_device *rdev, | |||
586 | return ret; | 586 | return ret; |
587 | } | 587 | } |
588 | 588 | ||
589 | static inline int | ||
590 | rdev_get_txq_stats(struct cfg80211_registered_device *rdev, | ||
591 | struct wireless_dev *wdev, | ||
592 | struct cfg80211_txq_stats *txqstats) | ||
593 | { | ||
594 | int ret; | ||
595 | trace_rdev_get_txq_stats(&rdev->wiphy, wdev); | ||
596 | ret = rdev->ops->get_txq_stats(&rdev->wiphy, wdev, txqstats); | ||
597 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
598 | return ret; | ||
599 | } | ||
600 | |||
589 | static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) | 601 | static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) |
590 | { | 602 | { |
591 | trace_rdev_rfkill_poll(&rdev->wiphy); | 603 | trace_rdev_rfkill_poll(&rdev->wiphy); |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 55fb279a5196..2b417a2fe63f 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -3243,6 +3243,20 @@ TRACE_EVENT(rdev_set_multicast_to_unicast, | |||
3243 | WIPHY_PR_ARG, NETDEV_PR_ARG, | 3243 | WIPHY_PR_ARG, NETDEV_PR_ARG, |
3244 | BOOL_TO_STR(__entry->enabled)) | 3244 | BOOL_TO_STR(__entry->enabled)) |
3245 | ); | 3245 | ); |
3246 | |||
3247 | TRACE_EVENT(rdev_get_txq_stats, | ||
3248 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
3249 | TP_ARGS(wiphy, wdev), | ||
3250 | TP_STRUCT__entry( | ||
3251 | WIPHY_ENTRY | ||
3252 | WDEV_ENTRY | ||
3253 | ), | ||
3254 | TP_fast_assign( | ||
3255 | WIPHY_ASSIGN; | ||
3256 | WDEV_ASSIGN; | ||
3257 | ), | ||
3258 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | ||
3259 | ); | ||
3246 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 3260 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
3247 | 3261 | ||
3248 | #undef TRACE_INCLUDE_PATH | 3262 | #undef TRACE_INCLUDE_PATH |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 05186a47878f..9e002df0f8d8 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1254,7 +1254,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev, | |||
1254 | { | 1254 | { |
1255 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1255 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1256 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | 1256 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
1257 | struct station_info sinfo = {}; | 1257 | struct station_info *sinfo; |
1258 | u8 addr[ETH_ALEN]; | 1258 | u8 addr[ETH_ALEN]; |
1259 | int err; | 1259 | int err; |
1260 | 1260 | ||
@@ -1274,16 +1274,23 @@ static int cfg80211_wext_giwrate(struct net_device *dev, | |||
1274 | if (err) | 1274 | if (err) |
1275 | return err; | 1275 | return err; |
1276 | 1276 | ||
1277 | err = rdev_get_station(rdev, dev, addr, &sinfo); | 1277 | sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); |
1278 | if (err) | 1278 | if (!sinfo) |
1279 | return err; | 1279 | return -ENOMEM; |
1280 | 1280 | ||
1281 | if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))) | 1281 | err = rdev_get_station(rdev, dev, addr, sinfo); |
1282 | return -EOPNOTSUPP; | 1282 | if (err) |
1283 | goto out; | ||
1283 | 1284 | ||
1284 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); | 1285 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) { |
1286 | err = -EOPNOTSUPP; | ||
1287 | goto out; | ||
1288 | } | ||
1285 | 1289 | ||
1286 | return 0; | 1290 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo->txrate); |
1291 | out: | ||
1292 | kfree(sinfo); | ||
1293 | return err; | ||
1287 | } | 1294 | } |
1288 | 1295 | ||
1289 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ | 1296 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ |