* [PATCH] cfg80211: Create structure for combination check/iter function parameters
From: Purushottam Kushwaha @ 2016-10-10 12:06 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, jouni, usdutt, amarnath, pkushwah
Move growing parameter list to a structure for check/iter combination
functions in cfg80211 and mac80211.
Signed-off-by: Purushottam Kushwaha <pkushwah@qti.qualcomm.com>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 25 ++++-----
include/net/cfg80211.h | 56 ++++++++++----------
net/mac80211/util.c | 42 ++++++++-------
net/wireless/util.c | 59 +++++++++-------------
4 files changed, 86 insertions(+), 96 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 1e73c88..00c5fb2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -414,24 +414,25 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif,
enum nl80211_iftype new_type)
{
- int iftype_num[NUM_NL80211_IFTYPES];
+ struct iface_combination_params params;
struct brcmf_cfg80211_vif *pos;
bool check_combos = false;
int ret = 0;
- memset(&iftype_num[0], 0, sizeof(iftype_num));
+ memset(¶ms, 0, sizeof(params));
+ params.num_different_channels = 1;
+
list_for_each_entry(pos, &cfg->vif_list, list)
if (pos == vif) {
- iftype_num[new_type]++;
+ params.iftype_num[new_type]++;
} else {
/* concurrent interfaces so need check combinations */
check_combos = true;
- iftype_num[pos->wdev.iftype]++;
+ params.iftype_num[pos->wdev.iftype]++;
}
if (check_combos)
- ret = cfg80211_check_combinations(cfg->wiphy, 1, 0,
- iftype_num, 0, false);
+ ret = cfg80211_check_combinations(cfg->wiphy, ¶ms);
return ret;
}
@@ -439,16 +440,16 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype new_type)
{
- int iftype_num[NUM_NL80211_IFTYPES];
+ struct iface_combination_params params;
struct brcmf_cfg80211_vif *pos;
- memset(&iftype_num[0], 0, sizeof(iftype_num));
+ memset(¶ms, 0, sizeof(params));
list_for_each_entry(pos, &cfg->vif_list, list)
- iftype_num[pos->wdev.iftype]++;
+ params.iftype_num[pos->wdev.iftype]++;
- iftype_num[new_type]++;
- return cfg80211_check_combinations(cfg->wiphy, 1, 0,
- iftype_num, 0, false);
+ params.iftype_num[new_type]++;
+ params.num_different_channels = 1;
+ return cfg80211_check_combinations(cfg->wiphy, ¶ms);
}
static void convert_key_from_CPU(struct brcmf_wsec_key *key,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 49aa6a0..4e509ed 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -772,6 +772,30 @@ struct cfg80211_csa_settings {
};
/**
+ * struct iface_combination_params - input parameters for interface combinations
+ *
+ * Used to pass interface combination parameters
+ *
+ * @num_different_channels: the number of different channels we want
+ * to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+ * width where radar detection is needed, as in the definition of
+ * &struct ieee80211_iface_combination.@radar_detect_widths
+ * @iftype_num: array with the numbers of interfaces of each interface
+ * type. The index is the interface type as specified in &enum
+ * nl80211_iftype.
+ * @beacon_gcd: a value specifying GCD of all beaconing interfaces.
+ * @diff_bi: a flag which denotes beacon intervals are different or same.
+ */
+struct iface_combination_params {
+ int num_different_channels;
+ u8 radar_detect;
+ int iftype_num[NUM_NL80211_IFTYPES];
+ u32 beacon_gcd;
+ bool diff_bi;
+};
+
+/**
* enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
* @STATION_PARAM_APPLY_CAPABILITY: apply new capability
@@ -5583,41 +5607,20 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
* cfg80211_check_combinations - check interface combinations
*
* @wiphy: the wiphy
- * @num_different_channels: the number of different channels we want
- * to use for verification
- * @radar_detect: a bitmap where each bit corresponds to a channel
- * width where radar detection is needed, as in the definition of
- * &struct ieee80211_iface_combination.@radar_detect_widths
- * @iftype_num: array with the numbers of interfaces of each interface
- * type. The index is the interface type as specified in &enum
- * nl80211_iftype.
- * @beacon_gcd: a value specifying GCD of all beaconing interfaces.
- * @diff_bi: a flag which denotes beacon intervals are different or same.
+ * @params: the interface combinations parameter.
*
* This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to
* the interface combinations.
*/
int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
- const u32 beacon_gcd, bool diff_bi);
+ struct iface_combination_params *params);
/**
* cfg80211_iter_combinations - iterate over matching combinations
*
* @wiphy: the wiphy
- * @num_different_channels: the number of different channels we want
- * to use for verification
- * @radar_detect: a bitmap where each bit corresponds to a channel
- * width where radar detection is needed, as in the definition of
- * &struct ieee80211_iface_combination.@radar_detect_widths
- * @iftype_num: array with the numbers of interfaces of each interface
- * type. The index is the interface type as specified in &enum
- * nl80211_iftype.
- * @beacon_gcd: a value specifying GCD of all beaconing interfaces.
- * @diff_bi: a flag which denotes beacon intervals are different or same.
+ * @params: the interface combinations parameter.
* @iter: function to call for each matching combination
* @data: pointer to pass to iter function
*
@@ -5626,10 +5629,7 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
* purposes.
*/
int cfg80211_iter_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
- const u32 beacon_gcd, bool diff_bi,
+ struct iface_combination_params *params,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index cfef5ce..0607fe1 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3308,9 +3308,8 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype;
- int num[NUM_NL80211_IFTYPES];
+ struct iface_combination_params params;
struct ieee80211_chanctx *ctx;
- int num_different_channels = 0;
int total = 1;
lockdep_assert_held(&local->chanctx_mtx);
@@ -3322,9 +3321,6 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
!chandef->chan))
return -EINVAL;
- if (chandef)
- num_different_channels = 1;
-
if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL;
@@ -3335,24 +3331,27 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
return 0;
}
- memset(num, 0, sizeof(num));
+ memset(¶ms, 0, sizeof(params));
+
+ if (chandef)
+ params.num_different_channels = 1;
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
- num[iftype] = 1;
+ params.iftype_num[iftype] = 1;
list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue;
radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
- num_different_channels++;
+ params.num_different_channels++;
continue;
}
if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
cfg80211_chandef_compatible(chandef,
&ctx->conf.def))
continue;
- num_different_channels++;
+ params.num_different_channels++;
}
list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
@@ -3365,16 +3364,16 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
continue;
- num[wdev_iter->iftype]++;
+ params.iftype_num[wdev_iter->iftype]++;
total++;
}
if (total == 1 && !radar_detect)
return 0;
- return cfg80211_check_combinations(local->hw.wiphy,
- num_different_channels,
- radar_detect, num, 0, false);
+ params.radar_detect = radar_detect;
+
+ return cfg80211_check_combinations(local->hw.wiphy, ¶ms);
}
static void
@@ -3390,30 +3389,29 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
int ieee80211_max_num_channels(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
- int num[NUM_NL80211_IFTYPES] = {};
struct ieee80211_chanctx *ctx;
- int num_different_channels = 0;
- u8 radar_detect = 0;
+ struct iface_combination_params params;
u32 max_num_different_channels = 1;
int err;
lockdep_assert_held(&local->chanctx_mtx);
+ memset(¶ms, 0, sizeof(params));
list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue;
- num_different_channels++;
+ params.num_different_channels++;
- radar_detect |= ieee80211_chanctx_radar_detect(local, ctx);
+ params.radar_detect |=
+ ieee80211_chanctx_radar_detect(local, ctx);
}
list_for_each_entry_rcu(sdata, &local->interfaces, list)
- num[sdata->wdev.iftype]++;
+ params.iftype_num[sdata->wdev.iftype]++;
- err = cfg80211_iter_combinations(local->hw.wiphy,
- num_different_channels, radar_detect,
- num, 0, false, ieee80211_iter_max_chans,
+ err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
+ ieee80211_iter_max_chans,
&max_num_different_channels);
if (err < 0)
return err;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 0d3bda4..fe39ece 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1562,52 +1562,47 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, u32 beacon_int)
{
struct wireless_dev *wdev;
- bool diff_bi = false;
int res = 0;
- u32 bi_prev, tmp_bi, gcd;
- int iftype_num[NUM_NL80211_IFTYPES];
+ u32 bi_prev, tmp_bi;
+ struct iface_combination_params params;
if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL;
- memset(iftype_num, 0, sizeof(iftype_num));
- iftype_num[iftype] = 1;
+ memset(¶ms, 0, sizeof(params));
+ params.iftype_num[iftype] = 1;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->beacon_interval)
continue;
- iftype_num[wdev->iftype]++;
+ params.iftype_num[wdev->iftype]++;
}
/* GCD(n) = n */
- gcd = beacon_int;
+ params.beacon_gcd = beacon_int;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->beacon_interval)
continue;
if (wdev->beacon_interval != beacon_int) {
- diff_bi = true;
+ params.diff_bi = true;
/* Get the GCD */
bi_prev = wdev->beacon_interval;
while (bi_prev != 0) {
tmp_bi = bi_prev;
- bi_prev = gcd % bi_prev;
- gcd = tmp_bi;
+ bi_prev = params.beacon_gcd % bi_prev;
+ params.beacon_gcd = tmp_bi;
}
break;
}
}
- res = cfg80211_check_combinations(&rdev->wiphy, 0, 0,
- iftype_num, gcd, diff_bi);
+ res = cfg80211_check_combinations(&rdev->wiphy, ¶ms);
return (res < 0) ? res : 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
- const u32 beacon_gcd, bool diff_bi,
+ struct iface_combination_params *params,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data)
@@ -1618,7 +1613,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int num_interfaces = 0;
u32 used_iftypes = 0;
- if (radar_detect) {
+ if (params->radar_detect) {
rcu_read_lock();
regdom = rcu_dereference(cfg80211_regdomain);
if (regdom)
@@ -1627,8 +1622,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
}
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
- num_interfaces += iftype_num[iftype];
- if (iftype_num[iftype] > 0 &&
+ num_interfaces += params->iftype_num[iftype];
+ if (params->iftype_num[iftype] > 0 &&
!(wiphy->software_iftypes & BIT(iftype)))
used_iftypes |= BIT(iftype);
}
@@ -1642,7 +1637,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if (num_interfaces > c->max_interfaces)
continue;
- if (num_different_channels > c->num_different_channels)
+ if (params->num_different_channels > c->num_different_channels)
continue;
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
@@ -1657,16 +1652,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype)))
continue;
- if (limits[j].max < iftype_num[iftype])
+ if (limits[j].max < params->iftype_num[iftype])
goto cont;
- limits[j].max -= iftype_num[iftype];
+ limits[j].max -= params->iftype_num[iftype];
}
}
- if (radar_detect != (c->radar_detect_widths & radar_detect))
+ if (params->radar_detect !=
+ (c->radar_detect_widths & params->radar_detect))
goto cont;
- if (radar_detect && c->radar_detect_regions &&
+ if (params->radar_detect && c->radar_detect_regions &&
!(c->radar_detect_regions & BIT(region)))
goto cont;
@@ -1678,11 +1674,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
- if (beacon_gcd) {
+ if (params->beacon_gcd) {
if (c->beacon_int_min_gcd &&
- beacon_gcd < c->beacon_int_min_gcd)
+ params->beacon_gcd < c->beacon_int_min_gcd)
return -EINVAL;
- if (!c->beacon_int_min_gcd && diff_bi)
+ if (!c->beacon_int_min_gcd && params->diff_bi)
goto cont;
}
@@ -1708,16 +1704,11 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
}
int cfg80211_check_combinations(struct wiphy *wiphy,
- const int num_different_channels,
- const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES],
- const u32 beacon_gcd, bool diff_bi)
+ struct iface_combination_params *params)
{
int err, num = 0;
- err = cfg80211_iter_combinations(wiphy, num_different_channels,
- radar_detect, iftype_num,
- beacon_gcd, diff_bi,
+ err = cfg80211_iter_combinations(wiphy, params,
cfg80211_iter_sum_ifcombs, &num);
if (err)
return err;
--
1.9.1
^ permalink raw reply related
* [PATCH v9] cfg80211: Provision to allow the support for different beacon intervals
From: Purushottam Kushwaha @ 2016-10-10 12:06 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, jouni, usdutt, amarnath, pkushwah
This commit provides a mechanism for the host drivers to advertise the
support for different beacon intervals among the respective interface
combinations in a group, through beacon_int_min_gcd (u32).
This beacon_int_min_gcd will be compared against GCD of all beaconing
interfaces of matching combinations.
Following sets the expectation for beacon_int_min_gcd.
= 0 - all beacon intervals for different interfaces must be same.
> 0 - any beacon interval for the interface part of this combination AND
*GCD* of all beacon intervals from beaconing interfaces of this
combination must be greator or equal to this value.
Signed-off-by: Purushottam Kushwaha <pkushwah@qti.qualcomm.com>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ++-
include/net/cfg80211.h | 18 ++++++++-
include/uapi/linux/nl80211.h | 8 +++-
net/mac80211/util.c | 4 +-
net/wireless/core.h | 2 +-
net/wireless/nl80211.c | 14 +++++--
net/wireless/util.c | 43 ++++++++++++++++++++--
7 files changed, 79 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index b777e1b..1e73c88 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -430,7 +430,8 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
}
if (check_combos)
- ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
+ ret = cfg80211_check_combinations(cfg->wiphy, 1, 0,
+ iftype_num, 0, false);
return ret;
}
@@ -446,7 +447,8 @@ static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
iftype_num[pos->wdev.iftype]++;
iftype_num[new_type]++;
- return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
+ return cfg80211_check_combinations(cfg->wiphy, 1, 0,
+ iftype_num, 0, false);
}
static void convert_key_from_CPU(struct brcmf_wsec_key *key,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fe78f02..49aa6a0 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3080,6 +3080,12 @@ struct ieee80211_iface_limit {
* only in special cases.
* @radar_detect_widths: bitmap of channel widths supported for radar detection
* @radar_detect_regions: bitmap of regions supported for radar detection
+ * @beacon_int_min_gcd: This interface combination supports different
+ * beacon intervals.
+ * = 0 - all beacon intervals for different interface must be same.
+ * > 0 - any beacon interval for the interface part of this combination AND
+ * *GCD* of all beacon intervals from beaconing interfaces of this
+ * combination must be greator or equal to this value.
*
* With this structure the driver can describe which interface
* combinations it supports concurrently.
@@ -3100,7 +3106,7 @@ struct ieee80211_iface_limit {
* };
*
*
- * 2. Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total:
+ * 2. Allow #{AP, P2P-GO} <= 8, BI min gcd = 10, channels = 1, 8 total:
*
* struct ieee80211_iface_limit limits2[] = {
* { .max = 8, .types = BIT(NL80211_IFTYPE_AP) |
@@ -3111,6 +3117,7 @@ struct ieee80211_iface_limit {
* .n_limits = ARRAY_SIZE(limits2),
* .max_interfaces = 8,
* .num_different_channels = 1,
+ * .beacon_int_min_gcd = 10,
* };
*
*
@@ -3138,6 +3145,7 @@ struct ieee80211_iface_combination {
bool beacon_int_infra_match;
u8 radar_detect_widths;
u8 radar_detect_regions;
+ u32 beacon_int_min_gcd;
};
struct ieee80211_txrx_stypes {
@@ -5583,6 +5591,8 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
+ * @beacon_gcd: a value specifying GCD of all beaconing interfaces.
+ * @diff_bi: a flag which denotes beacon intervals are different or same.
*
* This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to
@@ -5591,7 +5601,8 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES]);
+ const int iftype_num[NUM_NL80211_IFTYPES],
+ const u32 beacon_gcd, bool diff_bi);
/**
* cfg80211_iter_combinations - iterate over matching combinations
@@ -5605,6 +5616,8 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
+ * @beacon_gcd: a value specifying GCD of all beaconing interfaces.
+ * @diff_bi: a flag which denotes beacon intervals are different or same.
* @iter: function to call for each matching combination
* @data: pointer to pass to iter function
*
@@ -5616,6 +5629,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES],
+ const u32 beacon_gcd, bool diff_bi,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data);
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 56368e9..3c19cca 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4280,6 +4280,9 @@ enum nl80211_iface_limit_attrs {
* of supported channel widths for radar detection.
* @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
* of supported regulatory regions for radar detection.
+ * @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of
+ * different beacon intervals supported by all the interface combinations
+ * in this group (if not present, all beacon interval must match).
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -4287,8 +4290,8 @@ enum nl80211_iface_limit_attrs {
* limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
* => allows an AP and a STA that must match BIs
*
- * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
- * => allows 8 of AP/GO
+ * numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8,
+ * => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels
@@ -4314,6 +4317,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
+ NL80211_IFACE_COMB_BI_MIN_GCD,
/* keep last */
NUM_NL80211_IFACE_COMB,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 545c79a..cfef5ce 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3374,7 +3374,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
return cfg80211_check_combinations(local->hw.wiphy,
num_different_channels,
- radar_detect, num);
+ radar_detect, num, 0, false);
}
static void
@@ -3413,7 +3413,7 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
err = cfg80211_iter_combinations(local->hw.wiphy,
num_different_channels, radar_detect,
- num, ieee80211_iter_max_chans,
+ num, 0, false, ieee80211_iter_max_chans,
&max_num_different_channels);
if (err < 0)
return err;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 08d2e94..21e3188 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -475,7 +475,7 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
u32 *mask);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- u32 beacon_int);
+ enum nl80211_iftype iftype, u32 beacon_int);
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c510810..903cd5a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1075,6 +1075,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
c->radar_detect_regions)))
goto nla_put_failure;
+ if (c->beacon_int_min_gcd &&
+ nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
+ c->beacon_int_min_gcd))
+ goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
@@ -3803,7 +3807,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
- err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
+ params.beacon_interval);
if (err)
return err;
@@ -8152,7 +8157,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- err = cfg80211_validate_beacon_int(rdev, ibss.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
+ ibss.beacon_interval);
if (err)
return err;
@@ -9417,7 +9423,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- err = cfg80211_validate_beacon_int(rdev, setup.beacon_interval);
+ err = cfg80211_validate_beacon_int(rdev,
+ NL80211_IFTYPE_MESH_POINT,
+ setup.beacon_interval);
if (err)
return err;
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 8edce22..0d3bda4 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1559,30 +1559,55 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- u32 beacon_int)
+ enum nl80211_iftype iftype, u32 beacon_int)
{
struct wireless_dev *wdev;
+ bool diff_bi = false;
int res = 0;
+ u32 bi_prev, tmp_bi, gcd;
+ int iftype_num[NUM_NL80211_IFTYPES];
if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL;
+ memset(iftype_num, 0, sizeof(iftype_num));
+ iftype_num[iftype] = 1;
+
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+ if (!wdev->beacon_interval)
+ continue;
+
+ iftype_num[wdev->iftype]++;
+ }
+
+ /* GCD(n) = n */
+ gcd = beacon_int;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->beacon_interval)
continue;
if (wdev->beacon_interval != beacon_int) {
- res = -EINVAL;
+ diff_bi = true;
+ /* Get the GCD */
+ bi_prev = wdev->beacon_interval;
+ while (bi_prev != 0) {
+ tmp_bi = bi_prev;
+ bi_prev = gcd % bi_prev;
+ gcd = tmp_bi;
+ }
break;
}
}
- return res;
+ res = cfg80211_check_combinations(&rdev->wiphy, 0, 0,
+ iftype_num, gcd, diff_bi);
+ return (res < 0) ? res : 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES],
+ const u32 beacon_gcd, bool diff_bi,
void (*iter)(const struct ieee80211_iface_combination *c,
void *data),
void *data)
@@ -1653,6 +1678,14 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
+ if (beacon_gcd) {
+ if (c->beacon_int_min_gcd &&
+ beacon_gcd < c->beacon_int_min_gcd)
+ return -EINVAL;
+ if (!c->beacon_int_min_gcd && diff_bi)
+ goto cont;
+ }
+
/* This combination covered all interface types and
* supported the requested numbers, so we're good.
*/
@@ -1677,12 +1710,14 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels,
const u8 radar_detect,
- const int iftype_num[NUM_NL80211_IFTYPES])
+ const int iftype_num[NUM_NL80211_IFTYPES],
+ const u32 beacon_gcd, bool diff_bi)
{
int err, num = 0;
err = cfg80211_iter_combinations(wiphy, num_different_channels,
radar_detect, iftype_num,
+ beacon_gcd, diff_bi,
cfg80211_iter_sum_ifcombs, &num);
if (err)
return err;
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v5 3/4] cfg80211: configure multicast to unicast for AP interfaces
From: Johannes Berg @ 2016-10-10 10:28 UTC (permalink / raw)
To: Michael Braun; +Cc: linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475865574-5384-3-git-send-email-michael-dev@fami-braun.de>
> *
> + * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Multicast packets
> should be
> + * send out as unicast to all stations.
You should document what type of attribute is expected. You probably
wanted a flag attribute, but ...
> + [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type =
> NLA_U8, },
have u8 in the policy, yet
> + enabled = nla_get_flag(nla);
actually use as a flag :)
In addition to that, I think you should clarify the "per-BSS" comment
in nl80211, and also clarify (at the same place) what kind of
functionality is expected from this.
johannes
^ permalink raw reply
* Re: [PATCH] mac80211: enable to inject a-msdu frames using monitor interface
From: Johannes Berg @ 2016-10-10 10:16 UTC (permalink / raw)
To: Michael Braun; +Cc: linux-wireless, projekt-wlan
In-Reply-To: <1475872162-2835-1-git-send-email-michael-dev@fami-braun.de>
On Fri, 2016-10-07 at 22:29 +0200, Michael Braun wrote:
>
> I guess the same is needed for packets with IEEE80211_TX_CTRL_AMSDU
> set.
I don't think that's true, since we don't get here after A-MSDU
building in mac80211.
> /* preserve EOSP bit */
> ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
>
> + /* preserve A-MSDU bit for MONITOR interfaces to allow
> injecting
> + * A-MSDU frames
> + */
> + if (info->flags & IEEE80211_TX_CTL_INJECTED ||
> + info->control.flags & IEEE80211_TX_CTRL_AMSDU)
> + ack_policy |= *p & IEEE80211_QOS_CTL_A_MSDU_PRESENT;
However, why not just unconditionally preserve it?
johannes
^ permalink raw reply
* Re: [RFC] mac80211: fix A-MSDU outer SA/DA
From: Johannes Berg @ 2016-10-10 10:13 UTC (permalink / raw)
To: Michael Braun; +Cc: linux-wireless, projekt-wlan
In-Reply-To: <1475874542-9014-1-git-send-email-michael-dev@fami-braun.de>
>
> + /* according to IEEE 802.11-2012 8.3.2 table 8-19, the outer
> SA/DA
> + * fields needs to be changed to BSSID for A-MSDU frames
> depending
> + * on FromDS/ToDS values.
> + */
> + hdr = data;
> + if (bssid && (hdr->frame_control &
> cpu_to_le16(IEEE80211_FCTL_FROMDS)))
> + memcpy(amsdu_hdr.h_source, bssid, ETH_ALEN);
> + if (bssid && (hdr->frame_control &
> cpu_to_le16(IEEE80211_FCTL_TODS)))
> + memcpy(amsdu_hdr.h_dest, bssid, ETH_ALEN);
>
You should probably use ieee80211_has_tods() and ieee80211_has_fromds()
johannes
^ permalink raw reply
* [PATCH] mac80211_hwsim: make multi-channel ops const
From: Johannes Berg @ 2016-10-10 10:09 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Instead of building the multi-channel ops at runtime, declare
the common ops with a macro and build both that way, so that
the multi-channel ops can also be const.
As a side effect, due to the removed code, this decreases the
size of the module (while shifting data from .bss to .text
due to the newly added const).
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/mac80211_hwsim.c | 79 ++++++++++++++++++-----------------
1 file changed, 40 insertions(+), 39 deletions(-)
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 431f13b4faf6..f9ba0772e471 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2256,35 +2256,51 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
}
+#define HWSIM_COMMON_OPS \
+ .tx = mac80211_hwsim_tx, \
+ .start = mac80211_hwsim_start, \
+ .stop = mac80211_hwsim_stop, \
+ .add_interface = mac80211_hwsim_add_interface, \
+ .change_interface = mac80211_hwsim_change_interface, \
+ .remove_interface = mac80211_hwsim_remove_interface, \
+ .config = mac80211_hwsim_config, \
+ .configure_filter = mac80211_hwsim_configure_filter, \
+ .bss_info_changed = mac80211_hwsim_bss_info_changed, \
+ .sta_add = mac80211_hwsim_sta_add, \
+ .sta_remove = mac80211_hwsim_sta_remove, \
+ .sta_notify = mac80211_hwsim_sta_notify, \
+ .set_tim = mac80211_hwsim_set_tim, \
+ .conf_tx = mac80211_hwsim_conf_tx, \
+ .get_survey = mac80211_hwsim_get_survey, \
+ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \
+ .ampdu_action = mac80211_hwsim_ampdu_action, \
+ .flush = mac80211_hwsim_flush, \
+ .get_tsf = mac80211_hwsim_get_tsf, \
+ .set_tsf = mac80211_hwsim_set_tsf, \
+ .get_et_sset_count = mac80211_hwsim_get_et_sset_count, \
+ .get_et_stats = mac80211_hwsim_get_et_stats, \
+ .get_et_strings = mac80211_hwsim_get_et_strings,
+
static const struct ieee80211_ops mac80211_hwsim_ops = {
- .tx = mac80211_hwsim_tx,
- .start = mac80211_hwsim_start,
- .stop = mac80211_hwsim_stop,
- .add_interface = mac80211_hwsim_add_interface,
- .change_interface = mac80211_hwsim_change_interface,
- .remove_interface = mac80211_hwsim_remove_interface,
- .config = mac80211_hwsim_config,
- .configure_filter = mac80211_hwsim_configure_filter,
- .bss_info_changed = mac80211_hwsim_bss_info_changed,
- .sta_add = mac80211_hwsim_sta_add,
- .sta_remove = mac80211_hwsim_sta_remove,
- .sta_notify = mac80211_hwsim_sta_notify,
- .set_tim = mac80211_hwsim_set_tim,
- .conf_tx = mac80211_hwsim_conf_tx,
- .get_survey = mac80211_hwsim_get_survey,
- CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
- .ampdu_action = mac80211_hwsim_ampdu_action,
+ HWSIM_COMMON_OPS
.sw_scan_start = mac80211_hwsim_sw_scan,
.sw_scan_complete = mac80211_hwsim_sw_scan_complete,
- .flush = mac80211_hwsim_flush,
- .get_tsf = mac80211_hwsim_get_tsf,
- .set_tsf = mac80211_hwsim_set_tsf,
- .get_et_sset_count = mac80211_hwsim_get_et_sset_count,
- .get_et_stats = mac80211_hwsim_get_et_stats,
- .get_et_strings = mac80211_hwsim_get_et_strings,
};
-static struct ieee80211_ops mac80211_hwsim_mchan_ops;
+static const struct ieee80211_ops mac80211_hwsim_mchan_ops = {
+ HWSIM_COMMON_OPS
+ .hw_scan = mac80211_hwsim_hw_scan,
+ .cancel_hw_scan = mac80211_hwsim_cancel_hw_scan,
+ .sw_scan_start = NULL,
+ .sw_scan_complete = NULL,
+ .remain_on_channel = mac80211_hwsim_roc,
+ .cancel_remain_on_channel = mac80211_hwsim_croc,
+ .add_chanctx = mac80211_hwsim_add_chanctx,
+ .remove_chanctx = mac80211_hwsim_remove_chanctx,
+ .change_chanctx = mac80211_hwsim_change_chanctx,
+ .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,
+ .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx,
+};
struct hwsim_new_radio_params {
unsigned int channels;
@@ -3360,21 +3376,6 @@ static int __init init_mac80211_hwsim(void)
if (channels < 1)
return -EINVAL;
- mac80211_hwsim_mchan_ops = mac80211_hwsim_ops;
- mac80211_hwsim_mchan_ops.hw_scan = mac80211_hwsim_hw_scan;
- mac80211_hwsim_mchan_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan;
- mac80211_hwsim_mchan_ops.sw_scan_start = NULL;
- mac80211_hwsim_mchan_ops.sw_scan_complete = NULL;
- mac80211_hwsim_mchan_ops.remain_on_channel = mac80211_hwsim_roc;
- mac80211_hwsim_mchan_ops.cancel_remain_on_channel = mac80211_hwsim_croc;
- mac80211_hwsim_mchan_ops.add_chanctx = mac80211_hwsim_add_chanctx;
- mac80211_hwsim_mchan_ops.remove_chanctx = mac80211_hwsim_remove_chanctx;
- mac80211_hwsim_mchan_ops.change_chanctx = mac80211_hwsim_change_chanctx;
- mac80211_hwsim_mchan_ops.assign_vif_chanctx =
- mac80211_hwsim_assign_vif_chanctx;
- mac80211_hwsim_mchan_ops.unassign_vif_chanctx =
- mac80211_hwsim_unassign_vif_chanctx;
-
spin_lock_init(&hwsim_radio_lock);
err = register_pernet_device(&hwsim_net_ops);
--
2.8.1
^ permalink raw reply related
* Re: [PATCH] Report scan_abort as part of iw phy
From: Johannes Berg @ 2016-10-10 9:21 UTC (permalink / raw)
To: Ola Olsson; +Cc: linux-wireless, Ola Olsson
In-Reply-To: <1475934036-5981-1-git-send-email-ola1olsson@gmail.com>
On Sat, 2016-10-08 at 15:40 +0200, Ola Olsson wrote:
> nl80211: abort_scan has not been reported under the 'Supported
> commands'
> category when calling iw phy. Add that.
>
> Signed-off-by: Ola Olsson <ola.olsson@sonymobile.com>
> ---
> net/wireless/nl80211.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index 95d55d2..0bbce4f 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -1526,6 +1526,7 @@ static int nl80211_send_wiphy(struct
> cfg80211_registered_device *rdev,
> CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
> CMD(mgmt_tx, FRAME);
> CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
> + CMD(abort_scan, ABORT_SCAN);
>
You can't add this here, it has to be inside the "state->split" if.
johannes
^ permalink raw reply
* Re: [PATCH] Report scan_abort as part of iw phy
From: Kalle Valo @ 2016-10-10 9:13 UTC (permalink / raw)
To: Ola Olsson; +Cc: johannes, linux-wireless, Ola Olsson
In-Reply-To: <1475934036-5981-1-git-send-email-ola1olsson@gmail.com>
Ola Olsson <ola1olsson@gmail.com> writes:
> nl80211: abort_scan has not been reported under the 'Supported commands'
> category when calling iw phy. Add that.
>
> Signed-off-by: Ola Olsson <ola.olsson@sonymobile.com>
> ---
> net/wireless/nl80211.c | 1 +
> 1 file changed, 1 insertion(+)
You should prefix the title with "cfg80211: " (or "nl80211: ", not
really sure which one is more suitable).
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches#subject_name
--
Kalle Valo
^ permalink raw reply
* [PATCH] iwlwifi: pcie: reduce "unsupported splx" to a warning
From: Chris Rorvick @ 2016-10-10 7:19 UTC (permalink / raw)
To: Intel Linux Wireless, Luca Coelho, Emmanuel Grumbach,
Johannes Berg, Kalle Valo, Oren Givon
Cc: linux-wireless, netdev, linux-kernel, Chris Rorvick
Commit bcb079a14d75 ("iwlwifi: pcie: retrieve and parse ACPI power
limitations") looks for a specific structure in the ACPI tables for
setting the default power limit. The data returned for at least some
dual band chipsets is not recognized, though. For example, the AC 8260
reports the following:
Name (SPLX, Package (0x04)
{
Zero,
Package (0x03)
{
0,
1200,
1000
},
Package (0x03)
{
0,
1200,
1000
},
Package (0x03)
{
0,
1200,
1000
}
})
The current logic expects exactly two elements in the outer package,
causing the above to be ignored and the power limit unset.
Despite the interface being fully functional after initialization, the
above condition is reported as an error. Knock the message down to a
warning and provide better context for understanding its consequence.
Signed-off-by: Chris Rorvick <chris@rorvick.com>
---
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 78cf9a7..19b531f 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -540,7 +540,7 @@ static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx)
splx->package.count != 2 ||
splx->package.elements[0].type != ACPI_TYPE_INTEGER ||
splx->package.elements[0].integer.value != 0) {
- IWL_ERR(trans, "Unsupported splx structure\n");
+ IWL_WARN(trans, "Unsupported splx structure, not limiting WiFi power\n");
return 0;
}
--
2.10.1
^ permalink raw reply related
* Re: [PATCH v7 1/3] Documentation: dt: net: add ath9k wireless device binding
From: Martin Blumenstingl @ 2016-10-09 9:54 UTC (permalink / raw)
To: Rob Herring
Cc: ath9k-devel, devicetree, linux-wireless, ath9k-devel, mcgrof,
mark.rutland, kvalo, chunkeey, arend.vanspriel, julian.calaby,
bjorn, linux, nbd
In-Reply-To: <20161009012856.GK18158@rob-hp-laptop>
On Sun, Oct 9, 2016 at 3:28 AM, Rob Herring <robh@kernel.org> wrote:
> On Sun, Oct 02, 2016 at 11:47:41PM +0200, Martin Blumenstingl wrote:
>> Add documentation how devicetree can be used to configure ath9k based
>> devices.
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> ---
>> .../devicetree/bindings/net/wireless/qca,ath9k.txt | 30 ++++++++++++++++++++++
>> 1 file changed, 30 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
>>
>> diff --git a/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
>> new file mode 100644
>> index 0000000..9b58ede
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
>> @@ -0,0 +1,30 @@
>> +* Qualcomm Atheros ath9k wireless devices
>> +
>> +This node provides properties for configuring the ath9k wireless device. The
>> +node is expected to be specified as a child node of the PCI controller to
>> +which the wireless chip is connected.
>> +
>> +Required properties:
>> +- compatible: For PCI and PCIe devices this should be an identifier following
>> + the format as defined in "PCI Bus Binding to Open Firmware"
>> + Revision 2.1. One of the possible formats is "pciVVVV,DDDD"
>> + where VVVV is the PCI vendor ID and DDDD is PCI device ID.
>
> Are there some known values you can document here? Like the one in the
> example.
what do you have in mind there?
there are lots of supported device IDs just with vendor 0x168c (Atheros):
echo $(grep 'PCI_VDEVICE(ATHEROS'
drivers/net/wireless/ath/ath9k/pci.c; grep '{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS'
drivers/net/wireless/ath/ath9k/pci.c -A1) | grep -Eo "0x[
0-9A-Z]{4}" | sort -u
Also some device IDs seem to be used by different chips, for example
0x0029 is used for both, AR9220 and AR9223 - see [0]
I could extend the documentation with something like:
vendor ID is usually 168c (Atheros) and device ID is one of the
following, depending on the actual chipset:
- 002d: AR9227 (PCI variant of AR9287)
- 002e: AR9287 (PCI-e)
- ...
>> +- reg: Address and length of the register set for the device.
>> +
>> +Optional properties:
>> +- qca,no-eeprom: Indicates that there is no physical EEPROM connected to the
>> + ath9k wireless chip (in this case the calibration /
>> + EEPROM data will be loaded from userspace using the
>> + kernel firmware loader).
>> +- mac-address: See ethernet.txt in the parent directory
>> +- local-mac-address: See ethernet.txt in the parent directory
>> +
>> +
>> +In this example, the node is defined as child node of the PCI controller:
>> +&pci0 {
>> + ath9k@168c,002d {
>
> wifi@...
will fix that, thanks for the hint
[0] https://wireless.wiki.kernel.org/en/users/drivers/ath9k/devices
^ permalink raw reply
* Re: [PATCH v7 1/3] Documentation: dt: net: add ath9k wireless device binding
From: Rob Herring @ 2016-10-09 1:28 UTC (permalink / raw)
To: Martin Blumenstingl
Cc: ath9k-devel, devicetree, linux-wireless, ath9k-devel, mcgrof,
mark.rutland, kvalo, chunkeey, arend.vanspriel, julian.calaby,
bjorn, linux, nbd
In-Reply-To: <20161002214743.2263-2-martin.blumenstingl@googlemail.com>
On Sun, Oct 02, 2016 at 11:47:41PM +0200, Martin Blumenstingl wrote:
> Add documentation how devicetree can be used to configure ath9k based
> devices.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
> .../devicetree/bindings/net/wireless/qca,ath9k.txt | 30 ++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
>
> diff --git a/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
> new file mode 100644
> index 0000000..9b58ede
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/wireless/qca,ath9k.txt
> @@ -0,0 +1,30 @@
> +* Qualcomm Atheros ath9k wireless devices
> +
> +This node provides properties for configuring the ath9k wireless device. The
> +node is expected to be specified as a child node of the PCI controller to
> +which the wireless chip is connected.
> +
> +Required properties:
> +- compatible: For PCI and PCIe devices this should be an identifier following
> + the format as defined in "PCI Bus Binding to Open Firmware"
> + Revision 2.1. One of the possible formats is "pciVVVV,DDDD"
> + where VVVV is the PCI vendor ID and DDDD is PCI device ID.
Are there some known values you can document here? Like the one in the
example.
> +- reg: Address and length of the register set for the device.
> +
> +Optional properties:
> +- qca,no-eeprom: Indicates that there is no physical EEPROM connected to the
> + ath9k wireless chip (in this case the calibration /
> + EEPROM data will be loaded from userspace using the
> + kernel firmware loader).
> +- mac-address: See ethernet.txt in the parent directory
> +- local-mac-address: See ethernet.txt in the parent directory
> +
> +
> +In this example, the node is defined as child node of the PCI controller:
> +&pci0 {
> + ath9k@168c,002d {
wifi@...
> + compatible = "pci168c,002d";
> + reg = <0x7000 0 0 0 0x1000>;
> + qca,no-eeprom;
> + };
> +};
> --
> 2.10.0
>
^ permalink raw reply
* Re: [PATCH 1/2] ath10k: add per peer htt tx stats support for 10.4
From: Yeoh Chun-Yeow @ 2016-10-08 14:16 UTC (permalink / raw)
To: akolli; +Cc: ath10k@lists.infradead.org, akolli,
linux-wireless@vger.kernel.org
In-Reply-To: <1475852332-18217-2-git-send-email-akolli@qti.qualcomm.com>
On Fri, Oct 7, 2016 at 10:58 PM, <akolli@qti.qualcomm.com> wrote:
> From: Anilkumar Kolli <akolli@qti.qualcomm.com>
>
> Per peer tx stats are part of 'HTT_10_4_T2H_MSG_TYPE_PEER_STATS'
> event, Firmware sends one HTT event for every four PPDUs.
> HTT payload has success pkts/bytes, failed pkts/bytes, retry
> pkts/bytes and rate info per ppdu.
> Peer stats are enabled through 'WMI_SERVICE_PEER_STATS',
> which are nowadays enabled by default.
>
> Parse peer stats and update the tx rate information per STA.
>
> tx rate, Peer stats are tested on QCA4019 with Firmware version
> 10.4-3.2.1-00028.
>
Is QCA988X supported? I have tried to test with
firmware-5.bin_10.2.4.70.56 but not working.
---
Chun-Yeow
^ permalink raw reply
* [PATCH] Report scan_abort as part of iw phy
From: Ola Olsson @ 2016-10-08 13:40 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Ola Olsson, Ola Olsson
nl80211: abort_scan has not been reported under the 'Supported commands'
category when calling iw phy. Add that.
Signed-off-by: Ola Olsson <ola.olsson@sonymobile.com>
---
net/wireless/nl80211.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 95d55d2..0bbce4f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1526,6 +1526,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
CMD(mgmt_tx, FRAME);
CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
+ CMD(abort_scan, ABORT_SCAN);
if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
--
2.7.4
^ permalink raw reply related
* Re: [PATCHv4] mac80211: check A-MSDU inner frame source address on AP interfaces
From: michael-dev @ 2016-10-08 10:13 UTC (permalink / raw)
To: Johannes Berg
Cc: linux-wireless, projekt-wlan, kvalo, akarwar, nishants,
Larry.Finger, Jes.Sorensen
In-Reply-To: <1475753787.2015.13.camel@sipsolutions.net>
Am 06.10.2016 13:36, schrieb Johannes Berg:
> Could you test my patches in your scenario to see they do what we want?
> I'll resend as [PATCH] then, and think about applying them and perhaps
> backporting also.
I've tested them by running a new hostapd hwsim test [1] and after
applying [2].
I can confirm that this tests fails without your RFC series applied and
passes when your RFC series is applied.
So your RFC is fine.
Tested-by: Michael Braun <michael-dev@fami-braun.de>
Regards,
M. Braun
[1]
https://github.com/michael-dev/hostapd/commit/2caecdd9911529e39c6b8a83aac0cbe737dc8f65
[2] https://patchwork.kernel.org/patch/9367469/
^ permalink raw reply
* [RFC] mac80211: fix A-MSDU outer SA/DA
From: Michael Braun @ 2016-10-07 21:09 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan
According to IEEE 802.11-2012 section 8.3.2 table 8-19, the outer SA/DA
of A-MSDU frames need to be changed depending on FromDS/ToDS values.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
net/mac80211/tx.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 5023966..87670b7 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3050,7 +3050,7 @@ static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
int subframe_len = skb->len - hdr_len;
void *data;
- u8 *qc;
+ u8 *qc, *bssid;
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
return false;
@@ -3062,10 +3062,32 @@ static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
&subframe_len))
return false;
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ bssid = sdata->u.mgd.bssid;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ bssid = sdata->vif.addr;
+ break;
+ default:
+ bssid = NULL;
+ }
+
amsdu_hdr.h_proto = cpu_to_be16(subframe_len);
memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN);
memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN);
+ /* according to IEEE 802.11-2012 8.3.2 table 8-19, the outer SA/DA
+ * fields needs to be changed to BSSID for A-MSDU frames depending
+ * on FromDS/ToDS values.
+ */
+ hdr = data;
+ if (bssid && (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS)))
+ memcpy(amsdu_hdr.h_source, bssid, ETH_ALEN);
+ if (bssid && (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_TODS)))
+ memcpy(amsdu_hdr.h_dest, bssid, ETH_ALEN);
+
data = skb_push(skb, sizeof(amsdu_hdr));
memmove(data, data + sizeof(amsdu_hdr), hdr_len);
memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr));
--
2.1.4
^ permalink raw reply related
* [PATCH] mac80211: enable to inject a-msdu frames using monitor interface
From: Michael Braun @ 2016-10-07 20:29 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan
Problem: When injecting an A-MSDU using a PF_PACKET socket, the qos flag
IEEE80211_QOS_CTL_A_MSDU_PRESENT is cleared.
How to reproduce: Inject a frame on a mac80211 hwsim monitor interface and
have tshark sniffing on this monitor interface.
You'll see the packet twice: Once with correct flag and once with flag
cleared. On hwsim0, you'll only see the packet with a cleared flag.
I guess the same is needed for packets with IEEE80211_TX_CTRL_AMSDU set.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
net/mac80211/wme.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 9eb0aee..3faa972 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -248,6 +248,13 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
/* preserve EOSP bit */
ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
+ /* preserve A-MSDU bit for MONITOR interfaces to allow injecting
+ * A-MSDU frames
+ */
+ if (info->flags & IEEE80211_TX_CTL_INJECTED ||
+ info->control.flags & IEEE80211_TX_CTRL_AMSDU)
+ ack_policy |= *p & IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
if (is_multicast_ether_addr(hdr->addr1) ||
sdata->noack_map & BIT(tid)) {
ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
--
2.1.4
^ permalink raw reply related
* [PATCH v5 3/4] cfg80211: configure multicast to unicast for AP interfaces
From: Michael Braun @ 2016-10-07 18:39 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475865574-5384-1-git-send-email-michael-dev@fami-braun.de>
This add a userspace toggle to configure multicast to unicast.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
include/net/cfg80211.h | 6 ++++++
include/uapi/linux/nl80211.h | 10 ++++++++++
net/wireless/nl80211.c | 36 ++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 12 ++++++++++++
net/wireless/trace.h | 19 +++++++++++++++++++
5 files changed, 83 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7ce6223..7b0941d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2460,6 +2460,8 @@ struct cfg80211_qos_map {
*
* @set_wds_peer: set the WDS peer for a WDS interface
*
+ * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ *
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
* functions to adjust rfkill hw state
*
@@ -2722,6 +2724,10 @@ struct cfg80211_ops {
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr);
+ int (*set_multicast_to_unicast)(struct wiphy *wiphy,
+ struct net_device *dev,
+ const bool enabled);
+
void (*rfkill_poll)(struct wiphy *wiphy);
#ifdef CONFIG_NL80211_TESTMODE
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 2206941..1b9e87b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -599,6 +599,9 @@
*
* @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
*
+ * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if AP interface should
+ * perform multicast to unicast conversion (per-BSS).
+ *
* @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
* mesh config parameters may be given.
* @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
@@ -1026,6 +1029,8 @@ enum nl80211_commands {
NL80211_CMD_ABORT_SCAN,
+ NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1867,6 +1872,9 @@ enum nl80211_commands {
* @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
* used to pull the stored data for mesh peer in power save state.
*
+ * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Multicast packets should be
+ * send out as unicast to all stations.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2261,6 +2269,8 @@ enum nl80211_attrs {
NL80211_ATTR_MESH_PEER_AID,
+ NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f02653a..57b5d70 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -409,6 +409,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
.len = VHT_MUMIMO_GROUPS_DATA_LEN
},
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
+ [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_U8, },
};
/* policy for the key attributes */
@@ -1538,6 +1539,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
goto nla_put_failure;
}
CMD(set_wds_peer, SET_WDS_PEER);
+ CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
CMD(tdls_oper, TDLS_OPER);
@@ -2164,6 +2166,32 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
return rdev_set_wds_peer(rdev, dev, bssid);
}
+static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ const struct nlattr *nla;
+ bool enabled;
+
+ if (!info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED])
+ return -EINVAL;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ if (!rdev->ops->set_multicast_to_unicast)
+ return -EOPNOTSUPP;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
+ nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
+ enabled = nla_get_flag(nla);
+ return rdev_set_multicast_to_unicast(rdev, dev, enabled);
+}
+
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
@@ -11574,6 +11602,14 @@ static const struct genl_ops nl80211_ops[] = {
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+ .doit = nl80211_set_multicast_to_unicast,
+ .policy = nl80211_policy,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_JOIN_MESH,
.doit = nl80211_join_mesh,
.policy = nl80211_policy,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 85ff30b..7d93c3d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -562,6 +562,18 @@ static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_set_multicast_to_unicast(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ const bool enabled)
+{
+ int ret;
+ trace_rdev_set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
+ ret = rdev->ops->set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
{
trace_rdev_rfkill_poll(&rdev->wiphy);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 72b5255..8c9aa57 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2940,6 +2940,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_abort_scan,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev)
);
+
+TRACE_EVENT(rdev_set_multicast_to_unicast,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ const bool enabled),
+ TP_ARGS(wiphy, netdev, enabled),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(bool, enabled)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->enabled = enabled;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", unicast: %s",
+ WIPHY_PR_ARG, NETDEV_PR_ARG,
+ BOOL_TO_STR(__entry->enabled))
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
2.1.4
^ permalink raw reply related
* [PATCH v5 2/4] mac80211: filter multicast data packets on AP / AP_VLAN
From: Michael Braun @ 2016-10-07 18:39 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475865574-5384-1-git-send-email-michael-dev@fami-braun.de>
This patch adds filtering for multicast data packets on AP_VLAN interfaces
that have no authorized station connected and changes filtering on AP
interfaces to not count stations assigned to AP_VLAN interfaces.
This saves airtime and avoids waking up other stations currently authorized
in this BSS. When using WPA, the packets dropped could not be decrypted by
any station.
The behaviour when there are no AP_VLAN interfaces is left unchanged.
When there are AP_VLAN interfaces, this patch
1. adds filtering multicast data packets sent on AP_VLAN interfaces that
have no authorized station connected.
No filtering happens on 4addr AP_VLAN interfaces.
2. makes filtering of multicast data packets sent on AP interfaces depend
on the number of authorized stations in this bss not assigned to an
AP_VLAN interface.
Therefore, a new num_mcast_sta counter is added for AP_VLAN interfaces.
The existing one for AP interfaces is altered to not track stations
assigned to an AP_VLAN interface.
The new counter is exposed in debugfs.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
--
v4:
- update description
v3:
- reuse existing num_mcast_sta
v2:
- use separate function to inc/dec mcast_sta counters
- do not filter in 4addr mode
- change description
- change filtering on AP interface (do not count AP_VLAN sta)
- use new counters regardless of 4addr or not
- simplify cfg.c:change_station
- remove no-op change in __cleanup_single_sta
---
net/mac80211/cfg.c | 20 ++++++--------------
net/mac80211/debugfs_netdev.c | 11 +++++++++++
net/mac80211/ieee80211_i.h | 33 +++++++++++++++++++++++++++++++++
net/mac80211/rx.c | 5 +++--
net/mac80211/sta_info.c | 10 ++--------
net/mac80211/tx.c | 5 ++---
6 files changed, 57 insertions(+), 27 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 24133f5..1edb017 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1357,9 +1357,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
goto out_err;
if (params->vlan && params->vlan != sta->sdata->dev) {
- bool prev_4addr = false;
- bool new_4addr = false;
-
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (params->vlan->ieee80211_ptr->use_4addr) {
@@ -1369,26 +1366,21 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
- new_4addr = true;
__ieee80211_check_fast_rx_iface(vlansdata);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- sta->sdata->u.vlan.sta) {
+ sta->sdata->u.vlan.sta)
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
- prev_4addr = true;
- }
+
+ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ ieee80211_vif_dec_num_mcast(sta->sdata);
sta->sdata = vlansdata;
ieee80211_check_fast_xmit(sta);
- if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
- prev_4addr != new_4addr) {
- if (new_4addr)
- atomic_dec(&sta->sdata->bss->num_mcast_sta);
- else
- atomic_inc(&sta->sdata->bss->num_mcast_sta);
- }
+ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ ieee80211_vif_inc_num_mcast(sta->sdata);
ieee80211_send_layer2_update(sta);
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index a5ba739..ed7bff4 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -477,6 +477,7 @@ IEEE80211_IF_FILE_RW(tdls_wider_bw);
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
+IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -643,6 +644,13 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
}
+static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+ /* add num_mcast_sta_vlan using name num_mcast_sta */
+ debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
+ sdata, &num_mcast_sta_vlan_ops);
+}
+
static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD_MODE(tsf, 0600);
@@ -746,6 +754,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
case NL80211_IFTYPE_AP:
add_ap_files(sdata);
break;
+ case NL80211_IFTYPE_AP_VLAN:
+ add_vlan_files(sdata);
+ break;
case NL80211_IFTYPE_WDS:
add_wds_files(sdata);
break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f56d342..70c0963 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -305,6 +305,7 @@ struct ieee80211_if_vlan {
/* used for all tx if the VLAN is configured to 4-addr mode */
struct sta_info __rcu *sta;
+ atomic_t num_mcast_sta; /* number of stations receiving multicast */
};
struct mesh_stats {
@@ -1496,6 +1497,38 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
return false;
}
+static inline void
+ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ atomic_inc(&sdata->u.ap.num_mcast_sta);
+ else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ atomic_inc(&sdata->u.vlan.num_mcast_sta);
+}
+
+static inline void
+ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ atomic_dec(&sdata->u.ap.num_mcast_sta);
+ else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ atomic_dec(&sdata->u.vlan.num_mcast_sta);
+}
+
+/* This function returns the number of multicast stations connected to this
+ * interface. It returns -1 if that number is not tracked, that is for netdevs
+ * not in AP or AP_VLAN mode or when using 4addr.
+ */
+static inline int
+ieee80211_vif_get_num_mcast_if(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ return atomic_read(&sdata->u.ap.num_mcast_sta);
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
+ return atomic_read(&sdata->u.vlan.num_mcast_sta);
+ return -1;
+}
+
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
struct ieee80211_rx_status *status,
unsigned int mpdu_len,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9617f93..252d922 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2160,7 +2160,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
- if (is_multicast_ether_addr(ehdr->h_dest)) {
+ if (is_multicast_ether_addr(ehdr->h_dest) &&
+ ieee80211_vif_get_num_mcast_if(sdata) != 0) {
/*
* send multicast frames both to higher layers in
* local net stack and back to the wireless medium
@@ -2169,7 +2170,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
if (!xmit_skb)
net_info_ratelimited("%s: failed to clone multicast frame\n",
dev->name);
- } else {
+ } else if (!is_multicast_ether_addr(ehdr->h_dest)) {
dsta = sta_info_get(sdata, skb->data);
if (dsta) {
/*
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 76b737d..216ef65 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1882,10 +1882,7 @@ int sta_info_move_state(struct sta_info *sta,
if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
- if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
- (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- !sta->sdata->u.vlan.sta))
- atomic_dec(&sta->sdata->bss->num_mcast_sta);
+ ieee80211_vif_dec_num_mcast(sta->sdata);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_clear_fast_xmit(sta);
ieee80211_clear_fast_rx(sta);
@@ -1893,10 +1890,7 @@ int sta_info_move_state(struct sta_info *sta,
break;
case IEEE80211_STA_AUTHORIZED:
if (sta->sta_state == IEEE80211_STA_ASSOC) {
- if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
- (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
- !sta->sdata->u.vlan.sta))
- atomic_inc(&sta->sdata->bss->num_mcast_sta);
+ ieee80211_vif_inc_num_mcast(sta->sdata);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_rx(sta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 5023966..c3ce86e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -331,9 +331,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
return TX_DROP;
}
- } else if (unlikely(tx->sdata->vif.type == NL80211_IFTYPE_AP &&
- ieee80211_is_data(hdr->frame_control) &&
- !atomic_read(&tx->sdata->u.ap.num_mcast_sta))) {
+ } else if (unlikely(ieee80211_is_data(hdr->frame_control) &&
+ ieee80211_vif_get_num_mcast_if(tx->sdata) == 0)) {
/*
* No associated STAs - no need to send multicast
* frames.
--
2.1.4
^ permalink raw reply related
* [PATCH v5 4/4] mac80211: multicast to unicast conversion
From: Michael Braun @ 2016-10-07 18:39 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
In-Reply-To: <1475865574-5384-1-git-send-email-michael-dev@fami-braun.de>
This patch adds support for sending multicast data packets with ARP, IPv4
and IPv6 payload (possible 802.1q tagged) as 802.11 unicast frames to all
stations.
IEEE 802.11 multicast has well known issues, among them:
1. packets are not acked and hence not retransmitted, resulting in
decreased reliablity
2. packets are send at low rate, increasing time required on air
When used with AP_VLAN, there is another disadvantage:
3. all stations in the BSS are woken up, regardsless of their AP_VLAN
assignment.
By doing multicast to unicast conversion, all three issus are solved.
IEEE802.11-2012 proposes directed multicast service (DMS) using A-MSDU
frames and a station initiated control protocol. It has the advantage that
the station can recover the destination multicast mac address, but it is
not backward compatible with non QOS stations and does not enable the
administrator of a BSS to force this mode of operation within a BSS.
Additionally, it would require both the ap and the station to implement
the control protocol, which is optional on both ends. Furthermore, I've
seen a few mobile phone stations locally that indicate qos support but
won't complete DHCP if their broadcasts are encapsulated as A-MSDU. Though
they work fine with this series approach.
This patch therefore does not opt to implement DMS but instead just
replicates the packet and changes the destination address. As this works
fine with ARP, IPv4 and IPv6, it is limited to these protocols and normal
802.11 multicast frames are send out for all other payload protocols.
There is a runtime toggle to enable multicast conversion in a per-bss
fashion.
When there is only a single station assigned to the AP_VLAN interface, no
packet replication will occur. 4addr mode of operation is unchanged.
This change opts for iterating all BSS stations for finding the stations
assigned to this AP/AP_VLAN interface, as there currently is no per
AP_VLAN list to iterate and multicast packets are expected to be few.
If needed, such a list could be added later.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
--
v5:
- rename bss->unicast to bss->multicast_to_unicast
- access sdata->bss only after checking iftype
v4:
- rename MULTICAST_TO_UNICAST to MULTICAST_TO_UNICAST
v3: fix compile error for trace.h
v2: add nl80211 toggle
rename tx_dnat to change_da
change int to bool unicast
---
net/mac80211/cfg.c | 15 +++++++
net/mac80211/debugfs_netdev.c | 3 ++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/tx.c | 101 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 120 insertions(+)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1edb017..1db4c3e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2242,6 +2242,20 @@ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
+ struct net_device *dev,
+ const bool enabled)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
+ return -1;
+
+ sdata->u.ap.multicast_to_unicast = enabled;
+
+ return 0;
+}
+
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -3400,6 +3414,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
.set_wds_peer = ieee80211_set_wds_peer,
+ .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
.rfkill_poll = ieee80211_rfkill_poll,
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ed7bff4..509c6c3 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -487,6 +487,8 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
}
IEEE80211_IF_FILE_R(num_buffered_multicast);
+IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
+
/* IBSS attributes */
static ssize_t ieee80211_if_fmt_tsf(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -642,6 +644,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(dtim_count);
DEBUGFS_ADD(num_buffered_multicast);
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
+ DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
}
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 70c0963..84374ed 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -293,6 +293,7 @@ struct ieee80211_if_ap {
driver_smps_mode; /* smps mode request */
struct work_struct request_smps_work;
+ bool multicast_to_unicast;
};
struct ieee80211_if_wds {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c3ce86e..142201d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
#include <linux/etherdevice.h>
#include <linux/bitmap.h>
#include <linux/rcupdate.h>
@@ -1770,6 +1771,102 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
+/* rewrite destination mac address */
+static int ieee80211_change_da(struct sk_buff *skb, struct sta_info *sta)
+{
+ struct ethhdr *eth;
+ int err;
+
+ err = skb_ensure_writable(skb, ETH_HLEN);
+ if (unlikely(err))
+ return err;
+
+ eth = (void *)skb->data;
+ ether_addr_copy(eth->h_dest, sta->sta.addr);
+
+ return 0;
+}
+
+/* Check if multicast to unicast conversion is needed and do it.
+ * Returns 1 if skb was freed and should not be send out.
+ */
+static int
+ieee80211_tx_multicast_to_unicast(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, u32 info_flags)
+{
+ struct ieee80211_local *local = sdata->local;
+ const struct ethhdr *eth = (void *)skb->data;
+ const struct vlan_ethhdr *ethvlan = (void *)skb->data;
+ struct sta_info *sta, *prev = NULL;
+ struct sk_buff *cloned_skb;
+ u16 ethertype;
+
+ /* check if this is a multicast frame */
+ if (!is_multicast_ether_addr(eth->h_dest))
+ return 0;
+
+ /* multicast to unicast conversion only for AP interfaces */
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ sta = rcu_dereference(sdata->u.vlan.sta);
+ if (sta) /* 4addr */
+ return 0;
+ /* fall through */
+ case NL80211_IFTYPE_AP:
+ /* check runtime toggle for this bss */
+ if (!sdata->bss->multicast_to_unicast)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ /* info_flags would not get preserved, used only by TLDS */
+ if (info_flags)
+ return 0;
+
+ /* multicast to unicast conversion only for some payload */
+ ethertype = ntohs(eth->h_proto);
+ if (ethertype == ETH_P_8021Q && skb->len >= VLAN_ETH_HLEN)
+ ethertype = ntohs(ethvlan->h_vlan_encapsulated_proto);
+ switch (ethertype) {
+ case ETH_P_ARP:
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ break;
+ default:
+ return 0;
+ }
+
+ /* clone packets and update destination mac */
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sdata != sta->sdata)
+ continue;
+ if (unlikely(!ether_addr_equal(eth->h_source, sta->sta.addr)))
+ /* do not send back to source */
+ continue;
+ if (!prev) {
+ prev = sta;
+ continue;
+ }
+ cloned_skb = skb_clone(skb, GFP_ATOMIC);
+ if (unlikely(ieee80211_change_da(cloned_skb, prev))) {
+ dev_kfree_skb(cloned_skb);
+ continue;
+ }
+ __ieee80211_subif_start_xmit(cloned_skb, cloned_skb->dev, 0);
+ prev = sta;
+ }
+
+ if (likely(prev)) {
+ ieee80211_change_da(skb, prev);
+ return 0;
+ }
+
+ /* no STA connected, drop */
+ return 1;
+}
+
/*
* Returns false if the frame couldn't be transmitted but was queued instead.
*/
@@ -3353,6 +3450,10 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_lock();
+ /* AP multicast to unicast conversion */
+ if (ieee80211_tx_multicast_to_unicast(sdata, skb, info_flags))
+ goto out_free;
+
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto out_free;
--
2.1.4
^ permalink raw reply related
* [PATCH v5 1/4] mac80211: remove unnecessary num_mcast_sta user
From: Michael Braun @ 2016-10-07 18:39 UTC (permalink / raw)
To: johannes; +Cc: Michael Braun, linux-wireless, projekt-wlan, netdev
Checking for num_mcast_sta in __ieee80211_request_smps_ap() is unnecessary,
as sta list will be empty in this case anyway, so list_for_each_entry(sta,
...) will exit immediately.
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
net/mac80211/cfg.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 543b1d4..24133f5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2313,13 +2313,6 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
smps_mode == IEEE80211_SMPS_AUTOMATIC)
return 0;
- /* If no associated stations, there's no need to do anything */
- if (!atomic_read(&sdata->u.ap.num_mcast_sta)) {
- sdata->smps_mode = smps_mode;
- ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
- return 0;
- }
-
ht_dbg(sdata,
"SMPS %d requested in AP mode, sending Action frame to %d stations\n",
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
--
2.1.4
^ permalink raw reply related
* [PATCH] wlcore: Allow scans when in AP mode
From: Xander Huff @ 2016-10-07 15:45 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, netdev, James Minor, linux-kernel, xander.huff
From: James Minor <james.minor@ni.com>
When in AP mode, scans can be done without changing firmware to
the multi-role firmware. Allow the interface to scan if forced
in the scan request.
Signed-off-by: James Minor <james.minor@ni.com>
Signed-off-by: Xander Huff <xander.huff@ni.com>
Reviewed-by: Ben Shelton <ben.shelton@ni.com>
Reviewed-by: Jaeden Amero <jaeden.amero@ni.com>
---
drivers/net/wireless/ti/wlcore/main.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 471521a..01ca370 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -6120,6 +6120,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN;
+
/* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
ARRAY_SIZE(wl1271_channels_5ghz) >
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] ath10k: add support for per sta tx bitrate
From: akolli @ 2016-10-07 14:58 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, akolli, Anilkumar Kolli
In-Reply-To: <1475852332-18217-1-git-send-email-akolli@qti.qualcomm.com>
From: Anilkumar Kolli <akolli@qti.qualcomm.com>
Per STA tx bitrate info is filled from peer stats.
Export per sta txrate info to cfg80211/nl80211
Signed-off-by: Anilkumar Kolli <akolli@qti.qualcomm.com>
---
drivers/net/wireless/ath/ath10k/debugfs_sta.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index 9955fea0802a..7daf9927a1ef 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -77,6 +77,19 @@ void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
sinfo->rx_duration = arsta->rx_duration;
sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION;
+
+ if (!arsta->txrate.legacy && !arsta->txrate.nss)
+ return;
+
+ if(arsta->txrate.legacy) {
+ sinfo->txrate.legacy = arsta->txrate.legacy;
+ } else {
+ sinfo->txrate.mcs = arsta->txrate.mcs;
+ sinfo->txrate.nss = arsta->txrate.nss;
+ sinfo->txrate.bw = arsta->txrate.bw;
+ }
+ sinfo->txrate.flags = arsta->txrate.flags;
+ sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE;
}
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/2] ath10k: add per peer htt tx stats support for 10.4
From: akolli @ 2016-10-07 14:58 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, akolli, Anilkumar Kolli
In-Reply-To: <1475852332-18217-1-git-send-email-akolli@qti.qualcomm.com>
From: Anilkumar Kolli <akolli@qti.qualcomm.com>
Per peer tx stats are part of 'HTT_10_4_T2H_MSG_TYPE_PEER_STATS'
event, Firmware sends one HTT event for every four PPDUs.
HTT payload has success pkts/bytes, failed pkts/bytes, retry
pkts/bytes and rate info per ppdu.
Peer stats are enabled through 'WMI_SERVICE_PEER_STATS',
which are nowadays enabled by default.
Parse peer stats and update the tx rate information per STA.
tx rate, Peer stats are tested on QCA4019 with Firmware version
10.4-3.2.1-00028.
Signed-off-by: Anilkumar Kolli <akolli@qti.qualcomm.com>
---
drivers/net/wireless/ath/ath10k/core.h | 17 ++++
drivers/net/wireless/ath/ath10k/htt.c | 2 +
drivers/net/wireless/ath/ath10k/htt.h | 25 ++++++
drivers/net/wireless/ath/ath10k/htt_rx.c | 125 ++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.h | 10 ++-
5 files changed, 178 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index dda49af1eb74..fc3d3bded265 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -337,6 +337,7 @@ struct ath10k_sta {
u32 nss;
u32 smps;
u16 peer_id;
+ struct rate_info txrate;
struct work_struct update_wk;
@@ -694,6 +695,21 @@ struct ath10k_fw_components {
struct ath10k_fw_file fw_file;
};
+struct ath10k_per_peer_tx_stats {
+ u32 succ_bytes;
+ u32 retry_bytes;
+ u32 failed_bytes;
+ u8 ratecode;
+ u8 flags;
+ u16 peer_id;
+ u16 succ_pkts;
+ u16 retry_pkts;
+ u16 failed_pkts;
+ u16 duration;
+ u32 reserved1;
+ u32 reserved2;
+};
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -906,6 +922,7 @@ struct ath10k {
struct ath10k_thermal thermal;
struct ath10k_wow wow;
+ struct ath10k_per_peer_tx_stats peer_tx_stats;
/* NAPI */
struct net_device napi_dev;
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 130cd9502021..cd160b16db1e 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -137,6 +137,8 @@ static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = {
HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
[HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] =
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
+ [HTT_10_4_T2H_MSG_TYPE_PEER_STATS] =
+ HTT_T2H_MSG_TYPE_PEER_STATS,
};
int ath10k_htt_connect(struct ath10k_htt *htt)
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 0d2ed09f202b..164eb3a10566 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -419,6 +419,7 @@ enum htt_10_4_t2h_msg_type {
HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18,
/* 0x19 to 0x2f are reserved */
HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND = 0x30,
+ HTT_10_4_T2H_MSG_TYPE_PEER_STATS = 0x31,
/* keep this last */
HTT_10_4_T2H_NUM_MSGS
};
@@ -453,6 +454,7 @@ enum htt_t2h_msg_type {
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
+ HTT_T2H_MSG_TYPE_PEER_STATS,
/* keep this last */
HTT_T2H_NUM_MSGS
};
@@ -1470,6 +1472,28 @@ struct htt_channel_change {
__le32 phymode;
} __packed;
+struct htt_per_peer_tx_stats_ind {
+ __le32 succ_bytes;
+ __le32 retry_bytes;
+ __le32 failed_bytes;
+ u8 ratecode;
+ u8 flags;
+ __le16 peer_id;
+ __le16 succ_pkts;
+ __le16 retry_pkts;
+ __le16 failed_pkts;
+ __le16 tx_duration;
+ __le32 reserved1;
+ __le32 reserved2;
+} __packed;
+
+struct htt_peer_tx_stats {
+ u8 num_ppdu;
+ u8 ppdu_len;
+ u8 version;
+ u8 payload[0];
+} __packed;
+
union htt_rx_pn_t {
/* WEP: 24-bit PN */
u32 pn24;
@@ -1521,6 +1545,7 @@ struct htt_resp {
struct htt_tx_fetch_confirm tx_fetch_confirm;
struct htt_tx_mode_switch_ind tx_mode_switch_ind;
struct htt_channel_change chan_change;
+ struct htt_peer_tx_stats peer_tx_stats;
};
} __packed;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 0b4c1562420f..eab719d9729b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2194,6 +2194,128 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
dev_kfree_skb_any(skb);
}
+static inline bool is_valid_legacy_rate(u8 rate)
+{
+ static const u8 legacy_rates[] = {1, 2, 5, 11, 6, 9, 12,
+ 18, 24, 36, 48, 54};
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(legacy_rates); i++) {
+ if (rate == legacy_rates[i])
+ return true;
+ }
+
+ return false;
+}
+
+static void
+ath10k_update_per_peer_tx_stats(struct ath10k *ar,
+ struct ieee80211_sta *sta,
+ struct ath10k_per_peer_tx_stats *peer_stats)
+{
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ u8 rate = 0, sgi;
+ struct rate_info txrate;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ txrate.flags = ATH10K_HW_PREAMBLE(peer_stats->ratecode);
+ txrate.bw = ATH10K_HW_BW(peer_stats->flags);
+ txrate.nss = ATH10K_HW_NSS(peer_stats->ratecode);
+ txrate.mcs = ATH10K_HW_MCS_RATE(peer_stats->ratecode);
+ sgi = ATH10K_HW_GI(peer_stats->flags);
+
+ if (((txrate.flags == WMI_RATE_PREAMBLE_HT) ||
+ (txrate.flags == WMI_RATE_PREAMBLE_VHT)) && txrate.mcs > 9) {
+ ath10k_warn(ar, "Invalid mcs %hhd peer stats", txrate.mcs);
+ return;
+ }
+
+ if (txrate.flags == WMI_RATE_PREAMBLE_CCK ||
+ txrate.flags == WMI_RATE_PREAMBLE_OFDM) {
+ rate = ATH10K_HW_LEGACY_RATE(peer_stats->ratecode);
+
+ if (!is_valid_legacy_rate(rate)) {
+ ath10k_warn(ar, "Invalid legacy rate %hhd peer stats",
+ rate);
+ return;
+ }
+
+ /* This is hacky, FW sends CCK rate 5.5Mbps as 6 */
+ rate *= 10;
+ if (rate == 60 && txrate.flags == WMI_RATE_PREAMBLE_CCK)
+ rate = rate - 5;
+ arsta->txrate.legacy = rate * 10;
+ } else if (txrate.flags == WMI_RATE_PREAMBLE_HT) {
+ arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
+ arsta->txrate.mcs = txrate.mcs;
+ } else {
+ arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+ arsta->txrate.mcs = txrate.mcs;
+ }
+
+ if (sgi)
+ arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ arsta->txrate.nss = txrate.nss;
+ arsta->txrate.bw = txrate.bw + RATE_INFO_BW_20;
+}
+
+static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ struct htt_resp *resp = (struct htt_resp *)skb->data;
+ struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats;
+ struct htt_per_peer_tx_stats_ind *tx_stats;
+ struct ieee80211_sta *sta;
+ struct ath10k_peer *peer;
+ u32 peer_id, i;
+ u8 ppdu_len, num_ppdu;
+
+ num_ppdu = resp->peer_tx_stats.num_ppdu;
+ ppdu_len = resp->peer_tx_stats.ppdu_len * sizeof(__le32);
+
+ if (skb->len < sizeof(struct htt_resp_hdr) + num_ppdu * ppdu_len) {
+ ath10k_warn(ar, "Invalid peer stats buffer length\n", skb->len);
+ return;
+ }
+
+ tx_stats = (struct htt_per_peer_tx_stats_ind *)
+ (resp->peer_tx_stats.payload);
+ peer_id = tx_stats->peer_id;
+
+ rcu_read_lock();
+ spin_lock_bh(&ar->data_lock);
+ peer = ath10k_peer_find_by_id(ar, peer_id);
+ if (!peer) {
+ ath10k_warn(ar, "Invalid peer id %d peer stats buffer\n",
+ peer_id);
+ goto out;
+ }
+
+ sta = peer->sta;
+ for (i = 0; i < num_ppdu; i++) {
+ tx_stats = (struct htt_per_peer_tx_stats_ind *)
+ (resp->peer_tx_stats.payload + i * ppdu_len);
+
+ p_tx_stats->succ_bytes = __le32_to_cpu(tx_stats->succ_bytes);
+ p_tx_stats->retry_bytes = __le32_to_cpu(tx_stats->retry_bytes);
+ p_tx_stats->failed_bytes =
+ __le32_to_cpu(tx_stats->failed_bytes);
+ p_tx_stats->ratecode = tx_stats->ratecode;
+ p_tx_stats->flags = tx_stats->flags;
+ p_tx_stats->succ_pkts = __le16_to_cpu(tx_stats->succ_pkts);
+ p_tx_stats->retry_pkts = __le16_to_cpu(tx_stats->retry_pkts);
+ p_tx_stats->failed_pkts = __le16_to_cpu(tx_stats->failed_pkts);
+
+ ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats);
+ }
+
+out:
+ spin_unlock_bh(&ar->data_lock);
+ rcu_read_unlock();
+}
+
bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -2354,6 +2476,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
ath10k_htt_rx_tx_mode_switch_ind(ar, skb);
break;
+ case HTT_T2H_MSG_TYPE_PEER_STATS:
+ ath10k_htt_fetch_peer_stats(ar, skb);
+ break;
case HTT_T2H_MSG_TYPE_EN_STATS:
default:
ath10k_warn(ar, "htt event (%d) not handled\n",
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 1b243c899bef..e108d49998c3 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4603,9 +4603,17 @@ enum wmi_rate_preamble {
#define ATH10K_HW_NSS(rate) (1 + (((rate) >> 4) & 0x3))
#define ATH10K_HW_PREAMBLE(rate) (((rate) >> 6) & 0x3)
-#define ATH10K_HW_RATECODE(rate, nss, preamble) \
+#define ATH10K_HW_MCS_RATE(rate) ((rate) & 0xf)
+#define ATH10K_HW_LEGACY_RATE(rate) ((rate) & 0x3f)
+#define ATH10K_HW_BW(flags) (((flags) >> 3) & 0x3)
+#define ATH10K_HW_GI(flags) (((flags) >> 5) & 0x1)
+#define ATH10K_HW_RATECODE(rate, nss, preamble) \
(((preamble) << 6) | ((nss) << 4) | (rate))
+#define VHT_MCS_NUM 10
+#define VHT_BW_NUM 4
+#define VHT_NSS_NUM 4
+
/* Value to disable fixed rate setting */
#define WMI_FIXED_RATE_NONE (0xff)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/2] ath10k: add support for tx bitrate
From: akolli @ 2016-10-07 14:58 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, akolli
From: Anilkumar Kolli <akolli@codeaurora.org>
This patch series adds support for tx bitrate using
.sta_statistics callback.
tx bitrate tested on QCA4019 using iw.
Anilkumar Kolli (2):
ath10k: add per peer htt tx stats support for 10.4
ath10k: add support for per sta tx bitrate
drivers/net/wireless/ath/ath10k/core.h | 17 ++++
drivers/net/wireless/ath/ath10k/debugfs_sta.c | 13 +++
drivers/net/wireless/ath/ath10k/htt.c | 2 +
drivers/net/wireless/ath/ath10k/htt.h | 25 +++++
drivers/net/wireless/ath/ath10k/htt_rx.c | 125 +++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.h | 10 +-
6 files changed, 191 insertions(+), 1 deletion(-)
--
1.7.9.5
^ permalink raw reply
* Re: bcmdhd: Strange Power Save messages
From: Gucea Doru @ 2016-10-07 14:33 UTC (permalink / raw)
To: Arend Van Spriel
Cc: Krishna Chaitanya, Arend van Spriel, Andra Paraschiv,
linux-wireless
In-Reply-To: <8d01e83b-800d-bba4-b948-abbdc5188f6b@broadcom.com>
On Thu, Oct 6, 2016 at 10:25 AM, Arend Van Spriel
<arend.vanspriel@broadcom.com> wrote:
> On 6-10-2016 10:07, Gucea Doru wrote:
>> On Wed, Oct 5, 2016 at 11:12 AM, Arend Van Spriel
>> <arend.vanspriel@broadcom.com> wrote:
>>> On 4-10-2016 13:39, Gucea Doru wrote:
>>>> On Sat, Oct 1, 2016 at 2:52 PM, Arend van Spriel
>>>>> <arend.vanspriel@broadcom.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 29-09-16 13:32, Gucea Doru wrote:
>>>>>>> On Tue, Sep 27, 2016 at 12:03 PM, Gucea Doru <gucea.doru@gmail.com> wrote:
>>>>>>>> What is the decision triggering the exit from the PS mode immediately
>>>>>>>> after the ping request? I am asking this because 802.11 PS legacy
>>>>>>>> specifies that the client should wait for a beacon with TIM set in
>>>>>>>> order to wake up: in my case, there is no beacon between the ping
>>>>>>>> request message and the Null frame that announces the exit from the PS
>>>>>>>> mode.
>>>>>>>
>>>>>>>
>>>>>>> Any help would be highly appreciated :)
>>>>>>
>>>>>> Actually though I already sent you are reply, but alas here it is.
>>>>>>
>>>>>> bcmdhd is our aosp driver. I am maintaining the upstream brcm80211
>>>>>> drivers. Regardless your question is more for firmware running on the
>>>>>> device. So like the same behavior would be observed when using brcmfmac
>>>>>> with same firmware.
>>>>>>
>>>>>>> IEEE Std 802.11-2012, section 10.2.1.8 specifies that "when the STA
>>>>>>> detects that the bit corresponding to its AID is 1 i the TIM, the STA
>>>>>>> shall issue a PS Poll". In my capture there are cases when the STA
>>>>>>> exits the PS mode without waiting for a beacon.
>>>>>>
>>>>>> It is a bit tricky, but the standard does not explicitly say the STA
>>>>>> should be in power-save at any other time. So it is difficult to say
>>>>>> what event occurred on the STA side to exit PS mode. Also STA means
>>>>>> P2P-Client as you say. That means that you have multiple interfaces:
>>>>>> regular STA and P2P-Client. So is the STA connected to some other AP or
>>>>>> just not connected. wpa_supplicant will do intermittent scan or initiate
>>>>>> scheduled scan by which firmware will scan at a certain interval. That
>>>>>> is just some things I can come up with and I am sure there are more.
>>>>
>>>> I agree that there may be some events belonging to the regular STA
>>>> interface that could trigger the Null Frame (which includes the exit
>>>> from PS Mode). However, I would expect to see some management frames
>>>> in the air before/after the Null Packet (e.g.: a Probe request in case
>>>> of a scheduled scan). But in my case the trigger for the Null frame
>>>> seems to be the ping request packet, the scenario is the same every
>>>> time: ping request -> Block ACK -> Null Frame (Wireshark trace
>>>> confirms this behavior).
>>>>
>>>> I thought that you had a power save optimization algorithm that keeps
>>>> the card on a few milliseconds just to see if we can have a fast reply
>>>> from the peer. Does this ring a bell? :)
>>>
>>> It does not. That would be implemented in firmware. As said I am working
>>> on brcmfmac/brcmsmac. So bcmdhd and firmware are not my expertise.
>>>
>>
>> Arend, could you please redirect me to a Broadcom firmware maintainer?
>
> Can you please elaborate on your platform, broadcom chipset, and what
> version of bcmdhd you are using.
>
Platform: Nexus 5 running CM13 (Android 6.0.1)
Broadcom chipset: BCM4339 Wi-Fi Chipset
bcmdhd version:Dongle Host Driver, version 1.88.45 (r)
Do you need more information?
Thank you,
Doru
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox