diff mbox

[1/2] cfg80211: Add support to set tx power for a station associated

Message ID 1465926256-6463-1-git-send-email-arnagara@qti.qualcomm.com (mailing list archive)
State Not Applicable
Delegated to: Kalle Valo
Headers show

Commit Message

Ashok Raj Nagarajan June 14, 2016, 5:44 p.m. UTC
This patch adds support to set transmit power setting type and transmit
power level attributes to NL80211_CMD_SET_STATION in order to facilitate
adjusting the transmit power level of a station associated to the AP.

The added attributes allow selection of automatic and limited transmit
power level, with the level defined in mBm format.

Signed-off-by: Ashok Raj Nagarajan <arnagara@qti.qualcomm.com>
---
 include/net/cfg80211.h       |  5 ++++
 include/uapi/linux/nl80211.h | 12 ++++++++++
 net/wireless/nl80211.c       | 54 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 71 insertions(+)

Comments

Johannes Berg June 28, 2016, 10:48 a.m. UTC | #1
On Tue, 2016-06-14 at 23:14 +0530, Ashok Raj Nagarajan wrote:
> This patch adds support to set transmit power setting type and
> transmit power level attributes to NL80211_CMD_SET_STATION in order
> to facilitate adjusting the transmit power level of a station
> associated to the AP.

Why would you ever need to do that manually? Please give more
explanation in the commit message.

We have minstrel-blues (which never made it into the code, but that's
just because the submitter went away) doing power adjustments, so you
need to explain why this should be necessary.

johannes
Ashok Raj Nagarajan July 5, 2016, 12:31 p.m. UTC | #2
On 2016-06-28 16:18, Johannes Berg wrote:
> On Tue, 2016-06-14 at 23:14 +0530, Ashok Raj Nagarajan wrote:
>> This patch adds support to set transmit power setting type and
>> transmit power level attributes to NL80211_CMD_SET_STATION in order
>> to facilitate adjusting the transmit power level of a station
>> associated to the AP.
> 
> Why would you ever need to do that manually? Please give more
> explanation in the commit message.
> 
> We have minstrel-blues (which never made it into the code, but that's
> just because the submitter went away) doing power adjustments, so you
> need to explain why this should be necessary.
> 

Hi Johannes,

Sure.. First use case will be to help with the problem of legacy client 
devices that
roam across multiple APs. It is a classic enterprise Wi-Fi AP problem, 
often
managed by a "network controller" unit that is connected to all the APs. 
The
problem is how to handle seamless handoff of clients between multiple 
APs while
maximizing the client throughput and minimizing disruption of IP 
application
services like VoIP calls and video streaming. A legacy client will often 
hold
onto an AP association, even down to 1 Mbps as it roams away. Instead, 
if the
AP can recognise that the client RSSI (and therefore throughput) is 
poor, it
can "drop" the Tx power significantly (just to that client) such that it 
forces
the client to look for a better, closer, and therefore higher-throughput
association. It would "give it a kick" without blacklisting it. It just 
needs
to hold the power low for the small amount of time it takes to convince 
it to
go away.

Other use cases may be
         - Support a form of QoS per STA since a higher MCS rate might be
           achievable, and CW delays might be reduced
         - The optimal power can be negotiated (closed loop) or observed 
(open
           loop) for a given STA, reducing needless congestion on the 
overall channel
         - Reduce power to a STA that does not support certain radio 
features
           (e.g.  11b clients)

Thanks,
Ashok

> johannes
Johannes Berg Aug. 1, 2016, 9:29 a.m. UTC | #3
> Sure.. First use case will be to help with the problem of legacy
> client devices that roam across multiple APs. It is a classic
> enterprise Wi-Fi AP problem,  often managed by a "network controller"
> unit that is connected to all the APs. 
> The problem is how to handle seamless handoff of clients between
> multiple  APs while maximizing the client throughput and minimizing
> disruption of IP application services like VoIP calls and video
> streaming. A legacy client will often  hold onto an AP association,
> even down to 1 Mbps as it roams away. Instead,  if the AP can
> recognise that the client RSSI (and therefore throughput) is poor, it
> can "drop" the Tx power significantly (just to that client) such that
> it forcesthe client to look for a better, closer, and therefore
> higher-throughputassociation. It would "give it a kick" without
> blacklisting it. It just needsto hold the power low for the small
> amount of time it takes to convince it to go away.

Not sure that *works* since implementations may just compare beacon
signal strength and hold on to the AP based on that, but it does seem
like a reasonable use case.

How would this interact with automatic adjustment though?

