diff options
author | Thomas Pedersen <c_tpeder@qca.qualcomm.com> | 2012-07-12 19:17:33 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-07-17 05:57:23 -0400 |
commit | 84f10708f73254878246772cead70a2eb6a123f2 (patch) | |
tree | 39a4ca2f6cc3ab5b33320e3a62d2a8f7c4901b7a | |
parent | 00f5335079689cd65a9430b5df8974dc35c7914b (diff) |
cfg80211: support TX error rate CQM
Let the user configure serveral TX error conection quality monitoring
parameters: % error rate, survey interval, and # of attempted packets.
On exceeding the TX failure rate over the given interval, the driver
will send a CQM notify event with the actual TX failure rate and
packets attempted.
Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/linux/nl80211.h | 16 | ||||
-rw-r--r-- | include/net/cfg80211.h | 21 | ||||
-rw-r--r-- | net/wireless/mlme.c | 13 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 85 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 5 |
5 files changed, 140 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index e791487ead37..d6cfacc3ce4d 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -1550,6 +1550,8 @@ enum nl80211_attrs { | |||
1550 | /* default RSSI threshold for scan results if none specified. */ | 1550 | /* default RSSI threshold for scan results if none specified. */ |
1551 | #define NL80211_SCAN_RSSI_THOLD_OFF -300 | 1551 | #define NL80211_SCAN_RSSI_THOLD_OFF -300 |
1552 | 1552 | ||
1553 | #define NL80211_CQM_TXE_MAX_INTVL 1800 | ||
1554 | |||
1553 | /** | 1555 | /** |
1554 | * enum nl80211_iftype - (virtual) interface types | 1556 | * enum nl80211_iftype - (virtual) interface types |
1555 | * | 1557 | * |
@@ -2589,6 +2591,17 @@ enum nl80211_ps_state { | |||
2589 | * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event | 2591 | * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event |
2590 | * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many | 2592 | * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many |
2591 | * consecutive packets were not acknowledged by the peer | 2593 | * consecutive packets were not acknowledged by the peer |
2594 | * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures | ||
2595 | * during the given %NL80211_ATTR_CQM_TXE_INTVL before an | ||
2596 | * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and | ||
2597 | * %NL80211_ATTR_CQM_TXE_PKTS is generated. | ||
2598 | * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given | ||
2599 | * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is | ||
2600 | * checked. | ||
2601 | * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic | ||
2602 | * interval in which %NL80211_ATTR_CQM_TXE_PKTS and | ||
2603 | * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an | ||
2604 | * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. | ||
2592 | * @__NL80211_ATTR_CQM_AFTER_LAST: internal | 2605 | * @__NL80211_ATTR_CQM_AFTER_LAST: internal |
2593 | * @NL80211_ATTR_CQM_MAX: highest key attribute | 2606 | * @NL80211_ATTR_CQM_MAX: highest key attribute |
2594 | */ | 2607 | */ |
@@ -2598,6 +2611,9 @@ enum nl80211_attr_cqm { | |||
2598 | NL80211_ATTR_CQM_RSSI_HYST, | 2611 | NL80211_ATTR_CQM_RSSI_HYST, |
2599 | NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, | 2612 | NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, |
2600 | NL80211_ATTR_CQM_PKT_LOSS_EVENT, | 2613 | NL80211_ATTR_CQM_PKT_LOSS_EVENT, |
2614 | NL80211_ATTR_CQM_TXE_RATE, | ||
2615 | NL80211_ATTR_CQM_TXE_PKTS, | ||
2616 | NL80211_ATTR_CQM_TXE_INTVL, | ||
2601 | 2617 | ||
2602 | /* keep last */ | 2618 | /* keep last */ |
2603 | __NL80211_ATTR_CQM_AFTER_LAST, | 2619 | __NL80211_ATTR_CQM_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0245208c2978..493fa0c79005 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1573,6 +1573,8 @@ struct cfg80211_gtk_rekey_data { | |||
1573 | * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 | 1573 | * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 |
1574 | * allows the driver to adjust the dynamic ps timeout value. | 1574 | * allows the driver to adjust the dynamic ps timeout value. |
1575 | * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. | 1575 | * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. |
1576 | * @set_cqm_txe_config: Configure connection quality monitor TX error | ||
1577 | * thresholds. | ||
1576 | * @sched_scan_start: Tell the driver to start a scheduled scan. | 1578 | * @sched_scan_start: Tell the driver to start a scheduled scan. |
1577 | * @sched_scan_stop: Tell the driver to stop an ongoing scheduled | 1579 | * @sched_scan_stop: Tell the driver to stop an ongoing scheduled |
1578 | * scan. The driver_initiated flag specifies whether the driver | 1580 | * scan. The driver_initiated flag specifies whether the driver |
@@ -1783,6 +1785,10 @@ struct cfg80211_ops { | |||
1783 | struct net_device *dev, | 1785 | struct net_device *dev, |
1784 | s32 rssi_thold, u32 rssi_hyst); | 1786 | s32 rssi_thold, u32 rssi_hyst); |
1785 | 1787 | ||
1788 | int (*set_cqm_txe_config)(struct wiphy *wiphy, | ||
1789 | struct net_device *dev, | ||
1790 | u32 rate, u32 pkts, u32 intvl); | ||
1791 | |||
1786 | void (*mgmt_frame_register)(struct wiphy *wiphy, | 1792 | void (*mgmt_frame_register)(struct wiphy *wiphy, |
1787 | struct wireless_dev *wdev, | 1793 | struct wireless_dev *wdev, |
1788 | u16 frame_type, bool reg); | 1794 | u16 frame_type, bool reg); |
@@ -3396,6 +3402,21 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, | |||
3396 | const u8 *peer, u32 num_packets, gfp_t gfp); | 3402 | const u8 *peer, u32 num_packets, gfp_t gfp); |
3397 | 3403 | ||
3398 | /** | 3404 | /** |
3405 | * cfg80211_cqm_txe_notify - TX error rate event | ||
3406 | * @dev: network device | ||
3407 | * @peer: peer's MAC address | ||
3408 | * @num_packets: how many packets were lost | ||
3409 | * @rate: % of packets which failed transmission | ||
3410 | * @intvl: interval (in s) over which the TX failure threshold was breached. | ||
3411 | * @gfp: context flags | ||
3412 | * | ||
3413 | * Notify userspace when configured % TX failures over number of packets in a | ||
3414 | * given interval is exceeded. | ||
3415 | */ | ||
3416 | void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, | ||
3417 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); | ||
3418 | |||
3419 | /** | ||
3399 | * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying | 3420 | * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying |
3400 | * @dev: network device | 3421 | * @dev: network device |
3401 | * @bssid: BSSID of AP (to avoid races) | 3422 | * @bssid: BSSID of AP (to avoid races) |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index abe9f82d5a82..1cdb1d5e6b0f 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -919,6 +919,19 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, | |||
919 | } | 919 | } |
920 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | 920 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); |
921 | 921 | ||
922 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
923 | const u8 *peer, u32 num_packets, | ||
924 | u32 rate, u32 intvl, gfp_t gfp) | ||
925 | { | ||
926 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
927 | struct wiphy *wiphy = wdev->wiphy; | ||
928 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
929 | |||
930 | nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets, | ||
931 | rate, intvl, gfp); | ||
932 | } | ||
933 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
934 | |||
922 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, | 935 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, |
923 | const u8 *replay_ctr, gfp_t gfp) | 936 | const u8 *replay_ctr, gfp_t gfp) |
924 | { | 937 | { |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index be8750f91d78..9216e45e53a0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -6267,8 +6267,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
6267 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 6267 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
6268 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 6268 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
6269 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | 6269 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
6270 | [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, | ||
6271 | [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 }, | ||
6272 | [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 }, | ||
6270 | }; | 6273 | }; |
6271 | 6274 | ||
6275 | static int nl80211_set_cqm_txe(struct genl_info *info, | ||
6276 | u32 rate, u32 pkts, u32 intvl) | ||
6277 | { | ||
6278 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
6279 | struct wireless_dev *wdev; | ||
6280 | struct net_device *dev = info->user_ptr[1]; | ||
6281 | |||
6282 | if ((rate < 0 || rate > 100) || | ||
6283 | (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) | ||
6284 | return -EINVAL; | ||
6285 | |||
6286 | wdev = dev->ieee80211_ptr; | ||
6287 | |||
6288 | if (!rdev->ops->set_cqm_txe_config) | ||
6289 | return -EOPNOTSUPP; | ||
6290 | |||
6291 | if (wdev->iftype != NL80211_IFTYPE_STATION && | ||
6292 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) | ||
6293 | return -EOPNOTSUPP; | ||
6294 | |||
6295 | return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, | ||
6296 | rate, pkts, intvl); | ||
6297 | } | ||
6298 | |||
6272 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 6299 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
6273 | s32 threshold, u32 hysteresis) | 6300 | s32 threshold, u32 hysteresis) |
6274 | { | 6301 | { |
@@ -6316,6 +6343,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
6316 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | 6343 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); |
6317 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | 6344 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); |
6318 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); | 6345 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); |
6346 | } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] && | ||
6347 | attrs[NL80211_ATTR_CQM_TXE_PKTS] && | ||
6348 | attrs[NL80211_ATTR_CQM_TXE_INTVL]) { | ||
6349 | u32 rate, pkts, intvl; | ||
6350 | rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]); | ||
6351 | pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]); | ||
6352 | intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]); | ||
6353 | err = nl80211_set_cqm_txe(info, rate, pkts, intvl); | ||
6319 | } else | 6354 | } else |
6320 | err = -EINVAL; | 6355 | err = -EINVAL; |
6321 | 6356 | ||
@@ -8496,6 +8531,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8496 | } | 8531 | } |
8497 | 8532 | ||
8498 | void | 8533 | void |
8534 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
8535 | struct net_device *netdev, const u8 *peer, | ||
8536 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | ||
8537 | { | ||
8538 | struct sk_buff *msg; | ||
8539 | struct nlattr *pinfoattr; | ||
8540 | void *hdr; | ||
8541 | |||
8542 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
8543 | if (!msg) | ||
8544 | return; | ||
8545 | |||
8546 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
8547 | if (!hdr) { | ||
8548 | nlmsg_free(msg); | ||
8549 | return; | ||
8550 | } | ||
8551 | |||
8552 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
8553 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
8554 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | ||
8555 | goto nla_put_failure; | ||
8556 | |||
8557 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
8558 | if (!pinfoattr) | ||
8559 | goto nla_put_failure; | ||
8560 | |||
8561 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) | ||
8562 | goto nla_put_failure; | ||
8563 | |||
8564 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) | ||
8565 | goto nla_put_failure; | ||
8566 | |||
8567 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) | ||
8568 | goto nla_put_failure; | ||
8569 | |||
8570 | nla_nest_end(msg, pinfoattr); | ||
8571 | |||
8572 | genlmsg_end(msg, hdr); | ||
8573 | |||
8574 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
8575 | nl80211_mlme_mcgrp.id, gfp); | ||
8576 | return; | ||
8577 | |||
8578 | nla_put_failure: | ||
8579 | genlmsg_cancel(msg, hdr); | ||
8580 | nlmsg_free(msg); | ||
8581 | } | ||
8582 | |||
8583 | void | ||
8499 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 8584 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
8500 | struct net_device *netdev, const u8 *peer, | 8585 | struct net_device *netdev, const u8 *peer, |
8501 | u32 num_packets, gfp_t gfp) | 8586 | u32 num_packets, gfp_t gfp) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 89ce99675e61..9f2616fffb40 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -110,6 +110,11 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
110 | struct net_device *netdev, const u8 *peer, | 110 | struct net_device *netdev, const u8 *peer, |
111 | u32 num_packets, gfp_t gfp); | 111 | u32 num_packets, gfp_t gfp); |
112 | 112 | ||
113 | void | ||
114 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
115 | struct net_device *netdev, const u8 *peer, | ||
116 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); | ||
117 | |||
113 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | 118 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, |
114 | struct net_device *netdev, const u8 *bssid, | 119 | struct net_device *netdev, const u8 *bssid, |
115 | const u8 *replay_ctr, gfp_t gfp); | 120 | const u8 *replay_ctr, gfp_t gfp); |