Add support to collect per STA mcast/bcast packet information attribute NL80211_STA_INFO_RX_MCAST_BCAST. Signed-off-by: Narayanraddi Masti <team.nmasti@xxxxxxxxx> --- include/net/cfg80211.h | 17 +++++++++++++++++ include/uapi/linux/nl80211.h | 28 ++++++++++++++++++++++++++++ net/mac80211/rx.c | 17 +++++++++++++++++ net/mac80211/sta_info.c | 12 ++++++++++++ net/mac80211/sta_info.h | 6 ++++++ net/wireless/nl80211.c | 23 +++++++++++++++++++++++ 6 files changed, 103 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f1259e1..e4948b6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1250,6 +1250,20 @@ struct cfg80211_tid_stats { #define IEEE80211_MAX_CHAINS 4 /** + * struct mc_bc_stats - per STA multicast/broadcast data packets + * @mc_pkts: number of multicast packets + * @mc_bytes: number of bytes of multicast + * @bc_pkts: number of broadcast packets + * @bc_bytes: number of bytes of broadcast + */ +struct mc_bc_stats { + u64 mc_pkts; + u64 mc_bytes; + u64 bc_pkts; + u64 bc_bytes; +}; + +/** * struct station_info - station information * * Station information filled by driver for get_station() and dump_station. @@ -1311,6 +1325,7 @@ struct cfg80211_tid_stats { * an FCS error. This counter should be incremented only when TA of the * received packet with an FCS error matches the peer MAC address. * @airtime_link_metric: mesh airtime link metric. + * @mc_bc_stat: per STA rx mcast/bcast count stats. */ struct station_info { u64 filled; @@ -1364,6 +1379,8 @@ struct station_info { u32 fcs_err_count; u32 airtime_link_metric; + + struct mc_bc_stats mc_bc_stat; }; #if IS_ENABLED(CONFIG_CFG80211) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 99bebbf..6e9d54e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3054,6 +3054,32 @@ enum nl80211_sta_bss_param { }; /** + * enum nl80211_rx_mcast_bcast - per sta received mc/bc packet count information + * + * These attribute types are used with %NL80211_STA_INFO_RX_MCAST_BCAST + * when getting information about a station's received mcast/bcast packets. + * + * __NL80211_RX_MCAST_BCAST_INVALID: attribute number 0 is reserved + * @NL80211_RX_MCAST_PACKETS: number of received multicast packets + * @NL80211_RX_MCAST_BYTES: number of received multicast bytes + * @NL80211_RX_BCAST_PACKETS: number of received broadcast packets + * @NL80211_RX_BCAST_BYTES: number of received broadcast bytes + * @_NL80211_RX_MCAST_BCAST_AFTER_LAST: internal use + * @NL80211_RX_MCAST_BCAST_MAX: highest rx mcast_bcast info number + */ +enum nl80211_rx_mcast_bcast { + __NL80211_RX_MCAST_BCAST_INVALID, + NL80211_RX_MCAST_PACKETS, + NL80211_RX_MCAST_BYTES, + NL80211_RX_BCAST_PACKETS, + NL80211_RX_BCAST_BYTES, + + /* keep last */ + __NL80211_RX_MCAST_BCAST_AFTER_LAST, + NL80211_RX_MCAST_BCAST_MAX = __NL80211_RX_MCAST_BCAST_AFTER_LAST - 1 +}; + +/** * enum nl80211_sta_info - station information * * These attribute types are used with %NL80211_ATTR_STA_INFO @@ -3126,6 +3152,7 @@ enum nl80211_sta_bss_param { * @NL80211_STA_INFO_CONNECTED_TO_GATE: set to true if STA has a path to a * mesh gate (u8, 0 or 1) * @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station + * @NL80211_STA_INFO_RX_MCAST_BCAST: per station rx mcast/bcast count stats. * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -3170,6 +3197,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_FCS_ERROR_COUNT, NL80211_STA_INFO_CONNECTED_TO_GATE, NL80211_STA_INFO_AIRTIME_LINK_METRIC, + NL80211_STA_INFO_RX_MCAST_BCAST, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bb4d71e..af73562 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2772,6 +2772,20 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, } #endif +static inline void ieee80211_mc_bc_stats(char *dst, + struct ieee80211_rx_data *rx) +{ + if (is_multicast_ether_addr(dst) && rx->sta) { + if (is_broadcast_ether_addr(dst)) { + rx->sta->mc_bc_stat.bc_pkts++; + rx->sta->mc_bc_stat.bc_bytes += rx->skb->len; + } else { + rx->sta->mc_bc_stat.mc_pkts++; + rx->sta->mc_bc_stat.mc_bytes += rx->skb->len; + } + } +} + static ieee80211_rx_result debug_noinline ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { @@ -2806,6 +2820,9 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, if (unlikely(err)) return RX_DROP_UNUSABLE; + /* Get the multicat broadcast stats */ + ieee80211_mc_bc_stats(((struct ethhdr *)rx->skb->data)->h_dest, rx); + if (!ieee80211_frame_allowed(rx, fc)) return RX_DROP_MONITOR; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e24dd28..fa27961 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2341,6 +2341,18 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, sinfo->airtime_link_metric = airtime_link_metric_get(local, sta); } + + sta_get_rx_multicast_broadcast_info(sta, &sinfo->mc_bc_stat); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_MCAST_BCAST); +} + +void sta_get_rx_multicast_broadcast_info(struct sta_info *sta, + struct mc_bc_stats *stats) +{ + stats->mc_pkts = sta->mc_bc_stat.mc_pkts; + stats->mc_bytes = sta->mc_bc_stat.mc_bytes; + stats->bc_pkts = sta->mc_bc_stat.bc_pkts; + stats->bc_bytes = sta->mc_bc_stat.bc_bytes; } u32 sta_get_expected_throughput(struct sta_info *sta) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 8eb2904..75f5114 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -479,6 +479,7 @@ struct ieee80211_sta_rx_stats { * @fast_rx: RX fastpath information * @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to * the BSS one. + * @mc_bc_stat: per STA rx mcast/bcast count stats. * @tx_stats: TX statistics * @rx_stats: RX statistics * @pcpu_rx_stats: per-CPU RX statistics, assigned only if the driver needs @@ -585,6 +586,8 @@ struct sta_info { struct cfg80211_chan_def tdls_chandef; + struct mc_bc_stats mc_bc_stat; + /* keep last! */ struct ieee80211_sta sta; }; @@ -749,6 +752,9 @@ void sta_set_rate_info_tx(struct sta_info *sta, void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, bool tidstats); +void sta_get_rx_multicast_broadcast_info(struct sta_info *sta, + struct mc_bc_stats *stats); + u32 sta_get_expected_throughput(struct sta_info *sta); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 326493a..dfe474d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4981,6 +4981,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, nla_nest_end(msg, tidsattr); } + if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_MCAST_BCAST)) { + struct nlattr *packetsattr; + + packetsattr = nla_nest_start(msg, + NL80211_STA_INFO_RX_MCAST_BCAST); + if (!packetsattr) + goto nla_put_failure; + +#define PUT_MC_BC_VAL_U64(attr, memb) do { \ + if (nla_put_u64_64bit(msg, NL80211_RX_ ## attr, \ + sinfo->mc_bc_stat.memb, NL80211_STA_INFO_PAD)) \ + goto nla_put_failure; \ + } while (0) + + PUT_MC_BC_VAL_U64(MCAST_PACKETS, mc_pkts); + PUT_MC_BC_VAL_U64(MCAST_BYTES, mc_bytes); + PUT_MC_BC_VAL_U64(BCAST_PACKETS, bc_pkts); + PUT_MC_BC_VAL_U64(BCAST_BYTES, bc_bytes); + +#undef PUT_MC_BC_VAL_U64 + nla_nest_end(msg, packetsattr); + } + nla_nest_end(msg, sinfoattr); if (sinfo->assoc_req_ies_len && -- 1.9.1