Changes since v2:
- fix throughput computation in minstrel
- squash minstrel patches
Changes since v1:
- add expected throughput nl80211 attribute to the GET_STATION reply
message
- the unit of the exported value has been changed to kbps
- the way the exported value was computed in minstrel and minstrel_ht has been
changed after having really understood what minstrel is doing (thanks
Johannes!)
- the number of arguments of the RC api have been reduced
- allow the API result to be 0 if the underlying layer does not know what to
report
- squash ex patch 2/3/4
- use wiphy_to_rdev() where needed
Antonio Quartulli (4):
cfg80211: export expected throughput through get_station()
cfg80211: export expected throughput via nl80211 (GET_STATION)
mac80211: export the expected throughput
cfg80211: implement cfg80211_get_station cfg80211 API
include/net/cfg80211.h | 75 ++++++++++++++++++++++++--------------
include/net/mac80211.h | 7 ++++
include/uapi/linux/nl80211.h | 3 ++
net/mac80211/cfg.c | 19 ++++++++++
net/mac80211/driver-ops.h | 13 +++++++
net/mac80211/rc80211_minstrel.c | 12 ++++++
net/mac80211/rc80211_minstrel_ht.c | 17 +++++++++
net/mac80211/trace.h | 32 ++++++++++++++++
net/wireless/nl80211.c | 4 ++
net/wireless/util.c | 18 +++++++++
10 files changed, 172 insertions(+), 28 deletions(-)
--
1.8.5.5
On Sat, 2014-05-17 at 18:41 +0200, Antonio Quartulli wrote:
> From: Antonio Quartulli <[email protected]>
>
> Send the expected throughput when replying to a GET_STATION
> command via nl80211.
Since both are pretty short I think you might also just squash patches 1
and 2.
johannes
On 19/05/14 17:00, Johannes Berg wrote:
> On Sat, 2014-05-17 at 18:41 +0200, Antonio Quartulli wrote:
>> From: Antonio Quartulli <[email protected]>
>>
>> Send the expected throughput when replying to a GET_STATION
>> command via nl80211.
>
> Since both are pretty short I think you might also just squash patches 1
> and 2.
Ok, will resend with 1/4 and 2/4 squashed and I'll add the u32 spec.
Thanks!
--
Antonio Quartulli
From: Antonio Quartulli <[email protected]>
Add get_expected_throughput() API to mac80211 so that each
driver can implement its own version based on the RC
algorithm they are using (might be using an HW RC algo).
The API returns a value expressed in Kbps.
Also, add the new get_expected_throughput() member
to the rate_control_ops structure in order to be
able to query the RC algorithm (this patch provides an
implementation of this API for both minstrel and
minstrel_ht).
The related member in the station_info object is now
filled accordingly when dumping a station.
Cc: Felix Fietkau <[email protected]>
Signed-off-by: Antonio Quartulli <[email protected]>
---
include/net/mac80211.h | 7 +++++++
net/mac80211/cfg.c | 19 +++++++++++++++++++
net/mac80211/driver-ops.h | 13 +++++++++++++
net/mac80211/rc80211_minstrel.c | 12 ++++++++++++
net/mac80211/rc80211_minstrel_ht.c | 17 +++++++++++++++++
net/mac80211/trace.h | 32 ++++++++++++++++++++++++++++++++
6 files changed, 100 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 982d2cd..81efbc7 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2769,6 +2769,10 @@ enum ieee80211_roc_type {
* information in bss_conf is set up and the beacon can be retrieved. A
* channel context is bound before this is called.
* @leave_ibss: Leave the IBSS again.
+ *
+ * @get_expected_throughput: extract the expected throughput towards the
+ * specified station. The returned value is expressed in Kbps. It returns 0
+ * if the RC algorithm does not have proper data to provide.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -2962,6 +2966,7 @@ struct ieee80211_ops {
int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+ u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
};
/**
@@ -4534,6 +4539,8 @@ struct rate_control_ops {
void (*add_sta_debugfs)(void *priv, void *priv_sta,
struct dentry *dir);
void (*remove_sta_debugfs)(void *priv, void *priv_sta);
+
+ u32 (*get_expected_throughput)(void *priv_sta);
};
static inline int rate_supported(struct ieee80211_sta *sta,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bfd2534..d739409 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -472,8 +472,12 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
+ struct rate_control_ref *ref = local->rate_ctrl;
+ struct ieee80211_supported_band *sband;
+ enum ieee80211_band band;
struct timespec uptime;
u64 packets = 0;
+ u32 thr = 0;
int i, ac;
sinfo->generation = sdata->local->sta_generation;
@@ -587,6 +591,21 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+ /* check if the driver has a SW RC implementation */
+ if (ref && ref->ops->get_expected_throughput) {
+ band = ieee80211_get_sdata_band(sta->sdata);
+ sband = sta->local->hw.wiphy->bands[band];
+
+ thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
+ } else {
+ thr = drv_get_expected_throughput(local, &sta->sta);
+ }
+
+ if (thr != 0) {
+ sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
+ sinfo->expected_throughput = thr;
+ }
}
static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index df1d502..696ef78 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1156,4 +1156,17 @@ static inline void drv_leave_ibss(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline u32 drv_get_expected_throughput(struct ieee80211_local *local,
+ struct ieee80211_sta *sta)
+{
+ u32 ret = 0;
+
+ trace_drv_get_expected_throughput(sta);
+ if (local->ops->get_expected_throughput)
+ ret = local->ops->get_expected_throughput(sta);
+ trace_drv_return_u32(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 26fd94f..1c1469c 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -657,6 +657,17 @@ minstrel_free(void *priv)
kfree(priv);
}
+static u32 minstrel_get_expected_throughput(void *priv_sta)
+{
+ struct minstrel_sta_info *mi = priv_sta;
+ int idx = mi->max_tp_rate[0];
+
+ /* convert pkt per sec in kbps (1200 is the average pkt size used for
+ * computing cur_tp
+ */
+ return MINSTREL_TRUNC(mi->r[idx].cur_tp) * 1200 * 8 / 1024;
+}
+
const struct rate_control_ops mac80211_minstrel = {
.name = "minstrel",
.tx_status = minstrel_tx_status,
@@ -670,6 +681,7 @@ const struct rate_control_ops mac80211_minstrel = {
.add_sta_debugfs = minstrel_add_sta_debugfs,
.remove_sta_debugfs = minstrel_remove_sta_debugfs,
#endif
+ .get_expected_throughput = minstrel_get_expected_throughput,
};
int __init
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index bccaf85..949fb01 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1031,6 +1031,22 @@ minstrel_ht_free(void *priv)
mac80211_minstrel.free(priv);
}
+static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ int i, j;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.get_expected_throughput(priv_sta);
+
+ i = mi->max_tp_rate / MCS_GROUP_RATES;
+ j = mi->max_tp_rate % MCS_GROUP_RATES;
+
+ /* convert cur_tp from pkt per second in kbps */
+ return mi->groups[i].rates[j].cur_tp * AVG_PKT_SIZE * 8 / 1024;
+}
+
static const struct rate_control_ops mac80211_minstrel_ht = {
.name = "minstrel_ht",
.tx_status = minstrel_ht_tx_status,
@@ -1045,6 +1061,7 @@ static const struct rate_control_ops mac80211_minstrel_ht = {
.add_sta_debugfs = minstrel_ht_add_sta_debugfs,
.remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
#endif
+ .get_expected_throughput = minstrel_ht_get_expected_throughput,
};
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index a0b0aea..942f64b 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -184,6 +184,20 @@ TRACE_EVENT(drv_return_bool,
"true" : "false")
);
+TRACE_EVENT(drv_return_u32,
+ TP_PROTO(struct ieee80211_local *local, u32 ret),
+ TP_ARGS(local, ret),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, ret)
+ ),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->ret = ret;
+ ),
+ TP_printk(LOCAL_PR_FMT " - %u", LOCAL_PR_ARG, __entry->ret)
+);
+
TRACE_EVENT(drv_return_u64,
TP_PROTO(struct ieee80211_local *local, u64 ret),
TP_ARGS(local, ret),
@@ -1499,6 +1513,24 @@ DEFINE_EVENT(local_sdata_evt, drv_leave_ibss,
TP_ARGS(local, sdata)
);
+TRACE_EVENT(drv_get_expected_throughput,
+ TP_PROTO(struct ieee80211_sta *sta),
+
+ TP_ARGS(sta),
+
+ TP_STRUCT__entry(
+ STA_ENTRY
+ ),
+
+ TP_fast_assign(
+ STA_ASSIGN;
+ ),
+
+ TP_printk(
+ STA_PR_FMT, STA_PR_ARG
+ )
+);
+
/*
* Tracing for API calls that drivers call.
*/
--
1.8.5.5
On Sat, 2014-05-17 at 18:41 +0200, Antonio Quartulli wrote:
> From: Antonio Quartulli <[email protected]>
>
> Send the expected throughput when replying to a GET_STATION
> command via nl80211.
>
> Signed-off-by: Antonio Quartulli <[email protected]>
> ---
> include/uapi/linux/nl80211.h | 3 +++
> net/wireless/nl80211.c | 4 ++++
> 2 files changed, 7 insertions(+)
>
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index 0cfa827..2964948 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -2199,6 +2199,8 @@ enum nl80211_sta_bss_param {
> * Contains a nested array of signal strength attributes (u8, dBm)
> * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
> * Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
> + * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput (considering also the
> + * 802.11 header) expressed in kbps
This should say it's a u32.
johannes
From: Antonio Quartulli <[email protected]>
Send the expected throughput when replying to a GET_STATION
command via nl80211.
Signed-off-by: Antonio Quartulli <[email protected]>
---
include/uapi/linux/nl80211.h | 3 +++
net/wireless/nl80211.c | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 0cfa827..2964948 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2199,6 +2199,8 @@ enum nl80211_sta_bss_param {
* Contains a nested array of signal strength attributes (u8, dBm)
* @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
* Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
+ * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput (considering also the
+ * 802.11 header) expressed in kbps
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2230,6 +2232,7 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_BYTES64,
NL80211_STA_INFO_CHAIN_SIGNAL,
NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
+ NL80211_STA_INFO_EXPECTED_THROUGHPUT,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca19b15..9631648 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3650,6 +3650,10 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED,
sinfo->tx_failed))
goto nla_put_failure;
+ if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) &&
+ nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT,
+ sinfo->expected_throughput))
+ goto nla_put_failure;
if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) &&
nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
sinfo->beacon_loss_count))
--
1.8.5.5
From: Antonio Quartulli <[email protected]>
Implement and export the new cfg80211_get_station() API.
This utility can be used by other kernel modules to obtain
detailed information about a given wireless station.
It will be in particular useful to batman-adv which will
implement a wireless rate based metric.
Signed-off-by: Antonio Quartulli <[email protected]>
---
include/net/cfg80211.h | 13 +++++++++++++
net/wireless/util.c | 18 ++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 394189e..5917919 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1075,6 +1075,19 @@ struct station_info {
};
/**
+ * cfg80211_get_station - retrieve information about a given station
+ * @dev: the device where the station is supposed to be connected to
+ * @mac_addr: the mac address of the station of interest
+ * @sinfo: pointer to the structure to fill with the information
+ *
+ * Returns 0 on success and sinfo is filled with the available information
+ * otherwise returns a negative error code and the content of sinfo has to be
+ * considered undefined.
+ */
+int cfg80211_get_station(struct net_device *dev, u8 *mac_addr,
+ struct station_info *sinfo);
+
+/**
* enum monitor_flags - monitor flags
*
* Monitor interface configuration flags. Note that these must be the bits
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 8c61d5c..6380e55 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1545,6 +1545,24 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
}
EXPORT_SYMBOL(ieee80211_get_num_supported_channels);
+int cfg80211_get_station(struct net_device *dev, u8 *mac_addr,
+ struct station_info *sinfo)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
+
+ wdev = dev->ieee80211_ptr;
+ if (!wdev)
+ return -EOPNOTSUPP;
+
+ rdev = wiphy_to_rdev(wdev->wiphy);
+ if (!rdev->ops->get_station)
+ return -EOPNOTSUPP;
+
+ return rdev_get_station(rdev, dev, mac_addr, sinfo);
+}
+EXPORT_SYMBOL(cfg80211_get_station);
+
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
const unsigned char rfc1042_header[] __aligned(2) =
--
1.8.5.5
From: Antonio Quartulli <[email protected]>
Users may need information about the expected throughput
towards a given peer.
This value is supposed to consider the size overhead
generated by the 802.11 header.
Export such value in kbps through the get_station() API
(by including it into the station_info object).
This information will be useful to the batman-adv module
which will use it for its new metric computation.
Signed-off-by: Antonio Quartulli <[email protected]>
---
include/net/cfg80211.h | 62 +++++++++++++++++++++++++++-----------------------
1 file changed, 34 insertions(+), 28 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 447cb58..394189e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -873,36 +873,38 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
* @STATION_INFO_NONPEER_PM: @nonpeer_pm filled
* @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
* @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
+ * @STATION_INFO_EXPECTED_THROUGHPUT: @expected_throughput filled
*/
enum station_info_flags {
- STATION_INFO_INACTIVE_TIME = 1<<0,
- STATION_INFO_RX_BYTES = 1<<1,
- STATION_INFO_TX_BYTES = 1<<2,
- STATION_INFO_LLID = 1<<3,
- STATION_INFO_PLID = 1<<4,
- STATION_INFO_PLINK_STATE = 1<<5,
- STATION_INFO_SIGNAL = 1<<6,
- STATION_INFO_TX_BITRATE = 1<<7,
- STATION_INFO_RX_PACKETS = 1<<8,
- STATION_INFO_TX_PACKETS = 1<<9,
- STATION_INFO_TX_RETRIES = 1<<10,
- STATION_INFO_TX_FAILED = 1<<11,
- STATION_INFO_RX_DROP_MISC = 1<<12,
- STATION_INFO_SIGNAL_AVG = 1<<13,
- STATION_INFO_RX_BITRATE = 1<<14,
- STATION_INFO_BSS_PARAM = 1<<15,
- STATION_INFO_CONNECTED_TIME = 1<<16,
- STATION_INFO_ASSOC_REQ_IES = 1<<17,
- STATION_INFO_STA_FLAGS = 1<<18,
- STATION_INFO_BEACON_LOSS_COUNT = 1<<19,
- STATION_INFO_T_OFFSET = 1<<20,
- STATION_INFO_LOCAL_PM = 1<<21,
- STATION_INFO_PEER_PM = 1<<22,
- STATION_INFO_NONPEER_PM = 1<<23,
- STATION_INFO_RX_BYTES64 = 1<<24,
- STATION_INFO_TX_BYTES64 = 1<<25,
- STATION_INFO_CHAIN_SIGNAL = 1<<26,
- STATION_INFO_CHAIN_SIGNAL_AVG = 1<<27,
+ STATION_INFO_INACTIVE_TIME = BIT(0),
+ STATION_INFO_RX_BYTES = BIT(1),
+ STATION_INFO_TX_BYTES = BIT(2),
+ STATION_INFO_LLID = BIT(3),
+ STATION_INFO_PLID = BIT(4),
+ STATION_INFO_PLINK_STATE = BIT(5),
+ STATION_INFO_SIGNAL = BIT(6),
+ STATION_INFO_TX_BITRATE = BIT(7),
+ STATION_INFO_RX_PACKETS = BIT(8),
+ STATION_INFO_TX_PACKETS = BIT(9),
+ STATION_INFO_TX_RETRIES = BIT(10),
+ STATION_INFO_TX_FAILED = BIT(11),
+ STATION_INFO_RX_DROP_MISC = BIT(12),
+ STATION_INFO_SIGNAL_AVG = BIT(13),
+ STATION_INFO_RX_BITRATE = BIT(14),
+ STATION_INFO_BSS_PARAM = BIT(15),
+ STATION_INFO_CONNECTED_TIME = BIT(16),
+ STATION_INFO_ASSOC_REQ_IES = BIT(17),
+ STATION_INFO_STA_FLAGS = BIT(18),
+ STATION_INFO_BEACON_LOSS_COUNT = BIT(19),
+ STATION_INFO_T_OFFSET = BIT(20),
+ STATION_INFO_LOCAL_PM = BIT(21),
+ STATION_INFO_PEER_PM = BIT(22),
+ STATION_INFO_NONPEER_PM = BIT(23),
+ STATION_INFO_RX_BYTES64 = BIT(24),
+ STATION_INFO_TX_BYTES64 = BIT(25),
+ STATION_INFO_CHAIN_SIGNAL = BIT(26),
+ STATION_INFO_CHAIN_SIGNAL_AVG = BIT(27),
+ STATION_INFO_EXPECTED_THROUGHPUT = BIT(28),
};
/**
@@ -1024,6 +1026,8 @@ struct sta_bss_parameters {
* @local_pm: local mesh STA power save mode
* @peer_pm: peer mesh STA power save mode
* @nonpeer_pm: non-peer mesh STA power save mode
+ * @expected_throughput: expected throughput in kbps (including 802.11 headers)
+ * towards this station.
*/
struct station_info {
u32 filled;
@@ -1062,6 +1066,8 @@ struct station_info {
enum nl80211_mesh_power_mode peer_pm;
enum nl80211_mesh_power_mode nonpeer_pm;
+ u32 expected_throughput;
+
/*
* Note: Add a new enum station_info_flags value for each new field and
* use it to check which fields are initialized.
--
1.8.5.5