johannes
Ben Greear Aug. 1, 2016, 1:27 p.m. UTC | #4
On 08/01/2016 02:29 AM, Johannes Berg wrote:
>
>> Sure.. First use case will be to help with the problem of legacy
>> client devices that roam across multiple APs. It is a classic
>> enterprise Wi-Fi AP problem,  often managed by a "network controller"
>> unit that is connected to all the APs.
>> The problem is how to handle seamless handoff of clients between
>> multiple  APs while maximizing the client throughput and minimizing
>> disruption of IP application services like VoIP calls and video
>> streaming. A legacy client will often  hold onto an AP association,
>> even down to 1 Mbps as it roams away. Instead,  if the AP can
>> recognise that the client RSSI (and therefore throughput) is poor, it
>> can "drop" the Tx power significantly (just to that client) such that
>> it forcesthe client to look for a better, closer, and therefore
>> higher-throughputassociation. It would "give it a kick" without
>> blacklisting it. It just needsto hold the power low for the small
>> amount of time it takes to convince it to go away.
>
> Not sure that *works* since implementations may just compare beacon
> signal strength and hold on to the AP based on that, but it does seem
> like a reasonable use case.

How is that better than just kicking the station deliberately and/or
refusing to send frames to it at all?

Thanks,
Ben

>
> How would this interact with automatic adjustment though?
>
> johannes
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Ashok Raj Nagarajan Nov. 7, 2016, 2:10 p.m. UTC | #5
On 2016-08-01 18:57, Ben Greear wrote:
> On 08/01/2016 02:29 AM, Johannes Berg wrote:
>> 
>>> Sure.. First use case will be to help with the problem of legacy
>>> client devices that roam across multiple APs. It is a classic
>>> enterprise Wi-Fi AP problem,  often managed by a "network controller"
>>> unit that is connected to all the APs.
>>> The problem is how to handle seamless handoff of clients between
>>> multiple  APs while maximizing the client throughput and minimizing
>>> disruption of IP application services like VoIP calls and video
>>> streaming. A legacy client will often  hold onto an AP association,
>>> even down to 1 Mbps as it roams away. Instead,  if the AP can
>>> recognise that the client RSSI (and therefore throughput) is poor, it
>>> can "drop" the Tx power significantly (just to that client) such that
>>> it forcesthe client to look for a better, closer, and therefore
>>> higher-throughputassociation. It would "give it a kick" without
>>> blacklisting it. It just needsto hold the power low for the small
>>> amount of time it takes to convince it to go away.
>> 
>> Not sure that *works* since implementations may just compare beacon
>> signal strength and hold on to the AP based on that, but it does seem
>> like a reasonable use case.
> 
> How is that better than just kicking the station deliberately and/or
> refusing to send frames to it at all?
> 

Ben, deliberately kicking out the station can potentially cause the 
black
listing behaviour on the client side and results in connection failures. 
Each
client handles the kickout logic differently. Reducing the tx power, 
causes the
station to trigger its roaming algorithm.

>> 
>> How would this interact with automatic adjustment though?
>> 

Johannes,

In the case of manual intervention by user, the firmware will check 
three
values - regulatory domain, automatic tx power and user entered value. 
System
will always cap to the minimum of these values and see to that we do not 
exceed
the regulatory power limits.

If there are no more comments I will resent this patch series after 
rebase.

Thanks,
Ashok

>> johannes
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe 
>> linux-wireless" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
Ben Greear Nov. 7, 2016, 2:18 p.m. UTC | #6
On 11/07/2016 06:10 AM, Ashok Raj Nagarajan wrote:
> On 2016-08-01 18:57, Ben Greear wrote:
>> On 08/01/2016 02:29 AM, Johannes Berg wrote:
>>>
>>>> Sure.. First use case will be to help with the problem of legacy
>>>> client devices that roam across multiple APs. It is a classic
>>>> enterprise Wi-Fi AP problem,  often managed by a "network controller"
>>>> unit that is connected to all the APs.
>>>> The problem is how to handle seamless handoff of clients between
>>>> multiple  APs while maximizing the client throughput and minimizing
>>>> disruption of IP application services like VoIP calls and video
>>>> streaming. A legacy client will often  hold onto an AP association,
>>>> even down to 1 Mbps as it roams away. Instead,  if the AP can
>>>> recognise that the client RSSI (and therefore throughput) is poor, it
>>>> can "drop" the Tx power significantly (just to that client) such that
>>>> it forcesthe client to look for a better, closer, and therefore
>>>> higher-throughputassociation. It would "give it a kick" without
>>>> blacklisting it. It just needsto hold the power low for the small
>>>> amount of time it takes to convince it to go away.
>>>
>>> Not sure that *works* since implementations may just compare beacon
>>> signal strength and hold on to the AP based on that, but it does seem
>>> like a reasonable use case.
>>
>> How is that better than just kicking the station deliberately and/or
>> refusing to send frames to it at all?
>>
>
> Ben, deliberately kicking out the station can potentially cause the black
> listing behaviour on the client side and results in connection failures. Each
> client handles the kickout logic differently. Reducing the tx power, causes the
> station to trigger its roaming algorithm.

We tested some phones a year or so ago, and used a variable attenuator
to decrease the signal of one AP while ramping up signal of a second AP.
They did not roam until they lost connection, and since we were not using an isolation
chamber, we could not get the AP signal less than around -75 DB, so in our test,
the phones often did not roam at all.

http://www.candelatech.com/cookbook.php?vol=wifire&book=Emulating+Station+Motion+with+Programmable+Attenuator

