提交 52539ca8 编写于 作者: T Toke Høiland-Jørgensen 提交者: Johannes Berg

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: NToke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: NJohannes Berg <johannes.berg@intel.com>
上级 cc60dbbf
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -1079,6 +1079,37 @@ struct sta_bss_parameters {
u16 beacon_interval;
};
/**
* struct cfg80211_txq_stats - TXQ statistics for this TID
* @filled: bitmap of flags using the bits of &enum nl80211_txq_stats to
* indicate the relevant values in this struct are filled
* @backlog_bytes: total number of bytes currently backlogged
* @backlog_packets: total number of packets currently backlogged
* @flows: number of new flows seen
* @drops: total number of packets dropped
* @ecn_marks: total number of packets marked with ECN CE
* @overlimit: number of drops due to queue space overflow
* @overmemory: number of drops due to memory limit overflow
* @collisions: number of hash collisions
* @tx_bytes: total number of bytes dequeued
* @tx_packets: total number of packets dequeued
* @max_flows: maximum number of flows supported
*/
struct cfg80211_txq_stats {
u32 filled;
u32 backlog_bytes;
u32 backlog_packets;
u32 flows;
u32 drops;
u32 ecn_marks;
u32 overlimit;
u32 overmemory;
u32 collisions;
u32 tx_bytes;
u32 tx_packets;
u32 max_flows;
};
/**
* struct cfg80211_tid_stats - per-TID statistics
* @filled: bitmap of flags using the bits of &enum nl80211_tid_stats to
......@@ -1088,6 +1119,7 @@ struct sta_bss_parameters {
* @tx_msdu_retries: number of retries (not counting the first) for
* transmitted MSDUs
* @tx_msdu_failed: number of failed transmitted MSDUs
* @txq_stats: TXQ statistics
*/
struct cfg80211_tid_stats {
u32 filled;
......@@ -1095,6 +1127,7 @@ struct cfg80211_tid_stats {
u64 tx_msdu;
u64 tx_msdu_retries;
u64 tx_msdu_failed;
struct cfg80211_txq_stats txq_stats;
};
#define IEEE80211_MAX_CHAINS 4
......@@ -2204,6 +2237,9 @@ enum cfg80211_connect_params_changed {
* @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
* @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed
* @WIPHY_PARAM_DYN_ACK: dynack has been enabled
* @WIPHY_PARAM_TXQ_LIMIT: TXQ packet limit has been changed
* @WIPHY_PARAM_TXQ_MEMORY_LIMIT: TXQ memory limit has been changed
* @WIPHY_PARAM_TXQ_QUANTUM: TXQ scheduler quantum
*/
enum wiphy_params_flags {
WIPHY_PARAM_RETRY_SHORT = 1 << 0,
......@@ -2212,6 +2248,9 @@ enum wiphy_params_flags {
WIPHY_PARAM_RTS_THRESHOLD = 1 << 3,
WIPHY_PARAM_COVERAGE_CLASS = 1 << 4,
WIPHY_PARAM_DYN_ACK = 1 << 5,
WIPHY_PARAM_TXQ_LIMIT = 1 << 6,
WIPHY_PARAM_TXQ_MEMORY_LIMIT = 1 << 7,
WIPHY_PARAM_TXQ_QUANTUM = 1 << 8,
};
/**
......@@ -2964,6 +3003,9 @@ struct cfg80211_external_auth_params {
*
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
*
* @get_txq_stats: Get TXQ stats for interface or phy. If wdev is %NULL, this
* function should return phy stats, and interface stats otherwise.
*
* @set_pmk: configure the PMK to be used for offloaded 802.1X 4-Way handshake.
* If not deleted through @del_pmk the PMK remains valid until disconnect
* upon which the driver should clear it.
......@@ -3265,6 +3307,10 @@ struct cfg80211_ops {
struct net_device *dev,
const bool enabled);
int (*get_txq_stats)(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_txq_stats *txqstats);
int (*set_pmk)(struct wiphy *wiphy, struct net_device *dev,
const struct cfg80211_pmk_conf *conf);
int (*del_pmk)(struct wiphy *wiphy, struct net_device *dev,
......@@ -3943,6 +3989,10 @@ struct wiphy {
u8 nan_supported_bands;
u32 txq_limit;
u32 txq_memory_limit;
u32 txq_quantum;
char priv[0] __aligned(NETDEV_ALIGN);
};
......
......@@ -2226,6 +2226,16 @@ enum nl80211_commands {
* @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
* u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
*
* @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum
* nl80211_txq_stats)
* @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
* The smaller of this and the memory limit is enforced.
* @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
* TXQ queues for this phy. The smaller of this and the packet limit is
* enforced.
* @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
* a flow is assigned on each round of the DRR scheduler.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
......@@ -2660,6 +2670,11 @@ enum nl80211_attrs {
NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
NL80211_ATTR_TXQ_STATS,
NL80211_ATTR_TXQ_LIMIT,
NL80211_ATTR_TXQ_MEMORY_LIMIT,
NL80211_ATTR_TXQ_QUANTUM,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
......@@ -3040,6 +3055,7 @@ enum nl80211_sta_info {
* @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
* MSDUs (u64)
* @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
* @NL80211_TID_STATS_TXQ_STATS: TXQ stats (nested attribute)
* @NUM_NL80211_TID_STATS: number of attributes here
* @NL80211_TID_STATS_MAX: highest numbered attribute here
*/
......@@ -3050,12 +3066,51 @@ enum nl80211_tid_stats {
NL80211_TID_STATS_TX_MSDU_RETRIES,
NL80211_TID_STATS_TX_MSDU_FAILED,
NL80211_TID_STATS_PAD,
NL80211_TID_STATS_TXQ_STATS,
/* keep last */
NUM_NL80211_TID_STATS,
NL80211_TID_STATS_MAX = NUM_NL80211_TID_STATS - 1
};
/**
* enum nl80211_txq_stats - per TXQ statistics attributes
* @__NL80211_TXQ_STATS_INVALID: attribute number 0 is reserved
* @NUM_NL80211_TXQ_STATS: number of attributes here
* @NL80211_TXQ_STATS_BACKLOG_BYTES: number of bytes currently backlogged
* @NL80211_TXQ_STATS_BACKLOG_PACKETS: number of packets currently
* backlogged
* @NL80211_TXQ_STATS_FLOWS: total number of new flows seen
* @NL80211_TXQ_STATS_DROPS: total number of packet drops
* @NL80211_TXQ_STATS_ECN_MARKS: total number of packet ECN marks
* @NL80211_TXQ_STATS_OVERLIMIT: number of drops due to queue space overflow
* @NL80211_TXQ_STATS_OVERMEMORY: number of drops due to memory limit overflow
* (only for per-phy stats)
* @NL80211_TXQ_STATS_COLLISIONS: number of hash collisions
* @NL80211_TXQ_STATS_TX_BYTES: total number of bytes dequeued from TXQ
* @NL80211_TXQ_STATS_TX_PACKETS: total number of packets dequeued from TXQ
* @NL80211_TXQ_STATS_MAX_FLOWS: number of flow buckets for PHY
* @NL80211_TXQ_STATS_MAX: highest numbered attribute here
*/
enum nl80211_txq_stats {
__NL80211_TXQ_STATS_INVALID,
NL80211_TXQ_STATS_BACKLOG_BYTES,
NL80211_TXQ_STATS_BACKLOG_PACKETS,
NL80211_TXQ_STATS_FLOWS,
NL80211_TXQ_STATS_DROPS,
NL80211_TXQ_STATS_ECN_MARKS,
NL80211_TXQ_STATS_OVERLIMIT,
NL80211_TXQ_STATS_OVERMEMORY,
NL80211_TXQ_STATS_COLLISIONS,
NL80211_TXQ_STATS_TX_BYTES,
NL80211_TXQ_STATS_TX_PACKETS,
NL80211_TXQ_STATS_MAX_FLOWS,
/* keep last */
NUM_NL80211_TXQ_STATS,
NL80211_TXQ_STATS_MAX = NUM_NL80211_TXQ_STATS - 1
};
/**
* enum nl80211_mpath_flags - nl80211 mesh path flags
*
......@@ -5072,6 +5127,8 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack
* rssi if firmware support, this flag is to intimate about ack rssi
* support to nl80211.
* @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
* TXQs.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
......@@ -5105,6 +5162,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_DFS_OFFLOAD,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT,
NL80211_EXT_FEATURE_TXQS,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
......
......@@ -71,11 +71,15 @@ static void ieee80211_get_stats(struct net_device *dev,
struct ieee80211_channel *channel;
struct sta_info *sta;
struct ieee80211_local *local = sdata->local;
struct station_info sinfo;
struct station_info *sinfo;
struct survey_info survey;
int i, q;
#define STA_STATS_SURVEY_LEN 7
sinfo = kmalloc(sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return;
memset(data, 0, sizeof(u64) * STA_STATS_LEN);
#define ADD_STA_STATS(sta) \
......@@ -86,8 +90,8 @@ static void ieee80211_get_stats(struct net_device *dev,
data[i++] += sta->rx_stats.fragments; \
data[i++] += sta->rx_stats.dropped; \
\
data[i++] += sinfo.tx_packets; \
data[i++] += sinfo.tx_bytes; \
data[i++] += sinfo->tx_packets; \
data[i++] += sinfo->tx_bytes; \
data[i++] += sta->status_stats.filtered; \
data[i++] += sta->status_stats.retry_failed; \
data[i++] += sta->status_stats.retry_count; \
......@@ -107,8 +111,8 @@ static void ieee80211_get_stats(struct net_device *dev,
if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
goto do_survey;
memset(&sinfo, 0, sizeof(sinfo));
sta_set_sinfo(sta, &sinfo);
memset(sinfo, 0, sizeof(*sinfo));
sta_set_sinfo(sta, sinfo);
i = 0;
ADD_STA_STATS(sta);
......@@ -116,17 +120,17 @@ static void ieee80211_get_stats(struct net_device *dev,
data[i++] = sta->sta_state;
if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.txrate);
cfg80211_calculate_bitrate(&sinfo->txrate);
i++;
if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE))
if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))
data[i] = 100000 *
cfg80211_calculate_bitrate(&sinfo.rxrate);
cfg80211_calculate_bitrate(&sinfo->rxrate);
i++;
if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
data[i] = (u8)sinfo.signal_avg;
if (sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
data[i] = (u8)sinfo->signal_avg;
i++;
} else {
list_for_each_entry(sta, &local->sta_list, list) {
......@@ -134,14 +138,16 @@ static void ieee80211_get_stats(struct net_device *dev,
if (sta->sdata->dev != dev)
continue;
memset(&sinfo, 0, sizeof(sinfo));
sta_set_sinfo(sta, &sinfo);
memset(sinfo, 0, sizeof(*sinfo));
sta_set_sinfo(sta, sinfo);
i = 0;
ADD_STA_STATS(sta);
}
}
do_survey:
kfree(sinfo);
i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
/* Get survey stats for current channel */
survey.filled = 0;
......
......@@ -424,6 +424,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
[NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
[NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
};
/* policy for the key attributes */
......@@ -774,6 +778,39 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
return -ENOBUFS;
}
static bool nl80211_put_txq_stats(struct sk_buff *msg,
struct cfg80211_txq_stats *txqstats,
int attrtype)
{
struct nlattr *txqattr;
#define PUT_TXQVAL_U32(attr, memb) do { \
if (txqstats->filled & BIT(NL80211_TXQ_STATS_ ## attr) && \
nla_put_u32(msg, NL80211_TXQ_STATS_ ## attr, txqstats->memb)) \
return false; \
} while (0)
txqattr = nla_nest_start(msg, attrtype);
if (!txqattr)
return false;
PUT_TXQVAL_U32(BACKLOG_BYTES, backlog_bytes);
PUT_TXQVAL_U32(BACKLOG_PACKETS, backlog_packets);
PUT_TXQVAL_U32(FLOWS, flows);
PUT_TXQVAL_U32(DROPS, drops);
PUT_TXQVAL_U32(ECN_MARKS, ecn_marks);
PUT_TXQVAL_U32(OVERLIMIT, overlimit);
PUT_TXQVAL_U32(OVERMEMORY, overmemory);
PUT_TXQVAL_U32(COLLISIONS, collisions);
PUT_TXQVAL_U32(TX_BYTES, tx_bytes);
PUT_TXQVAL_U32(TX_PACKETS, tx_packets);
PUT_TXQVAL_U32(MAX_FLOWS, max_flows);
nla_nest_end(msg, txqattr);
#undef PUT_TXQVAL_U32
return true;
}
/* netlink command implementations */
struct key_parse {
......@@ -1973,6 +2010,28 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
rdev->wiphy.nan_supported_bands))
goto nla_put_failure;
if (wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_TXQS)) {
struct cfg80211_txq_stats txqstats = {};
int res;
res = rdev_get_txq_stats(rdev, NULL, &txqstats);
if (!res &&
!nl80211_put_txq_stats(msg, &txqstats,
NL80211_ATTR_TXQ_STATS))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_TXQ_LIMIT,
rdev->wiphy.txq_limit))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT,
rdev->wiphy.txq_memory_limit))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_TXQ_QUANTUM,
rdev->wiphy.txq_quantum))
goto nla_put_failure;
}
/* done */
state->split_start = 0;
break;
......@@ -2350,6 +2409,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
u8 retry_short = 0, retry_long = 0;
u32 frag_threshold = 0, rts_threshold = 0;
u8 coverage_class = 0;
u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
ASSERT_RTNL();
......@@ -2556,10 +2616,38 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
changed |= WIPHY_PARAM_DYN_ACK;
}
if (info->attrs[NL80211_ATTR_TXQ_LIMIT]) {
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_TXQS))
return -EOPNOTSUPP;
txq_limit = nla_get_u32(
info->attrs[NL80211_ATTR_TXQ_LIMIT]);
changed |= WIPHY_PARAM_TXQ_LIMIT;
}
if (info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) {
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_TXQS))
return -EOPNOTSUPP;
txq_memory_limit = nla_get_u32(
info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]);
changed |= WIPHY_PARAM_TXQ_MEMORY_LIMIT;
}
if (info->attrs[NL80211_ATTR_TXQ_QUANTUM]) {
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_TXQS))
return -EOPNOTSUPP;
txq_quantum = nla_get_u32(
info->attrs[NL80211_ATTR_TXQ_QUANTUM]);
changed |= WIPHY_PARAM_TXQ_QUANTUM;
}
if (changed) {
u8 old_retry_short, old_retry_long;
u32 old_frag_threshold, old_rts_threshold;
u8 old_coverage_class;
u32 old_txq_limit, old_txq_memory_limit, old_txq_quantum;
if (!rdev->ops->set_wiphy_params)
return -EOPNOTSUPP;
......@@ -2569,6 +2657,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
old_frag_threshold = rdev->wiphy.frag_threshold;
old_rts_threshold = rdev->wiphy.rts_threshold;
old_coverage_class = rdev->wiphy.coverage_class;
old_txq_limit = rdev->wiphy.txq_limit;
old_txq_memory_limit = rdev->wiphy.txq_memory_limit;
old_txq_quantum = rdev->wiphy.txq_quantum;
if (changed & WIPHY_PARAM_RETRY_SHORT)
rdev->wiphy.retry_short = retry_short;
......@@ -2580,6 +2671,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
rdev->wiphy.rts_threshold = rts_threshold;
if (changed & WIPHY_PARAM_COVERAGE_CLASS)
rdev->wiphy.coverage_class = coverage_class;
if (changed & WIPHY_PARAM_TXQ_LIMIT)
rdev->wiphy.txq_limit = txq_limit;
if (changed & WIPHY_PARAM_TXQ_MEMORY_LIMIT)
rdev->wiphy.txq_memory_limit = txq_memory_limit;
if (changed & WIPHY_PARAM_TXQ_QUANTUM)
rdev->wiphy.txq_quantum = txq_quantum;
result = rdev_set_wiphy_params(rdev, changed);
if (result) {
......@@ -2588,6 +2685,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
rdev->wiphy.frag_threshold = old_frag_threshold;
rdev->wiphy.rts_threshold = old_rts_threshold;
rdev->wiphy.coverage_class = old_coverage_class;
rdev->wiphy.txq_limit = old_txq_limit;
rdev->wiphy.txq_memory_limit = old_txq_memory_limit;
rdev->wiphy.txq_quantum = old_txq_quantum;
return result;
}
}
......@@ -2709,6 +2809,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
}
wdev_unlock(wdev);
if (rdev->ops->get_txq_stats) {
struct cfg80211_txq_stats txqstats = {};
int ret = rdev_get_txq_stats(rdev, wdev, &txqstats);
if (ret == 0 &&
!nl80211_put_txq_stats(msg, &txqstats,
NL80211_ATTR_TXQ_STATS))
goto nla_put_failure;
}
genlmsg_end(msg, hdr);
return 0;
......@@ -4582,6 +4692,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
#undef PUT_TIDVAL_U64
if ((tidstats->filled &
BIT(NL80211_TID_STATS_TXQ_STATS)) &&
!nl80211_put_txq_stats(msg, &tidstats->txq_stats,
NL80211_TID_STATS_TXQ_STATS))
goto nla_put_failure;
nla_nest_end(msg, tidattr);
}
......@@ -4606,13 +4722,17 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
static int nl80211_dump_station(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct station_info sinfo;
struct station_info *sinfo;
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
u8 mac_addr[ETH_ALEN];
int sta_idx = cb->args[2];
int err;
sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return -ENOMEM;
rtnl_lock();
err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (err)
......@@ -4629,9 +4749,9 @@ static int nl80211_dump_station(struct sk_buff *skb,
}
while (1) {
memset(&sinfo, 0, sizeof(sinfo));
memset(sinfo, 0, sizeof(*sinfo));
err = rdev_dump_station(rdev, wdev->netdev, sta_idx,
mac_addr, &sinfo);
mac_addr, sinfo);
if (err == -ENOENT)
break;
if (err)
......@@ -4641,7 +4761,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
rdev, wdev->netdev, mac_addr,
&sinfo) < 0)
sinfo) < 0)
goto out;
sta_idx++;
......@@ -4652,6 +4772,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
err = skb->len;
out_err:
rtnl_unlock();
kfree(sinfo);
return err;
}
......@@ -4660,37 +4781,49 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct station_info sinfo;
struct station_info *sinfo;
struct sk_buff *msg;
u8 *mac_addr = NULL;
int err;
memset(&sinfo, 0, sizeof(sinfo));
sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return -ENOMEM;
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
if (!info->attrs[NL80211_ATTR_MAC]) {
err = -EINVAL;
goto out;
}
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (!rdev->ops->get_station)
return -EOPNOTSUPP;
if (!rdev->ops->get_station) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
err = rdev_get_station(rdev, dev, mac_addr, sinfo);
if (err)
return err;
goto out;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (!msg) {
err = -ENOMEM;
goto out;
}
if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
info->snd_portid, info->snd_seq, 0,
rdev, dev, mac_addr, &sinfo) < 0) {
rdev, dev, mac_addr, sinfo) < 0) {
nlmsg_free(msg);
return -ENOBUFS;
err = -ENOBUFS;
goto out;
}
return genlmsg_reply(msg, info);
err = genlmsg_reply(msg, info);
out:
kfree(sinfo);
return err;
}
int cfg80211_check_station_change(struct wiphy *wiphy,
......@@ -9954,18 +10087,26 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
*/
if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
rdev->ops->get_station) {
struct station_info sinfo = {};
struct station_info *sinfo;
u8 *mac_addr;
sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return -ENOMEM;
mac_addr = wdev->current_bss->pub.bssid;
err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
if (err)
err = rdev_get_station(rdev, dev, mac_addr, sinfo);
if (err) {
kfree(sinfo);
return err;
}
if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
if (sinfo->filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
wdev->cqm_config->last_rssi_event_value =
(s8) sinfo.rx_beacon_signal_avg;
(s8)sinfo->rx_beacon_signal_avg;
kfree(sinfo);
}
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,
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct sk_buff *msg;
struct station_info empty_sinfo = {};
struct station_info *empty_sinfo = NULL;
if (!sinfo)
sinfo = &empty_sinfo;
if (!sinfo) {
empty_sinfo = kzalloc(sizeof(*empty_sinfo), GFP_KERNEL);
if (!empty_sinfo)
return;
sinfo = empty_sinfo;
}
trace_cfg80211_del_sta(dev, mac_addr);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
goto out;
if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
rdev, dev, mac_addr, sinfo) < 0) {
nlmsg_free(msg);
return;
goto out;
}
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, gfp);
out:
kfree(empty_sinfo);
}
EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
......
......@@ -586,6 +586,18 @@ rdev_set_multicast_to_unicast(struct cfg80211_registered_device *rdev,
return ret;
}
static inline int
rdev_get_txq_stats(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_txq_stats *txqstats)
{
int ret;
trace_rdev_get_txq_stats(&rdev->wiphy, wdev);
ret = rdev->ops->get_txq_stats(&rdev->wiphy, wdev, txqstats);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
{
trace_rdev_rfkill_poll(&rdev->wiphy);
......
......@@ -3243,6 +3243,20 @@ TRACE_EVENT(rdev_set_multicast_to_unicast,
WIPHY_PR_ARG, NETDEV_PR_ARG,
BOOL_TO_STR(__entry->enabled))
);
TRACE_EVENT(rdev_get_txq_stats,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
......
......@@ -1254,7 +1254,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct station_info sinfo = {};
struct station_info *sinfo;
u8 addr[ETH_ALEN];
int err;
......@@ -1274,16 +1274,23 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
if (err)
return err;
err = rdev_get_station(rdev, dev, addr, &sinfo);
if (err)
return err;
sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return -ENOMEM;
if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)))
return -EOPNOTSUPP;
err = rdev_get_station(rdev, dev, addr, sinfo);
if (err)
goto out;
rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) {
err = -EOPNOTSUPP;
goto out;
}
return 0;
rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo->txrate);
out:
kfree(sinfo);
return err;
}
/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部