From 3eb0928fc3e4b4702462164b399acddb7f0f09fd Mon Sep 17 00:00:00 2001 From: "Manoharan, Rajkumar" Date: Tue, 14 Feb 2017 12:27:16 -0800 Subject: mac80211: use DECLARE_EWMA for mesh_fail_avg As moving average is not considering fractional part, it will get stuck at the same level after certain state. For example, with current values, it can get stuck at 96. Fortunately the current threshold 95%, but if it were increased to 96 or more mesh paths would never be deactivated. Fix failure average movement by using EWMA helpers, which does take into account fractional parts. Signed-off-by: Rajkumar Manoharan [johannes: pick a larger EWMA factor for more precision with the limited range that we will feed into it, adjust to new API] Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 21 +++++++++++++++------ net/mac80211/mesh_pathtbl.c | 3 +++ net/mac80211/sta_info.h | 5 ++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index b747c9645e43..d07ee3ca07ee 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -307,10 +307,11 @@ void ieee80211s_update_metric(struct ieee80211_local *local, failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); - /* moving average, scaled to 100 */ - sta->mesh->fail_avg = - ((80 * sta->mesh->fail_avg + 5) / 100 + 20 * failed); - if (sta->mesh->fail_avg > 95) + /* moving average, scaled to 100. + * feed failure as 100 and success as 0 + */ + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, failed * 100); + if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > 95) mesh_plink_broken(sta); } @@ -325,6 +326,8 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, int rate, err; u32 tx_time, estimated_retx; u64 result; + unsigned long fail_avg = + ewma_mesh_fail_avg_read(&sta->mesh->fail_avg); /* Try to get rate based on HW/SW RC algorithm. * Rate is returned in units of Kbps, correct this @@ -336,7 +339,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (rate) { err = 0; } else { - if (sta->mesh->fail_avg >= 100) + if (fail_avg >= 100) return MAX_METRIC; sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); @@ -344,7 +347,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (WARN_ON(!rate)) return MAX_METRIC; - err = (sta->mesh->fail_avg << ARITH_SHIFT) / 100; + err = (fail_avg << ARITH_SHIFT) / 100; } /* bitrate is in units of 100 Kbps, while we need rate in units of @@ -484,6 +487,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, ? mpath->exp_time : exp_time; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock); + ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); + /* init it at a low value - 0 start is tricky */ + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1); mesh_path_tx_pending(mpath); /* draft says preq_id should be saved to, but there does * not seem to be any use for it, skipping by now @@ -522,6 +528,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, ? mpath->exp_time : exp_time; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock); + ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); + /* init it at a low value - 0 start is tricky */ + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1); mesh_path_tx_pending(mpath); } else spin_unlock_bh(&mpath->state_lock); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index f0e6175a9821..98a3b1c0c338 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -829,6 +829,9 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) mpath->flags = MESH_PATH_FIXED | MESH_PATH_SN_VALID; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock); + ewma_mesh_fail_avg_init(&next_hop->mesh->fail_avg); + /* init it at a low value - 0 start is tricky */ + ewma_mesh_fail_avg_add(&next_hop->mesh->fail_avg, 1); mesh_path_tx_pending(mpath); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e65cda34d2bc..cc413f52108e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -324,6 +324,9 @@ struct ieee80211_fast_rx { struct rcu_head rcu_head; }; +/* we use only values in the range 0-100, so pick a large precision */ +DECLARE_EWMA(mesh_fail_avg, 20, 8) + /** * struct mesh_sta - mesh STA information * @plink_lock: serialize access to plink fields @@ -369,7 +372,7 @@ struct mesh_sta { enum nl80211_mesh_power_mode nonpeer_pm; /* moving percentage of failed MSDUs */ - unsigned int fail_avg; + struct ewma_mesh_fail_avg fail_avg; }; DECLARE_EWMA(signal, 10, 8) -- cgit v1.2.3 From 4a4b8169501b18c3450ac735a7e277b24886a651 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Fri, 10 Feb 2017 10:02:31 +0100 Subject: cfg80211: Accept multiple RSSI thresholds for CQM Change the SET CQM command's RSSI threshold attribute to accept any number of thresholds as a sorted array. The API should be backwards compatible so that if one s32 threshold value is passed, the old mechanism is enabled. The netlink event generated is the same in both cases. cfg80211 handles an arbitrary number of RSSI thresholds but drivers have to provide a method (set_cqm_rssi_range_config) that configures a range set by a high and a low value. Drivers have to call back when the RSSI goes out of that range and there's no additional event for each time the range is reconfigured as there was with the current one-threshold API. This method doesn't have a hysteresis parameter because there's no benefit to the cfg80211 code from having the hysteresis be handled by hardware/driver in terms of the number of wakeups. At the same time it would likely be less consistent between drivers if offloaded or done in the drivers. Signed-off-by: Andrew Zaborowski Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 13 ++++ include/uapi/linux/nl80211.h | 9 ++- net/wireless/core.c | 9 +++ net/wireless/core.h | 9 +++ net/wireless/nl80211.c | 138 +++++++++++++++++++++++++++++++++++++++---- net/wireless/rdev-ops.h | 12 ++++ net/wireless/trace.h | 22 +++++++ 7 files changed, 198 insertions(+), 14 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ead1aa6d003e..ffc08687b31d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2712,6 +2712,11 @@ struct cfg80211_nan_func { * the current level is above/below the configured threshold; this may * need some care when the configuration is changed (without first being * disabled.) + * @set_cqm_rssi_range_config: Configure two RSSI thresholds in the + * connection quality monitor. An event is to be sent only when the + * signal level is found to be outside the two values. The driver should + * set %NL80211_EXT_FEATURE_CQM_RSSI_LIST if this method is implemented. + * If it is provided then there's no point providing @set_cqm_rssi_config. * @set_cqm_txe_config: Configure connection quality monitor TX error * thresholds. * @sched_scan_start: Tell the driver to start a scheduled scan. @@ -3001,6 +3006,10 @@ struct cfg80211_ops { struct net_device *dev, s32 rssi_thold, u32 rssi_hyst); + int (*set_cqm_rssi_range_config)(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_low, s32 rssi_high); + int (*set_cqm_txe_config)(struct wiphy *wiphy, struct net_device *dev, u32 rate, u32 pkts, u32 intvl); @@ -3871,6 +3880,7 @@ void wiphy_free(struct wiphy *wiphy); struct cfg80211_conn; struct cfg80211_internal_bss; struct cfg80211_cached_keys; +struct cfg80211_cqm_config; /** * struct wireless_dev - wireless device state @@ -3934,6 +3944,7 @@ struct cfg80211_cached_keys; * @event_list: (private) list for internal event processing * @event_lock: (private) lock for event list * @owner_nlportid: (private) owner socket port ID + * @cqm_config: (private) nl80211 RSSI monitor state */ struct wireless_dev { struct wiphy *wiphy; @@ -4002,6 +4013,8 @@ struct wireless_dev { bool prev_bssid_valid; } wext; #endif + + struct cfg80211_cqm_config *cqm_config; }; static inline u8 *wdev_address(struct wireless_dev *wdev) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5ed257c4cd4e..9a499b15cfbc 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3942,7 +3942,10 @@ enum nl80211_ps_state { * @__NL80211_ATTR_CQM_INVALID: invalid * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies * the threshold for the RSSI level at which an event will be sent. Zero - * to disable. + * to disable. Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is + * set, multiple values can be supplied as a low-to-high sorted array of + * threshold values in dBm. Events will be sent when the RSSI value + * crosses any of the thresholds. * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies * the minimum amount the RSSI level must change after an event before a * new event may be issued (to reduce effects of RSSI oscillation). @@ -4753,6 +4756,9 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan * for reporting BSSs with better RSSI than the current connected BSS * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI). + * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the + * %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more + * RSSI threshold values to monitor rather than exactly one threshold. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -4771,6 +4777,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI, + NL80211_EXT_FEATURE_CQM_RSSI_LIST, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/core.c b/net/wireless/core.c index e55e05bc4805..04143df20f7f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -954,6 +954,12 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) } EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); +void cfg80211_cqm_config_free(struct wireless_dev *wdev) +{ + kfree(wdev->cqm_config); + wdev->cqm_config = NULL; +} + void cfg80211_unregister_wdev(struct wireless_dev *wdev) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); @@ -980,6 +986,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) WARN_ON_ONCE(1); break; } + + cfg80211_cqm_config_free(wdev); } EXPORT_SYMBOL(cfg80211_unregister_wdev); @@ -1234,6 +1242,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, kzfree(wdev->wext.keys); #endif flush_work(&wdev->disconnect_wk); + cfg80211_cqm_config_free(wdev); } /* * synchronise (so that we won't find this netdev diff --git a/net/wireless/core.h b/net/wireless/core.h index 58ca206982fe..efa690a7ef8d 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -272,6 +272,13 @@ struct cfg80211_iface_destroy { u32 nlportid; }; +struct cfg80211_cqm_config { + u32 rssi_hyst; + s32 last_rssi_event_value; + int n_rssi_thresholds; + s32 rssi_thresholds[0]; +}; + void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev); /* free object */ @@ -512,4 +519,6 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, #define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; }) #endif +void cfg80211_cqm_config_free(struct wireless_dev *wdev); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d7f8be4e321a..d516527fcb8e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9473,7 +9473,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) static const struct nla_policy nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { - [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY }, [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, @@ -9502,28 +9502,123 @@ static int nl80211_set_cqm_txe(struct genl_info *info, return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl); } +static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + s32 last, low, high; + u32 hyst; + int i, n; + int err; + + /* RSSI reporting disabled? */ + if (!wdev->cqm_config) + return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0); + + /* + * Obtain current RSSI value if possible, if not and no RSSI threshold + * event has been received yet, we should receive an event after a + * connection is established and enough beacons received to calculate + * the average. + */ + if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss && + rdev->ops->get_station) { + struct station_info sinfo; + u8 *mac_addr; + + mac_addr = wdev->current_bss->pub.bssid; + + err = rdev_get_station(rdev, dev, mac_addr, &sinfo); + if (err) + return err; + + if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG)) + wdev->cqm_config->last_rssi_event_value = + (s8) sinfo.rx_beacon_signal_avg; + } + + last = wdev->cqm_config->last_rssi_event_value; + hyst = wdev->cqm_config->rssi_hyst; + n = wdev->cqm_config->n_rssi_thresholds; + + for (i = 0; i < n; i++) + if (last < wdev->cqm_config->rssi_thresholds[i]) + break; + + low = i > 0 ? + (wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN; + high = i < n ? + (wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX; + + return rdev_set_cqm_rssi_range_config(rdev, dev, low, high); +} + static int nl80211_set_cqm_rssi(struct genl_info *info, - s32 threshold, u32 hysteresis) + const s32 *thresholds, int n_thresholds, + u32 hysteresis) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; + int i, err; + s32 prev = S32_MIN; - if (threshold > 0) - return -EINVAL; - - /* disabling - hysteresis should also be zero then */ - if (threshold == 0) - hysteresis = 0; + /* Check all values negative and sorted */ + for (i = 0; i < n_thresholds; i++) { + if (thresholds[i] > 0 || thresholds[i] <= prev) + return -EINVAL; - if (!rdev->ops->set_cqm_rssi_config) - return -EOPNOTSUPP; + prev = thresholds[i]; + } if (wdev->iftype != NL80211_IFTYPE_STATION && wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis); + wdev_lock(wdev); + cfg80211_cqm_config_free(wdev); + wdev_unlock(wdev); + + if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) { + if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */ + return rdev_set_cqm_rssi_config(rdev, dev, 0, 0); + + return rdev_set_cqm_rssi_config(rdev, dev, + thresholds[0], hysteresis); + } + + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_CQM_RSSI_LIST)) + return -EOPNOTSUPP; + + if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */ + n_thresholds = 0; + + wdev_lock(wdev); + if (n_thresholds) { + struct cfg80211_cqm_config *cqm_config; + + cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) + + n_thresholds * sizeof(s32), GFP_KERNEL); + if (!cqm_config) { + err = -ENOMEM; + goto unlock; + } + + cqm_config->rssi_hyst = hysteresis; + cqm_config->n_rssi_thresholds = n_thresholds; + memcpy(cqm_config->rssi_thresholds, thresholds, + n_thresholds * sizeof(s32)); + + wdev->cqm_config = cqm_config; + } + + err = cfg80211_cqm_rssi_update(rdev, dev); + +unlock: + wdev_unlock(wdev); + + return err; } static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) @@ -9543,10 +9638,16 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] && attrs[NL80211_ATTR_CQM_RSSI_HYST]) { - s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); + const s32 *thresholds = + nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); + int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); - return nl80211_set_cqm_rssi(info, threshold, hysteresis); + if (len % 4) + return -EINVAL; + + return nl80211_set_cqm_rssi(info, thresholds, len / 4, + hysteresis); } if (attrs[NL80211_ATTR_CQM_TXE_RATE] && @@ -13983,6 +14084,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, s32 rssi_level, gfp_t gfp) { struct sk_buff *msg; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level); @@ -13990,6 +14093,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH)) return; + if (wdev->cqm_config) { + wdev->cqm_config->last_rssi_event_value = rssi_level; + + cfg80211_cqm_rssi_update(rdev, dev); + + if (rssi_level == 0) + rssi_level = wdev->cqm_config->last_rssi_event_value; + } + msg = cfg80211_prepare_cqm(dev, NULL, gfp); if (!msg) return; diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 2f425075ada8..f2baf5921091 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -749,6 +749,18 @@ rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_set_cqm_rssi_range_config(struct cfg80211_registered_device *rdev, + struct net_device *dev, s32 low, s32 high) +{ + int ret; + trace_rdev_set_cqm_rssi_range_config(&rdev->wiphy, dev, low, high); + ret = rdev->ops->set_cqm_rssi_range_config(&rdev->wiphy, dev, + low, high); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + static inline int rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev, struct net_device *dev, u32 rate, u32 pkts, u32 intvl) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 776e80cef9b4..fd55786f0462 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1322,6 +1322,28 @@ TRACE_EVENT(rdev_set_cqm_rssi_config, __entry->rssi_thold, __entry->rssi_hyst) ); +TRACE_EVENT(rdev_set_cqm_rssi_range_config, + TP_PROTO(struct wiphy *wiphy, + struct net_device *netdev, s32 low, s32 high), + TP_ARGS(wiphy, netdev, low, high), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(s32, rssi_low) + __field(s32, rssi_high) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->rssi_low = low; + __entry->rssi_high = high; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT + ", range: %d - %d ", + WIPHY_PR_ARG, NETDEV_PR_ARG, + __entry->rssi_low, __entry->rssi_high) +); + TRACE_EVENT(rdev_set_cqm_txe_config, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate, u32 pkts, u32 intvl), -- cgit v1.2.3 From 2c3c5f8c0cfa8e88a4c34d7651b5712c558ab9b7 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Fri, 10 Feb 2017 04:50:22 +0100 Subject: mac80211: Add set_cqm_rssi_range_config Support .set_cqm_rssi_range_config if the beacons are available for processing in mac80211. There's no reason that this couldn't be offloaded by mac80211-based drivers but there's no driver method for that added in this patch. Signed-off-by: Andrew Zaborowski Signed-off-by: Johannes Berg --- include/net/mac80211.h | 6 ++++++ net/mac80211/cfg.c | 28 ++++++++++++++++++++++++++++ net/mac80211/mlme.c | 24 ++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a3bab3c5ecfb..1a26a375feb8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -501,6 +501,10 @@ struct ieee80211_mu_group_data { * implies disabled. As with the cfg80211 callback, a change here should * cause an event to be sent indicating where the current value is in * relation to the newly configured threshold. + * @cqm_rssi_low: Connection quality monitor RSSI lower threshold, a zero value + * implies disabled. This is an alternative mechanism to the single + * threshold event and can't be enabled simultaneously with it. + * @cqm_rssi_high: Connection quality monitor RSSI upper threshold. * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The * may filter ARP queries targeted for other addresses than listed here. @@ -553,6 +557,8 @@ struct ieee80211_bss_conf { u16 ht_operation_mode; s32 cqm_rssi_thold; u32 cqm_rssi_hyst; + s32 cqm_rssi_low; + s32 cqm_rssi_high; struct cfg80211_chan_def chandef; struct ieee80211_mu_group_data mu_group; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ac879bb17870..9c7490cb2243 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2630,6 +2630,33 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, bss_conf->cqm_rssi_thold = rssi_thold; bss_conf->cqm_rssi_hyst = rssi_hyst; + bss_conf->cqm_rssi_low = 0; + bss_conf->cqm_rssi_high = 0; + sdata->u.mgd.last_cqm_event_signal = 0; + + /* tell the driver upon association, unless already associated */ + if (sdata->u.mgd.associated && + sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); + + return 0; +} + +static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_low, s32 rssi_high) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_vif *vif = &sdata->vif; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) + return -EOPNOTSUPP; + + bss_conf->cqm_rssi_low = rssi_low; + bss_conf->cqm_rssi_high = rssi_high; + bss_conf->cqm_rssi_thold = 0; + bss_conf->cqm_rssi_hyst = 0; sdata->u.mgd.last_cqm_event_signal = 0; /* tell the driver upon association, unless already associated */ @@ -3639,6 +3666,7 @@ const struct cfg80211_ops mac80211_config_ops = { .mgmt_tx = ieee80211_mgmt_tx, .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait, .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, + .set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config, .mgmt_frame_register = ieee80211_mgmt_frame_register, .set_antenna = ieee80211_set_antenna, .get_antenna = ieee80211_get_antenna, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6e90301154d5..23986934d7af 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3430,6 +3430,30 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } } + if (bss_conf->cqm_rssi_low && + ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { + int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal); + int last_event = ifmgd->last_cqm_event_signal; + int low = bss_conf->cqm_rssi_low; + int high = bss_conf->cqm_rssi_high; + + if (sig < low && + (last_event == 0 || last_event >= low)) { + ifmgd->last_cqm_event_signal = sig; + ieee80211_cqm_rssi_notify( + &sdata->vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + sig, GFP_KERNEL); + } else if (sig > high && + (last_event == 0 || last_event <= high)) { + ifmgd->last_cqm_event_signal = sig; + ieee80211_cqm_rssi_notify( + &sdata->vif, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + sig, GFP_KERNEL); + } + } + if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { mlme_dbg_ratelimited(sdata, "cancelling AP probe due to a received beacon\n"); -- cgit v1.2.3 From ae44b502669d0cd1f167cdb48994292aa20fd3dd Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Fri, 10 Feb 2017 04:50:23 +0100 Subject: wireless: Set NL80211_EXT_FEATURE_CQM_RSSI_LIST in multiple drivers Set the NL80211_EXT_FEATURE_CQM_RSSI_LIST wiphy extended feature wholesale in all mac80211-based drivers that do not set the IEEE80211_VIF_BEACON_FILTER flags on their interfaces. mac80211 will be processing supplied RSSI values in ieee80211_rx_mgmt_beacon and will detect when the thresholds set by ieee80211_set_cqm_rssi_range_config are crossed. Remaining (few) drivers need code to enable the firmware to monitor the thresholds. This is mostly only compile-tested. Signed-off-by: Andrew Zaborowski Signed-off-by: Johannes Berg --- drivers/net/wireless/admtek/adm8211.c | 2 ++ drivers/net/wireless/ath/ar5523/ar5523.c | 2 ++ drivers/net/wireless/ath/ath10k/mac.c | 2 ++ drivers/net/wireless/ath/ath5k/base.c | 2 ++ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 ++ drivers/net/wireless/ath/ath9k/init.c | 2 ++ drivers/net/wireless/ath/carl9170/main.c | 2 ++ drivers/net/wireless/ath/wcn36xx/main.c | 3 +++ drivers/net/wireless/atmel/at76c50x-usb.c | 2 ++ drivers/net/wireless/broadcom/b43/main.c | 2 ++ drivers/net/wireless/broadcom/b43legacy/main.c | 2 ++ drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c | 2 ++ drivers/net/wireless/intel/iwlegacy/3945-mac.c | 2 ++ drivers/net/wireless/intel/iwlegacy/4965-mac.c | 2 ++ drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 2 ++ drivers/net/wireless/mac80211_hwsim.c | 2 ++ drivers/net/wireless/marvell/libertas_tf/main.c | 2 ++ drivers/net/wireless/marvell/mwl8k.c | 2 ++ drivers/net/wireless/mediatek/mt7601u/init.c | 2 ++ drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 3 +++ drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 ++ drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 ++ drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 ++ drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 ++ drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 2 ++ 25 files changed, 52 insertions(+) diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 098c814e22c8..ed626f568b58 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1917,6 +1917,8 @@ static int adm8211_probe(struct pci_dev *pdev, dev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; + wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + err = ieee80211_register_hw(dev); if (err) { printk(KERN_ERR "%s (adm8211): Cannot register device\n", diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 7a60d2e652da..f2f4ccfdf8da 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1689,6 +1689,8 @@ static int ar5523_probe(struct usb_interface *intf, if (error) goto out_cancel_rx_cmd; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + usb_set_intfdata(intf, hw); error = ieee80211_register_hw(hw); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3029f257a19a..abc291de1d31 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8248,6 +8248,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->cipher_suites = cipher_suites; ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = ieee80211_register_hw(ar->hw); if (ret) { ath10k_err(ar, "failed to register ieee80211: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index d98fd421c7ec..92ece64fd455 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2564,6 +2564,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) hw->extra_tx_headroom = 2; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + /* * Mark the device as detached to avoid processing * interrupts until setup is complete. diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index b65c1b661ade..defacc6c9c99 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -780,6 +780,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, } SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); } static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fa4b3cc1ba22..fd9a61834c17 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -955,6 +955,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_cmn_reload_chainmask(ah); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); } int ath9k_init_device(u16 devid, struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ffb22a04beeb..988c8857d78c 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1874,6 +1874,8 @@ void *carl9170_alloc(size_t priv_size) for (i = 0; i < ARRAY_SIZE(ar->noise); i++) ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + return ar; err_nomem: diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 7a0c2e7da7f6..cee4f655bf36 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1112,6 +1112,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta); wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif); + wiphy_ext_feature_set(wcn->hw->wiphy, + NL80211_EXT_FEATURE_CQM_RSSI_LIST); + return ret; } diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 0e180677c7fc..09defbcedd5e 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -2377,6 +2377,8 @@ static int at76_init_new_device(struct at76_priv *priv, wiphy->hw_version = priv->board_type; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = ieee80211_register_hw(priv->hw); if (ret) { printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n", diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 52f3541ecbcf..d23aac7503d3 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -5598,6 +5598,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wl->hw_registred = false; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index cdafebb9c936..f1e3dad57629 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -3850,6 +3850,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev) else SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + /* Get and initialize struct b43legacy_wl */ wl = hw_to_b43legacy_wl(hw); memset(wl, 0, sizeof(*wl)); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 7c2a9a9bc372..ddfdfe177e24 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -1082,6 +1082,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw) * hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; */ + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + hw->rate_control_algorithm = "minstrel_ht"; hw->sta_data_size = 0; diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index e8e65115feba..38bf403bb1e1 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3592,6 +3592,8 @@ il3945_setup_mac(struct il_priv *il) il_leds_init(il); + wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = ieee80211_register_hw(il->hw); if (ret) { IL_ERR("Failed to register hw (error %d)\n", ret); diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 2781f5728d07..7eda525e3f4f 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -5799,6 +5799,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) il_leds_init(il); + wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = ieee80211_register_hw(il->hw); if (ret) { IL_ERR("Failed to register hw (error %d)\n", ret); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 2a04d0cd71ae..e3cab60ddf0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -213,6 +213,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, iwl_leds_init(priv); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = ieee80211_register_hw(priv->hw); if (ret) { IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 50c219fb1a52..307a53a7da23 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2645,6 +2645,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, if (param->no_vif) ieee80211_hw_set(hw, NO_AUTO_VIF); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + err = ieee80211_register_hw(hw); if (err < 0) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 54e426c1e405..d80333117989 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -641,6 +641,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) BIT(NL80211_IFTYPE_ADHOC); skb_queue_head_init(&priv->bc_ps_buf); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + SET_IEEE80211_DEV(hw, dmdev); INIT_WORK(&priv->cmd_work, lbtf_cmd_work); diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index b1b400b59d86..c295a4c6e5cd 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -6144,6 +6144,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) if (priv->sta_macids_supported || priv->device_info->fw_image_sta) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + rc = ieee80211_register_hw(hw); if (rc) { wiphy_err(hw->wiphy, "Cannot register device\n"); diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index a6e901766226..d3b611aaf061 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -615,6 +615,8 @@ int mt7601u_register_device(struct mt7601u_dev *dev) wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = mt76_init_sband_2g(dev); if (ret) return ret; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index dd6678109b7e..57e6af9a44a1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -1384,6 +1384,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy_ext_feature_set(rt2x00dev->hw->wiphy, + NL80211_EXT_FEATURE_CQM_RSSI_LIST); + /* * Initialize ieee80211 structure. */ diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index e895a84481da..e387dec82d3d 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1877,6 +1877,8 @@ static int rtl8180_probe(struct pci_dev *pdev, else ieee80211_hw_set(dev, SIGNAL_UNSPEC); + wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + rtl8180_eeprom_read(priv); switch (priv->rf_type) { diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 231f84db9ab0..274ad6d34d68 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1609,6 +1609,8 @@ static int rtl8187_probe(struct usb_interface *intf, dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) ; + wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) printk(KERN_INFO "rtl8187: inconsistency between id with OEM" " info!\n"); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index e544dd1d618c..9b4a9a00be64 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6135,6 +6135,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, AMPDU_AGGREGATION); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ret = ieee80211_register_hw(priv->hw); if (ret) { dev_err(&udev->dev, "%s: Failed to register: %i\n", diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index e3216473aecb..021e5ac5f107 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1261,6 +1261,8 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->reg_notifier = rsi_reg_notify; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + status = ieee80211_register_hw(hw); if (status) return status; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 3e37a045f702..fe6517a621b0 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -1408,6 +1408,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + hw->max_signal = 100; hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); -- cgit v1.2.3 From d4f29978675d7d07e7bb9da30ed05ecf588820a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Feb 2017 20:53:38 +0100 Subject: cfg80211: combine two nested ifs into a single condition Combine two instances of having two nested if statements into a single one with a combined condition to reduce the indentation. Signed-off-by: Johannes Berg --- net/wireless/core.c | 12 ++++++------ net/wireless/util.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 04143df20f7f..76e664144c8e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1216,12 +1216,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, */ if ((wdev->iftype == NL80211_IFTYPE_STATION || wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && - rdev->ops->set_power_mgmt) - if (rdev_set_power_mgmt(rdev, dev, wdev->ps, - wdev->ps_timeout)) { - /* assume this means it's off */ - wdev->ps = false; - } + rdev->ops->set_power_mgmt && + rdev_set_power_mgmt(rdev, dev, wdev->ps, + wdev->ps_timeout)) { + /* assume this means it's off */ + wdev->ps = false; + } break; case NETDEV_UNREGISTER: /* diff --git a/net/wireless/util.c b/net/wireless/util.c index 68e5f2ecee1a..daef500a7b64 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -914,11 +914,11 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) netdev_err(dev, "failed to set key %d\n", i); continue; } - if (wdev->connect_keys->def == i) - if (rdev_set_default_key(rdev, dev, i, true, true)) { - netdev_err(dev, "failed to set defkey %d\n", i); - continue; - } + if (wdev->connect_keys->def == i && + rdev_set_default_key(rdev, dev, i, true, true)) { + netdev_err(dev, "failed to set defkey %d\n", i); + continue; + } } kzfree(wdev->connect_keys); -- cgit v1.2.3 From f22775ede2eb58ed84b55e30768d041f607a2199 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 13 Feb 2017 14:37:41 +0200 Subject: ieee80211: add FT-PSK AKM suite selector Signed-off-by: Avraham Stern Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0dd9498c694f..6ea381c98aae 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2347,6 +2347,7 @@ enum ieee80211_sa_query_action { /* AKM suite selectors */ #define WLAN_AKM_SUITE_8021X SUITE(0x000FAC, 1) #define WLAN_AKM_SUITE_PSK SUITE(0x000FAC, 2) +#define WLAN_AKM_SUITE_FT_PSK SUITE(0x000FAC, 4) #define WLAN_AKM_SUITE_8021X_SHA256 SUITE(0x000FAC, 5) #define WLAN_AKM_SUITE_PSK_SHA256 SUITE(0x000FAC, 6) #define WLAN_AKM_SUITE_TDLS SUITE(0x000FAC, 7) -- cgit v1.2.3 From 68506e9af132a6b5735c1dd4b11240da0cf5eeae Mon Sep 17 00:00:00 2001 From: Arkadiusz Miskiewicz Date: Wed, 15 Feb 2017 14:21:27 +0100 Subject: mac80211: Print text for disassociation reason MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When disassociation happens only numeric reason is printed in ieee80211_rx_mgmt_disassoc(). Add text variant, too. Signed-off-by: Arkadiusz Miƛkiewicz Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 23986934d7af..1568a74757bc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2797,8 +2797,9 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - sdata_info(sdata, "disassociated from %pM (Reason: %u)\n", - mgmt->sa, reason_code); + sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n", + mgmt->sa, reason_code, + ieee80211_get_reason_code_string(reason_code)); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); -- cgit v1.2.3 From 2fb51c35815dc08638a7d9b1a497a9d7cb4109b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Feb 2017 15:02:06 +0100 Subject: ieee80211: rename CCFS1/CCFS2 to CCFS0/CCFS1 This matches the spec, and otherwise things are really confusing with the next patch adding CCFS2. Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/mwifiex/tdls.c | 2 +- include/linux/ieee80211.h | 4 ++-- net/mac80211/spectmgmt.c | 4 ++-- net/mac80211/util.c | 22 +++++++++++----------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index df9704de0715..5fc8319ed302 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -349,7 +349,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT; break; } - vht_oper->center_freq_seg1_idx = + vht_oper->center_freq_seg0_idx = mwifiex_get_center_freq_index(priv, BAND_AAC, bss_desc->channel, chan_bw); diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 6ea381c98aae..e167a262d3b0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1525,14 +1525,14 @@ enum ieee80211_vht_chanwidth { * This structure is the "VHT operation element" as * described in 802.11ac D3.0 8.4.2.161 * @chan_width: Operating channel width + * @center_freq_seg0_idx: center freq segment 0 index * @center_freq_seg1_idx: center freq segment 1 index - * @center_freq_seg2_idx: center freq segment 2 index * @basic_mcs_set: VHT Basic MCS rate set */ struct ieee80211_vht_operation { u8 chan_width; + u8 center_freq_seg0_idx; u8 center_freq_seg1_idx; - u8 center_freq_seg2_idx; __le16 basic_mcs_set; } __packed; diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 97f4c9d6b54c..0782e486fe89 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -132,9 +132,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, struct ieee80211_vht_operation vht_oper = { .chan_width = wide_bw_chansw_ie->new_channel_width, - .center_freq_seg1_idx = + .center_freq_seg0_idx = wide_bw_chansw_ie->new_center_freq_seg0, - .center_freq_seg2_idx = + .center_freq_seg1_idx = wide_bw_chansw_ie->new_center_freq_seg1, /* .basic_mcs_set doesn't matter */ }; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ac59fbd280df..7a37ce78bb38 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2413,13 +2413,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, *pos++ = WLAN_EID_VHT_OPERATION; *pos++ = sizeof(struct ieee80211_vht_operation); vht_oper = (struct ieee80211_vht_operation *)pos; - vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel( + vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel( chandef->center_freq1); if (chandef->center_freq2) - vht_oper->center_freq_seg2_idx = + vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(chandef->center_freq2); else - vht_oper->center_freq_seg2_idx = 0x00; + vht_oper->center_freq_seg1_idx = 0x00; switch (chandef->width) { case NL80211_CHAN_WIDTH_160: @@ -2428,11 +2428,11 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, * workaround. */ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; - vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx; + vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx; if (chandef->chan->center_freq < chandef->center_freq1) - vht_oper->center_freq_seg1_idx -= 8; + vht_oper->center_freq_seg0_idx -= 8; else - vht_oper->center_freq_seg1_idx += 8; + vht_oper->center_freq_seg0_idx += 8; break; case NL80211_CHAN_WIDTH_80P80: /* @@ -2491,9 +2491,9 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, if (!oper) return false; - cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, + cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx, chandef->chan->band); - cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx, + cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, chandef->chan->band); switch (oper->chan_width) { @@ -2503,11 +2503,11 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, new.width = NL80211_CHAN_WIDTH_80; new.center_freq1 = cf1; /* If needed, adjust based on the newer interop workaround. */ - if (oper->center_freq_seg2_idx) { + if (oper->center_freq_seg1_idx) { unsigned int diff; - diff = abs(oper->center_freq_seg2_idx - - oper->center_freq_seg1_idx); + diff = abs(oper->center_freq_seg1_idx - + oper->center_freq_seg0_idx); if (diff == 8) { new.width = NL80211_CHAN_WIDTH_160; new.center_freq1 = cf2; -- cgit v1.2.3 From a858958b689211dcfe54cdd94c93160d2d659eba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Feb 2017 15:02:07 +0100 Subject: mac80211: remove local pointer from rate_ctrl_ref This pointer really isn't needed, so remove it. Signed-off-by: Johannes Berg --- net/mac80211/rate.c | 10 +++++----- net/mac80211/rate.h | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 206698bc93f4..094c15645228 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -208,7 +208,6 @@ static struct rate_control_ref *rate_control_alloc(const char *name, ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); if (!ref) return NULL; - ref->local = local; ref->ops = ieee80211_rate_control_ops_get(name); if (!ref->ops) goto free; @@ -229,13 +228,14 @@ free: return NULL; } -static void rate_control_free(struct rate_control_ref *ctrl_ref) +static void rate_control_free(struct ieee80211_local *local, + struct rate_control_ref *ctrl_ref) { ctrl_ref->ops->free(ctrl_ref->priv); #ifdef CONFIG_MAC80211_DEBUGFS - debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir); - ctrl_ref->local->debugfs.rcdir = NULL; + debugfs_remove_recursive(local->debugfs.rcdir); + local->debugfs.rcdir = NULL; #endif kfree(ctrl_ref); @@ -936,6 +936,6 @@ void rate_control_deinitialize(struct ieee80211_local *local) return; local->rate_ctrl = NULL; - rate_control_free(ref); + rate_control_free(local, ref); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 8d3260785b94..d51a1cce4d4a 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -20,7 +20,6 @@ #include "driver-ops.h" struct rate_control_ref { - struct ieee80211_local *local; const struct rate_control_ops *ops; void *priv; }; -- cgit v1.2.3 From 0c1eca4e2f96000077900e0108fff23994c73486 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Feb 2017 15:02:08 +0100 Subject: cfg80211: refactor cfg80211_calculate_bitrate() This function contains the HT calculations, which makes no sense - split that out into a separate function. As a side effect, this makes the 60G flag independent from HT_MCS so remove the MCS one from wil6210 (also deleting a duplicate assignment.) Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/wil6210/cfg80211.c | 3 +- net/wireless/util.c | 60 +++++++++++++++-------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 83155b5ddbfb..79d107018eac 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -178,9 +178,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, BIT(NL80211_STA_INFO_RX_DROP_MISC) | BIT(NL80211_STA_INFO_TX_FAILED); - sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; + sinfo->txrate.flags = RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); - sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->rxrate.mcs = stats->last_mcs_rx; sinfo->rx_bytes = stats->rx_bytes; sinfo->rx_packets = stats->rx_packets; diff --git a/net/wireless/util.c b/net/wireless/util.c index daef500a7b64..737c9c2c9cc9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1097,6 +1097,35 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return err; } +static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + /* the formula below does only work for MCS values smaller than 32 */ + if (WARN_ON_ONCE(rate->mcs >= 32)) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) { static const u32 __mcs2bitrate[] = { @@ -1230,39 +1259,14 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) u32 cfg80211_calculate_bitrate(struct rate_info *rate) { - int modulation, streams, bitrate; - - if (!(rate->flags & RATE_INFO_FLAGS_MCS) && - !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) - return rate->legacy; + if (rate->flags & RATE_INFO_FLAGS_MCS) + return cfg80211_calculate_bitrate_ht(rate); if (rate->flags & RATE_INFO_FLAGS_60G) return cfg80211_calculate_bitrate_60g(rate); if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) return cfg80211_calculate_bitrate_vht(rate); - /* the formula below does only work for MCS values smaller than 32 */ - if (WARN_ON_ONCE(rate->mcs >= 32)) - return 0; - - modulation = rate->mcs & 7; - streams = (rate->mcs >> 3) + 1; - - bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; - - if (modulation < 4) - bitrate *= (modulation + 1); - else if (modulation == 4) - bitrate *= (modulation + 2); - else - bitrate *= (modulation + 3); - - bitrate *= streams; - - if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) - bitrate = (bitrate / 9) * 10; - - /* do NOT round down here */ - return (bitrate + 50000) / 100000; + return rate->legacy; } EXPORT_SYMBOL(cfg80211_calculate_bitrate); -- cgit v1.2.3 From 7f406cd16a0f0965c761ea02bc1f03154b06bbfb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Feb 2017 15:02:09 +0100 Subject: mac80211: encode rate type (legacy, HT, VHT) with fewer bits We don't really need three different bits for each, since the types are mutually exclusive. Use just two bits for it. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 11 ++++++++--- net/mac80211/sta_info.h | 13 +++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3323a2fb289b..81ec1f72518d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1960,14 +1960,17 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate, rinfo->bw = (rate & STA_STATS_RATE_BW_MASK) >> STA_STATS_RATE_BW_SHIFT; - if (rate & STA_STATS_RATE_VHT) { + switch (rate & STA_STATS_RATE_TYPE_MASK) { + case STA_STATS_RATE_TYPE_VHT: rinfo->flags = RATE_INFO_FLAGS_VHT_MCS; rinfo->mcs = rate & 0xf; rinfo->nss = (rate & 0xf0) >> 4; - } else if (rate & STA_STATS_RATE_HT) { + break; + case STA_STATS_RATE_TYPE_HT: rinfo->flags = RATE_INFO_FLAGS_MCS; rinfo->mcs = rate & 0xff; - } else if (rate & STA_STATS_RATE_LEGACY) { + break; + case STA_STATS_RATE_TYPE_LEGACY: { struct ieee80211_supported_band *sband; u16 brate; unsigned int shift; @@ -1982,6 +1985,8 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate, else shift = 0; rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); + break; + } } if (rate & STA_STATS_RATE_SGI) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index cc413f52108e..8949266d7bc3 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -728,9 +728,10 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); unsigned long ieee80211_sta_last_active(struct sta_info *sta); #define STA_STATS_RATE_INVALID 0 -#define STA_STATS_RATE_VHT 0x8000 -#define STA_STATS_RATE_HT 0x4000 -#define STA_STATS_RATE_LEGACY 0x2000 +#define STA_STATS_RATE_TYPE_MASK 0xC000 +#define STA_STATS_RATE_TYPE_LEGACY 0x4000 +#define STA_STATS_RATE_TYPE_HT 0x8000 +#define STA_STATS_RATE_TYPE_VHT 0xC000 #define STA_STATS_RATE_SGI 0x1000 #define STA_STATS_RATE_BW_SHIFT 9 #define STA_STATS_RATE_BW_MASK (0x7 << STA_STATS_RATE_BW_SHIFT) @@ -756,11 +757,11 @@ static inline u16 sta_stats_encode_rate(struct ieee80211_rx_status *s) r |= STA_STATS_RATE_SGI; if (s->flag & RX_FLAG_VHT) - r |= STA_STATS_RATE_VHT | (s->vht_nss << 4); + r |= STA_STATS_RATE_TYPE_VHT | (s->vht_nss << 4); else if (s->flag & RX_FLAG_HT) - r |= STA_STATS_RATE_HT; + r |= STA_STATS_RATE_TYPE_HT; else - r |= STA_STATS_RATE_LEGACY | (s->band << 4); + r |= STA_STATS_RATE_TYPE_LEGACY | (s->band << 4); return r; } -- cgit v1.2.3 From 75b99bc300463e65f87c90425704c2688489f963 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Feb 2017 15:02:10 +0100 Subject: ieee80211: define HT operation CCFS2 field The Channel Center Frequency Segment 2 field is used in 802.11-2016 for encoding the actual channel position of the 80+80/160 MHz channel, if the max NSS is restricted. This is used for backwards compatibility. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e167a262d3b0..22bf0676d928 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1411,6 +1411,8 @@ struct ieee80211_ht_operation { #define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3 #define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004 #define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010 +#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5 +#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0 /* for stbc_param */ #define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040 -- cgit v1.2.3 From fe56c9c17b09769691e8b91747b32aa2555bef35 Mon Sep 17 00:00:00 2001 From: "Manoharan, Rajkumar" Date: Wed, 15 Feb 2017 12:46:50 -0800 Subject: mac80211: fix mesh fail_avg check Mesh failure average never be more than 100. Only in case of fixed path, average will be more than threshold limit (95%). With recent EWMA changes it may go upto 99 as it is scaled to 100. It make sense to return maximum metric when average is greater than threshold limit. Signed-off-by: Rajkumar Manoharan Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index d07ee3ca07ee..4005edd71fe8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -16,6 +16,7 @@ #define TEST_FRAME_LEN 8192 #define MAX_METRIC 0xffffffff #define ARITH_SHIFT 8 +#define LINK_FAIL_THRESH 95 #define MAX_PREQ_QUEUE_LEN 64 @@ -311,7 +312,8 @@ void ieee80211s_update_metric(struct ieee80211_local *local, * feed failure as 100 and success as 0 */ ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, failed * 100); - if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > 95) + if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > + LINK_FAIL_THRESH) mesh_plink_broken(sta); } @@ -339,7 +341,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (rate) { err = 0; } else { - if (fail_avg >= 100) + if (fail_avg > LINK_FAIL_THRESH) return MAX_METRIC; sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); -- cgit v1.2.3 From f7d3b4f5203832f57ece96300888323fd5a6c6b3 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Thu, 23 Feb 2017 13:02:10 +0100 Subject: mac80211_hwsim: Make sure NEW_RADIO contains final name ieee80211_alloc_hw_nm will validate the requested name (if any) before creating the new device and may use a name different from the one requested rather than fail. Make sure the HWSIM_CMD_NEW_RADIO event/response generated has the final name or userspace will receive the wrong name. Note that mac80211_hwsim_new_radio may now modify params. A check for duplicate radio name could be added separately. Signed-off-by: Andrew Zaborowski Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 307a53a7da23..7b9662ae0143 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2438,6 +2438,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, goto failed; } + /* ieee80211_alloc_hw_nm may have used a default name */ + param->hwname = wiphy_name(hw->wiphy); + if (info) net = genl_info_net(info); else -- cgit v1.2.3 From 037651950d5800f236407e139572433a53efb798 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Mar 2017 09:39:40 +0100 Subject: mac80211_hwsim: fix command documentation indentation Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index 39f22467ca2a..3f5eda591dba 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -57,12 +57,12 @@ enum hwsim_tx_control_flags { * @HWSIM_CMD_REGISTER: request to register and received all broadcasted * frames by any mac80211_hwsim radio device. * @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user - * space, uses: + * space, uses: * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional) * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to - * kernel, uses: + * kernel, uses: * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters, -- cgit v1.2.3 From 85bbd80373a7cc9d06d3ef103b1a93d934a8da43 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 6 Mar 2017 11:56:06 +0200 Subject: mac80211_hwsim: Add channel 169 (5845 MHz) This channel is defined in the IEEE 802.11 standard and available in number of countries, so extend the mac80211_hwsim channel list to cover channel 169 to enable additional testing. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7b9662ae0143..8b823c70ab69 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -350,6 +350,7 @@ sta