So, I am not sure you can assume much about scanning behaviour either.  Maybe newer
phones are better...

Thanks,
Ben
Johannes Berg Nov. 15, 2016, 9:31 a.m. UTC | #7
> In the case of manual intervention by user, the firmware will check 
> three
> values - regulatory domain, automatic tx power and user entered
> value. 
> System
> will always cap to the minimum of these values and see to that we do
> not 
> exceed
> the regulatory power limits.

Fair enough.

> If there are no more comments I will resent this patch series after 
> rebase.

I suspect we should also have some kind of capability for all of this,
so it can be used reliably?

johannes
diff mbox

Patch

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6392167..4bf761d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -797,6 +797,10 @@  enum station_parameters_apply_mask {
  * @opmode_notif: operating mode field from Operating Mode Notification
  * @opmode_notif_used: information if operating mode field is used
  * @support_p2p_ps: information if station supports P2P PS mechanism
+ * @txpwr: tx power (in mBm) to be used for sending data traffic. If tx power
+ *	is not provided, the default per-interface tx power setting will be
+ *	overriding. Driver should be picking up the lowest tx power, either tx
+ *	power per-interface or per-station.
  */
 struct station_parameters {
 	const u8 *supported_rates;
@@ -823,6 +827,7 @@  struct station_parameters {
 	u8 opmode_notif;
 	bool opmode_notif_used;
 	int support_p2p_ps;
+	unsigned int txpwr;
 };
 
 /**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index e23d786..fe28006 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1819,6 +1819,15 @@  enum nl80211_commands {
  *
  * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
  *
+ * @NL80211_ATTR_STA_TX_POWER_SETTING: Transmit power setting type (u32) for
+ *	station associated with the AP. See &enum nl80211_tx_power_setting for
+ *	possible values.
+ * @NL80211_ATTR_STA_TX_POWER: Transmit power level (u32) in mBm units. This
+ *	allows to set Tx power for a station. If this attribute is not included,
+ *	the default per-interface tx power setting will be overriding. Driver
+ *	should be picking up the lowest tx power, either tx power per-interface
+ *	or per-station.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2201,6 +2210,9 @@  enum nl80211_attrs {
 
 	NL80211_ATTR_PAD,
 
+	NL80211_ATTR_STA_TX_POWER_SETTING,
+	NL80211_ATTR_STA_TX_POWER,
+
 	/* 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 d759901..0ef7377 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -257,6 +257,8 @@  static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 	[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
 					       .len = NL80211_MAX_SUPP_RATES },
 	[NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
+	[NL80211_ATTR_STA_TX_POWER_SETTING] = { .type = NLA_U32 },
+	[NL80211_ATTR_STA_TX_POWER] = { .type = NLA_U32 },
 	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
 	[NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
 	[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
@@ -4380,6 +4382,32 @@  static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 		params.local_pm = pm;
 	}
 
+	if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) {
+		enum nl80211_tx_power_setting type;
+		int idx;
+
+		if (!rdev->ops->set_tx_power)
+			return -EOPNOTSUPP;
+
+		idx = NL80211_ATTR_STA_TX_POWER_SETTING;
+		type = nla_get_u32(info->attrs[idx]);
+
+		if (!info->attrs[NL80211_ATTR_STA_TX_POWER] &&
+		    (type != NL80211_TX_POWER_AUTOMATIC))
+			return -EINVAL;
+
+		if (type != NL80211_TX_POWER_AUTOMATIC) {
+			if (type == NL80211_TX_POWER_LIMITED) {
+				idx = NL80211_ATTR_STA_TX_POWER;
+				params.txpwr = nla_get_u32(info->attrs[idx]);
+			} else {
+				return -EINVAL;
+			}
+		} else {
+			params.txpwr = 0;
+		}
+	}
+
 	/* Include parameters for TDLS peer (will check later) */
 	err = nl80211_set_station_tdls(info, &params);
 	if (err)
@@ -4507,6 +4535,32 @@  static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 			return -EINVAL;
 	}
 
+	if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) {
+		enum nl80211_tx_power_setting type;
+		int idx;
+
+		if (!rdev->ops->set_tx_power)
+			return -EOPNOTSUPP;
+
+		idx = NL80211_ATTR_STA_TX_POWER_SETTING;
+		type = nla_get_u32(info->attrs[idx]);
+
+		if (!info->attrs[NL80211_ATTR_STA_TX_POWER] &&
+		    (type != NL80211_TX_POWER_AUTOMATIC))
+			return -EINVAL;
+
+		if (type != NL80211_TX_POWER_AUTOMATIC) {
+			if (type == NL80211_TX_POWER_LIMITED) {
+				idx = NL80211_ATTR_STA_TX_POWER;
+				params.txpwr = nla_get_u32(info->attrs[idx]);
+			} else {
+				return -EINVAL;
+			}
+		} else {
+			params.txpwr = 0;
+		}
+	}
+
 	err = nl80211_parse_sta_channel_info(info, &params);
 	if (err)
 		return err;