This patch adds support for txrate configuration to monitor station's current txrate strength. This will be useful for the application like steering, which monitors/requires station's txrate crossing event. Driver should advertise NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG to enable this feature. User will set the values in 100kbps using NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD and NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD. And cfg80211_sta_mon_txrate_notify api introduced to notify the txrate cross event using NL80211_CMD_NOTIFY_STA_MON.
Signed-off-by: Tamizh chelvam <tami...@codeaurora.org> --- include/net/cfg80211.h | 26 ++++++++++++++++ include/uapi/linux/nl80211.h | 34 ++++++++++++++++++++ net/wireless/nl80211.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ net/wireless/rdev-ops.h | 17 ++++++++++ net/wireless/trace.h | 49 +++++++++++++++++++++++++++++ 5 files changed, 200 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2f18794..e934742 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2984,6 +2984,10 @@ struct cfg80211_external_auth_params { * The driver should set %NL80211_EXT_FEATURE_STA_MON_RSSI_LIST if this * method is implemented. If it is provided then there's no point providing * @set_sta_mon_rssi_config. + * @set_sta_mon_txrate_config: Configure low and high TXRATE threshold in 100kbs + * for a connected station. The driver should(soon) send an event + * indicating the current attempted frame txrate level is above/below the + * configured threshold. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3293,6 +3297,11 @@ struct cfg80211_ops { struct net_device *dev, const u8 *addr, s32 rssi_low, s32 rssi_high); + int (*set_sta_mon_txrate_config)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr, + u32 low_txrate_thold, + u32 high_txrate_thold); }; /* @@ -5812,6 +5821,23 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, s32 rssi_level, gfp_t gfp); /** + * cfg80211_sta_mon_txrate_notify - txrate event for connected stations + * @dev: network device + * @peer: peer's MAC address + * @txrate_event: the triggered TX RATE event + * @txrate_level: new TX RATE level value or 0 if not available + * @gfp: context flags + * + * This function is called when a average of attempted frame txrate crossed + * above configured high txrate or below configured low txrate event + * occurs for a station. + */ +void +cfg80211_sta_mon_txrate_notify(struct net_device *dev, const u8 *peer, + enum nl80211_sta_mon_txrate_threshold_event txrate_event, + u32 txrate_level, gfp_t gfp); + +/** * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer * @dev: network device * @peer: peer's MAC address diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 78a019c..120dfb9 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4263,6 +4263,15 @@ enum nl80211_attr_cqm { * @NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT: RSSI threshold event * @NL80211_ATTR_STA_MON_RSSI_LEVEL: the RSSI value in dBm that triggered the * RSSI threshold event. + * @NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD: TX_RATE threshold in 100kbps. This + * u32 attribute specifies the low txrate threshold. Event will be sent + * if the station's txrate goes lesser than this threshold. + * @NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD: TX_RATE threshold in 100kbps. This + * u32 attribute specifies the upper txrate threshold. Event will be sent + * if the station's txrate goes greater than this threshold. + * @NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT: TX_RATE threshold cross event + * @NL80211_ATTR_STA_MON_TXRATE_LEVEL: Station's tx rate value in 100kbps that + * triggered the TX_RATE threshold cross event. */ enum nl80211_attr_sta_mon { __NL80211_ATTR_STA_MON_INVALID, @@ -4270,6 +4279,10 @@ enum nl80211_attr_sta_mon { NL80211_ATTR_STA_MON_RSSI_HYST, NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT, NL80211_ATTR_STA_MON_RSSI_LEVEL, + NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD, + NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD, + NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT, + NL80211_ATTR_STA_MON_TXRATE_LEVEL, /* keep last */ __NL80211_ATTR_STA_MON_AFTER_LAST, @@ -4302,6 +4315,21 @@ enum nl80211_sta_mon_rssi_threshold_event { NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH, }; +/** + * enum nl80211_sta_mon_txrate_threshold_event - TX_RATE threshold event + * @NL80211_STA_MON_TXRATE_THRESHOLD_IN_RANGE: The TX_RATE level is in between + * low and high threshold + * @NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW: The TX_RATE level is lower than + * the configured threshold + * @NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH: The TX_RATE is higher than the + * configured threshold + */ +enum nl80211_sta_mon_txrate_threshold_event { + NL80211_STA_MON_TXRATE_THRESHOLD_IN_RANGE, + NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW, + NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH, +}; + /** * enum nl80211_tx_power_setting - TX power adjustment @@ -5097,6 +5125,11 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_STA_MON_RSSI_LIST: With this driver the * %NL80211_ATTR_STA_MON_RSSI_THOLD attribute accepts a list of zero or * more RSSI threshold values to monitor rather than exactly one threshold. + * @NL80211_EXT_FEATURE_AP_STA_CQM_TXRATE_CONFIG: With this driver will accept + * %NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD attribute as low txrate and + * %NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD attribute as high txrate + * for AP/AP_VLAN/P2P_GO interface to monitor txrate for the connected + * stations and the drvier should advertise txrate via ieee80211_tx_status. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -5131,6 +5164,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG, NL80211_EXT_FEATURE_STA_MON_RSSI_LIST, + NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1adcdfd..e0e6ba0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9871,6 +9871,10 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) [NL80211_ATTR_STA_MON_RSSI_HYST] = { .type = NLA_U32 }, [NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, [NL80211_ATTR_STA_MON_RSSI_LEVEL] = { .type = NLA_S32 }, + [NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT] = { .type = NLA_U32 }, + [NL80211_ATTR_STA_MON_TXRATE_LEVEL] = { .type = NLA_U32 }, }; static int nl80211_set_cqm_txe(struct genl_info *info, @@ -12776,6 +12780,27 @@ static int nl80211_set_sta_mon_rssi(struct genl_info *info, return err; } +static int nl80211_set_sta_mon_txrate(struct genl_info *info, const u8 *addr, + u32 low_thold, u32 high_thold) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (!rdev->ops->set_sta_mon_txrate_config) + return -EOPNOTSUPP; + + if ((wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO && + wdev->iftype != NL80211_IFTYPE_AP_VLAN) || + (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG))) + return -EOPNOTSUPP; + + return rdev_set_sta_mon_txrate_config(rdev, dev, addr, low_thold, + high_thold); +} + static int nl80211_sta_mon(struct sk_buff *skb, struct genl_info *info) { struct nlattr *attrs[NL80211_ATTR_STA_MON_MAX + 1]; @@ -12811,6 +12836,19 @@ static int nl80211_sta_mon(struct sk_buff *skb, struct genl_info *info) hysteresis); } + if (attrs[NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD] && + attrs[NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD]) { + u32 low_thold = + nla_get_u32(attrs[NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD]); + u32 high_thold = + nla_get_u32(attrs[NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD]); + + if (low_thold > high_thold) + return -EINVAL; + + return nl80211_set_sta_mon_txrate(info, addr, low_thold, + high_thold); + } return -EINVAL; } @@ -15006,6 +15044,42 @@ void cfg80211_sta_mon_rssi_notify(struct net_device *dev, const u8 *peer, } EXPORT_SYMBOL(cfg80211_sta_mon_rssi_notify); +void +cfg80211_sta_mon_txrate_notify(struct net_device *dev, const u8 *peer, + enum nl80211_sta_mon_txrate_threshold_event txrate_event, + u32 txrate_level, gfp_t gfp) +{ + struct sk_buff *msg; + + trace_cfg80211_sta_mon_txrate_notify(dev, peer, txrate_event, + txrate_level); + + if (WARN_ON(txrate_event != + NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW && + txrate_event != + NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH)) + return; + + msg = cfg80211_prepare_sta_mon(dev, peer, gfp); + if (!msg) + return; + + if (nla_put_u32(msg, NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT, + txrate_event)) + goto nla_put_failure; + + if (txrate_level && nla_put_u32(msg, NL80211_ATTR_STA_MON_TXRATE_LEVEL, + txrate_level)) + goto nla_put_failure; + + cfg80211_send_sta_mon(msg, gfp); + + return; +nla_put_failure: + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_sta_mon_txrate_notify); + static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev, const char *mac, gfp_t gfp) { diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 47562b9..5c3289c 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1251,4 +1251,21 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_set_sta_mon_txrate_config(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *peer, + u32 low_txrate_thold, u32 high_txrate_thold) +{ + int ret; + + trace_rdev_set_sta_mon_txrate_config(&rdev->wiphy, dev, peer, + low_txrate_thold, + high_txrate_thold); + ret = rdev->ops->set_sta_mon_txrate_config(&rdev->wiphy, dev, peer, + low_txrate_thold, + high_txrate_thold); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 78ff0f2..1819411 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1390,6 +1390,55 @@ __entry->rssi_low, __entry->rssi_high) ); +TRACE_EVENT(rdev_set_sta_mon_txrate_config, + TP_PROTO(struct wiphy *wiphy, + struct net_device *netdev, const u8 *peer, + u32 low_txrate_thold, u32 high_txrate_thold), + TP_ARGS(wiphy, netdev, peer, low_txrate_thold, high_txrate_thold), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(u32, low_txrate_thold) + __field(u32, high_txrate_thold) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->low_txrate_thold = low_txrate_thold; + __entry->high_txrate_thold = high_txrate_thold; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT + ", low_txrate_thold: %u, high_txrate_thold: %u ", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), + __entry->low_txrate_thold, __entry->high_txrate_thold) +); + +TRACE_EVENT(cfg80211_sta_mon_txrate_notify, + TP_PROTO(struct net_device *netdev, const u8 *peer, + enum nl80211_sta_mon_txrate_threshold_event txrate_event, + u32 txrate_level), + TP_ARGS(netdev, peer, txrate_event, txrate_level), + TP_STRUCT__entry( + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(enum nl80211_sta_mon_txrate_threshold_event, + txrate_event) + __field(u32, txrate_level) + ), + TP_fast_assign( + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->txrate_event = txrate_event; + __entry->txrate_level = txrate_level; + ), + TP_printk(NETDEV_PR_FMT ", peer: " MAC_PR_FMT + ", tx_rate event: %d, txrate : %u", + NETDEV_PR_ARG, MAC_PR_ARG(peer), + __entry->txrate_event, __entry->txrate_level) +); + TRACE_EVENT(rdev_set_cqm_txe_config, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate, u32 pkts, u32 intvl), -- 1.9.1