2013-04-22 14:29:33

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 1/2] cfg80211: add support for per-chain signal strength reporting

Signed-off-by: Felix Fietkau <[email protected]>
---
include/net/cfg80211.h | 14 ++++++++++++++
include/uapi/linux/nl80211.h | 6 ++++++
net/wireless/nl80211.c | 38 ++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dff96d8..0c51500 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -753,6 +753,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
* @STATION_INFO_LOCAL_PM: @local_pm filled
* @STATION_INFO_PEER_PM: @peer_pm filled
* @STATION_INFO_NONPEER_PM: @nonpeer_pm filled
+ * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
+ * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
*/
enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0,
@@ -781,6 +783,8 @@ enum station_info_flags {
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,
};

/**
@@ -857,6 +861,8 @@ struct sta_bss_parameters {
u16 beacon_interval;
};

+#define IEEE80211_MAX_CHAINS 4
+
/**
* struct station_info - station information
*
@@ -874,6 +880,9 @@ struct sta_bss_parameters {
* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
* @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg
+ * @chain_signal: per-chain signal strength of last received packet in dBm
+ * @chain_signal_avg: per-chain signal strength average in dBm
* @txrate: current unicast bitrate from this station
* @rxrate: current unicast bitrate to this station
* @rx_packets: packets received from this station
@@ -909,6 +918,11 @@ struct station_info {
u8 plink_state;
s8 signal;
s8 signal_avg;
+
+ u8 chains;
+ s8 chain_signal[IEEE80211_MAX_CHAINS];
+ s8 chain_signal_avg[IEEE80211_MAX_CHAINS];
+
struct rate_info txrate;
struct rate_info rxrate;
u32 rx_packets;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 79da871..2f9c380 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1973,6 +1973,10 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
* @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
* non-peer STA
+ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
+ * 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_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2002,6 +2006,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_NONPEER_PM,
NL80211_STA_INFO_RX_BYTES64,
NL80211_STA_INFO_TX_BYTES64,
+ NL80211_STA_INFO_CHAIN_SIGNAL,
+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG,

/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 671b69a..c09a84e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3365,6 +3365,32 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
return true;
}

+static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
+ int id)
+{
+ void *attr;
+ int i = 0;
+
+ if (!mask)
+ return true;
+
+ attr = nla_nest_start(msg, id);
+ if (!attr)
+ return false;
+
+ for (i = 0; i < IEEE80211_MAX_CHAINS; i++) {
+ if (!(mask & BIT(i)))
+ continue;
+
+ if (nla_put_u8(msg, i, signal[i]))
+ return false;
+ }
+
+ nla_nest_end(msg, attr);
+
+ return true;
+}
+
static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
int flags,
struct cfg80211_registered_device *rdev,
@@ -3436,6 +3462,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
default:
break;
}
+ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
+ if (!nl80211_put_signal(msg, sinfo->chains,
+ sinfo->chain_signal,
+ NL80211_STA_INFO_CHAIN_SIGNAL))
+ goto nla_put_failure;
+ }
+ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
+ if (!nl80211_put_signal(msg, sinfo->chains,
+ sinfo->chain_signal_avg,
+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
+ goto nla_put_failure;
+ }
if (sinfo->filled & STATION_INFO_TX_BITRATE) {
if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
NL80211_STA_INFO_TX_BITRATE))
--
1.8.0.2



2013-04-22 14:53:05

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] mac80211: add support for per-chain signal strength reporting

On 2013-04-22 4:37 PM, Johannes Berg wrote:
> On Mon, 2013-04-22 at 16:29 +0200, Felix Fietkau wrote:
>> Signed-off-by: Felix Fietkau <[email protected]>
>> ---
>> include/net/mac80211.h | 5 +++++
>> net/mac80211/cfg.c | 13 ++++++++++++-
>> net/mac80211/rx.c | 14 ++++++++++++++
>> net/mac80211/sta_info.c | 2 ++
>> net/mac80211/sta_info.h | 5 +++++
>> 5 files changed, 38 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
>> index 4ecff78..aeb4a5c 100644
>> --- a/include/net/mac80211.h
>> +++ b/include/net/mac80211.h
>> @@ -848,6 +848,9 @@ enum mac80211_rx_flags {
>> * @signal: signal strength when receiving this frame, either in dBm, in dB or
>> * unspecified depending on the hardware capabilities flags
>> * @IEEE80211_HW_SIGNAL_*
>> + * @chains: bitmask of receive chains for which separate signal strength
>> + * values were filled.
>> + * @chain_signal: per-chain signal strength, same format as @signal
>
> Oops, sorry, I should've looked at this patch before ... This isn't
> right, @signal can be in "dB" or "unspec" units, but @chain_signal is
> required to be dBm. If you want, I'll edit the patch to just say that it
> must only be provided in dBm?
OK, sounds good.

- Felix


2013-04-22 14:37:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] mac80211: add support for per-chain signal strength reporting

On Mon, 2013-04-22 at 16:29 +0200, Felix Fietkau wrote:
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
> include/net/mac80211.h | 5 +++++
> net/mac80211/cfg.c | 13 ++++++++++++-
> net/mac80211/rx.c | 14 ++++++++++++++
> net/mac80211/sta_info.c | 2 ++
> net/mac80211/sta_info.h | 5 +++++
> 5 files changed, 38 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 4ecff78..aeb4a5c 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -848,6 +848,9 @@ enum mac80211_rx_flags {
> * @signal: signal strength when receiving this frame, either in dBm, in dB or
> * unspecified depending on the hardware capabilities flags
> * @IEEE80211_HW_SIGNAL_*
> + * @chains: bitmask of receive chains for which separate signal strength
> + * values were filled.
> + * @chain_signal: per-chain signal strength, same format as @signal

Oops, sorry, I should've looked at this patch before ... This isn't
right, @signal can be in "dB" or "unspec" units, but @chain_signal is
required to be dBm. If you want, I'll edit the patch to just say that it
must only be provided in dBm?

johannes


2013-04-22 14:29:33

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 2/2] mac80211: add support for per-chain signal strength reporting

Signed-off-by: Felix Fietkau <[email protected]>
---
include/net/mac80211.h | 5 +++++
net/mac80211/cfg.c | 13 ++++++++++++-
net/mac80211/rx.c | 14 ++++++++++++++
net/mac80211/sta_info.c | 2 ++
net/mac80211/sta_info.h | 5 +++++
5 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4ecff78..aeb4a5c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -848,6 +848,9 @@ enum mac80211_rx_flags {
* @signal: signal strength when receiving this frame, either in dBm, in dB or
* unspecified depending on the hardware capabilities flags
* @IEEE80211_HW_SIGNAL_*
+ * @chains: bitmask of receive chains for which separate signal strength
+ * values were filled.
+ * @chain_signal: per-chain signal strength, same format as @signal
* @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates or MCS index if
* HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
@@ -879,6 +882,8 @@ struct ieee80211_rx_status {
u8 band;
u8 antenna;
s8 signal;
+ u8 chains;
+ s8 chain_signal[IEEE80211_MAX_CHAINS];
u8 ampdu_delimiter_crc;
u8 vendor_radiotap_align;
u8 vendor_radiotap_oui[3];
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 490990e..b1b8841 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -444,7 +444,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
struct ieee80211_local *local = sdata->local;
struct timespec uptime;
u64 packets = 0;
- int ac;
+ int i, ac;

sinfo->generation = sdata->local->sta_generation;

@@ -488,6 +488,17 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->signal = (s8)sta->last_signal;
sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
}
+ if (sta->chains) {
+ sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
+ STATION_INFO_CHAIN_SIGNAL_AVG;
+
+ sinfo->chains = sta->chains;
+ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
+ sinfo->chain_signal[i] = sta->chain_signal_last[i];
+ sinfo->chain_signal_avg[i] =
+ (s8) -ewma_read(&sta->chain_signal_avg[i]);
+ }
+ }

sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
sta_set_rate_info_rx(sta, &sinfo->rxrate);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4ffff07..ce33b56 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1372,6 +1372,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
struct sk_buff *skb = rx->skb;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ int i;

if (!sta)
return RX_CONTINUE;
@@ -1422,6 +1423,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
ewma_add(&sta->avg_signal, -status->signal);
}

+ if (status->chains) {
+ sta->chains = status->chains;
+ for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
+ int signal = status->chain_signal[i];
+
+ if (!(status->chains & BIT(i)))
+ continue;
+
+ sta->chain_signal_last[i] = signal;
+ ewma_add(&sta->chain_signal_avg[i], -signal);
+ }
+ }
+
/*
* Change STA power saving mode only at the end of a frame
* exchange sequence.
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 11216bc..a04c5671 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -358,6 +358,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
do_posix_clock_monotonic_gettime(&uptime);
sta->last_connected = uptime.tv_sec;
ewma_init(&sta->avg_signal, 1024, 8);
+ for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
+ ewma_init(&sta->chain_signal_avg[i], 1024, 8);

if (sta_prepare_rate_control(local, sta, gfp)) {
kfree(sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 876dd3f..fa1aa8a 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -342,6 +342,11 @@ struct sta_info {
int last_signal;
struct ewma avg_signal;
int last_ack_signal;
+
+ u8 chains;
+ s8 chain_signal_last[IEEE80211_MAX_CHAINS];
+ struct ewma chain_signal_avg[IEEE80211_MAX_CHAINS];
+
/* Plus 1 for non-QoS frames */
__le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];

--
1.8.0.2