2013-12-03 19:15:30

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 0/6] Enable additional channels for use

Sorry for the big delay between the previous series and this one ... seems
that I was too hasty with the previous one ... hope I did a better work this
time :)

As before, this series addresses the option of enabling additional channels for
use based on the following relaxations:

1. Indoor operation, where a device can use channels requiring indoor
operation, subject to that it can guarantee indoor operation.
2. Concurrent GO operation, where devices may instantiate a P2P GO
while they are under the guidance of an authorized master.

The series includes:

* Some clarification (mainly in documentation) about the intended usage of
channels marked as INDOOR_ONLY and CONCURRENT GO.
* Mapping of NL80211_RFF_NO_OUTDOOR to NL80211_CHAN_INDOOR_ONLY
* Support for a user hint that the platform is operating in an indoor
environment, i.e., channel marked as INDOOR_ONLY can be used.
* Allow initiating radiation on channel marked with INDOOR_ONLY also
for scanning an frame injection in monitor mode.
* Some additional fixes for comments I got.

Following is an example of a possible channel map that can be used to allow
the INDOOR_ONLY and CONCURRENT_GO relaxations. Note that:

* Channels 12,13 are marked as Concurrent GO, so even in the lack of exact
information about the current regulatory domain, these channels can be used
for GO instantiation based on the concurrent GO relaxation.
* The above is also true for channels 149-165 (a.k.a U-NII 3).
* Channels 36-48 (a.k.a thee U-NII 1), are marked both with Concurrent GO and
indoor only. While the Concurrent GO can be used as described above, the
indoor only setting allows to use these channels given the platform is
identified as an indoor one, i.e., media server.

2412 MHz [1] (16.0 dBm)
2417 MHz [2] (16.0 dBm)
2422 MHz [3] (16.0 dBm)
2427 MHz [4] (16.0 dBm)
2432 MHz [5] (16.0 dBm)
2437 MHz [6] (16.0 dBm)
2442 MHz [7] (16.0 dBm)
2447 MHz [8] (16.0 dBm)
2452 MHz [9] (16.0 dBm)
2457 MHz [10] (16.0 dBm)
2462 MHz [11] (16.0 dBm)
2467 MHz [12] (16.0 dBm) (no IR, Concurrent GO)
2472 MHz [13] (16.0 dBm) (no IR, Concurrent GO)
5180 MHz [36] (16.0 dBm) (no IR, Indoor Only, Concurrent GO)
5200 MHz [40] (16.0 dBm) (no IR, Indoor Only, Concurrent GO)
5220 MHz [44] (16.0 dBm) (no IR, Indoor Only, Concurrent GO)
5240 MHz [48] (16.0 dBm) (no IR, Indoor Only, Concurrent GO)
5260 MHz [52] (16.0 dBm) (no IR, radar detection)
5280 MHz [56] (16.0 dBm) (no IR, radar detection)
5300 MHz [60] (16.0 dBm) (no IR, radar detection)
5320 MHz [64] (16.0 dBm) (no IR, radar detection)
5500 MHz [100] (16.0 dBm) (no IR, radar detection)
5520 MHz [104] (16.0 dBm) (no IR, radar detection)
5540 MHz [108] (16.0 dBm) (no IR, radar detection)
5560 MHz [112] (16.0 dBm) (no IR, radar detection)
5580 MHz [116] (16.0 dBm) (no IR, radar detection)
5600 MHz [120] (16.0 dBm) (no IR, radar detection)
5620 MHz [124] (16.0 dBm) (no IR, radar detection)
5640 MHz [128] (16.0 dBm) (no IR, radar detection)
5660 MHz [132] (16.0 dBm) (no IR, radar detection)
5680 MHz [136] (16.0 dBm) (no IR, radar detection)
5700 MHz [140] (16.0 dBm) (no IR, radar detection)
5720 MHz [144] (16.0 dBm) (no IR, radar detection)
5745 MHz [149] (16.0 dBm) (no IR, Concurrent GO)
5765 MHz [153] (16.0 dBm) (no IR, Concurrent GO)
5785 MHz [157] (16.0 dBm) (no IR, Concurrent GO)
5805 MHz [161] (16.0 dBm) (no IR, Concurrent GO)
5825 MHz [165] (16.0 dBm) (no IR, Concurrent GO)

Thanks in advance,

Ilan.

David Spinadel (1):
cfg80211: Add indoor only and GO concurrent channel attributes

Ilan Peer (5):
cfg80211: Add Kconfig option for cellular BS hints
cfg80211: Enable GO operation on additional channels
cfg80211: Add an option to hint indoor operation
cfg80211: Enable GO operation on indoor channels
mac80211: Enable initiating radiation on indoor channels

include/net/cfg80211.h | 39 +++++++++++++++++++-
include/uapi/linux/nl80211.h | 10 +++++
net/mac80211/ibss.c | 9 +++--
net/mac80211/scan.c | 8 ++--
net/mac80211/tx.c | 2 +-
net/wireless/Kconfig | 16 ++++++++
net/wireless/chan.c | 73 +++++++++++++++++++++++++++++++++++--
net/wireless/mesh.c | 3 +-
net/wireless/nl80211.c | 35 +++++++++++-------
net/wireless/reg.c | 83 ++++++++++++++++++++++++++++++++++++++++--
net/wireless/reg.h | 13 +++++++
net/wireless/trace.h | 11 ++++--
12 files changed, 266 insertions(+), 36 deletions(-)

--
1.7.10.4



2013-12-05 13:56:50

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v3 3/6] cfg80211: Enable GO operation on additional channels

Allow GO operation on a channel marked with IEEE80211_CHAN_GO_CONCURRENT
iff there is an active station interface that is associated to
an AP operating on the same channel in 2.4 or the same UNII band in 5.2
(assuming that the AP is an authorized master)

Note that this is a permissive approach to the FCC definitions,
that require a clear assessment that the device operating the AP is
an authorized master, i.e., with radar detection and DFS capabilities.

It is assumed that such restrictions are enforced by user space.
Furthermore, it is assumed, that if the conditions that allowed for
the operation of the GO on such a channel change, i.e., the station
interface disconnected from the AP, it is the responsibility of user
space to evacuate the GO from the channel.

Signed-off-by: Ilan Peer <[email protected]>
---
include/net/cfg80211.h | 4 ++-
net/mac80211/ibss.c | 9 ++++---
net/wireless/Kconfig | 9 +++++++
net/wireless/chan.c | 63 +++++++++++++++++++++++++++++++++++++++++++++---
net/wireless/mesh.c | 3 ++-
net/wireless/nl80211.c | 11 ++++++---
net/wireless/reg.c | 22 +++++++++++++++++
net/wireless/reg.h | 12 +++++++++
net/wireless/trace.h | 11 ++++++---
9 files changed, 128 insertions(+), 16 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f4289db..504d656 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4297,12 +4297,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
* cfg80211_reg_can_beacon - check if beaconing is allowed
* @wiphy: the wiphy
* @chandef: the channel definition
+ * @iftype: interface type
*
* Return: %true if there is no secondary channel or the secondary channel(s)
* can be used for beaconing (i.e. is not a radar channel etc.)
*/
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef);
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype);

/*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 2eda7b1..9d5688d 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -263,7 +263,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
/* make a copy of the chandef, it could be modified below. */
chandef = *req_chandef;
chan = chandef.chan;
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
+ NL80211_IFTYPE_ADHOC)) {
if (chandef.width == NL80211_CHAN_WIDTH_5 ||
chandef.width == NL80211_CHAN_WIDTH_10 ||
chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
@@ -275,7 +276,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
chandef.width = NL80211_CHAN_WIDTH_20;
chandef.center_freq1 = chan->center_freq;
/* check again for downgraded chandef */
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
+ NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata,
"Failed to join IBSS, beacons forbidden\n");
return;
@@ -865,7 +867,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
goto disconnect;
}

- if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) {
+ if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
+ NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata,
"IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
ifibss->bssid,
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 81c05e4..f4012fc 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -102,6 +102,15 @@ config CFG80211_REG_CELLULAR_HINTS
This option adds support for drivers that can receive regulatory
hints from cellular base stations

+config CFG80211_REG_SOFT_CONFIGURATIONS
+ bool "cfg80211 support for GO operation on additional channels"
+ depends on CFG80211_CERTIFICATION_ONUS
+ ---help---
+ This option enables the operation of a P2P group owner on
+ additional channels, if there is an additional BSS interface
+ which is connected to an AP which is assumed to be an authorized
+ master, i.e., with radar detection support and DFS capabilities
+
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 78559b5..2c1b319 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -605,15 +605,72 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_chandef_usable);

+/* For GO only, check if the channel can be used under permissive conditions
+ * mandated by the some regulatory bodies, i.e., the channel is marked with
+ * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
+ * associated to an AP on the same channel or on the same UNII band
+ * (assuming that the AP is an authorized master).
+ */
+static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
+ struct ieee80211_channel *chan)
+{
+#ifdef CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS
+ struct wireless_dev *wdev_iter;
+
+ ASSERT_RTNL();
+
+ if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
+ return false;
+
+ list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+ struct ieee80211_channel *other_chan = NULL;
+
+ if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
+ !netif_running(wdev_iter->netdev))
+ continue;
+
+ wdev_lock(wdev_iter);
+ if (wdev_iter->current_bss)
+ other_chan = wdev_iter->current_bss->pub.channel;
+ wdev_unlock(wdev_iter);
+
+ if (!other_chan)
+ continue;
+
+ if (chan == other_chan) {
+ return true;
+ } else if (chan->band == IEEE80211_BAND_5GHZ) {
+ int r1 = cfg80211_get_unii(chan->center_freq);
+ int r2 = cfg80211_get_unii(other_chan->center_freq);
+
+ if (r1 != -EINVAL && r1 == r2)
+ return true;
+ }
+ }
+#endif /* CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS */
+
+ return false;
+}
+
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype)
{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
bool res;
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_RADAR;

- trace_cfg80211_reg_can_beacon(wiphy, chandef);
+ trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
+
+ /* Under certain conditions suggested by the some regulatory bodies
+ * a GO can operate on channels marked with IEEE80211_NO_IR
+ * so set this flag only if such relaxations are not enabled and
+ * the conditions are not met.
+ */
+ if (iftype != NL80211_IFTYPE_P2P_GO ||
+ !cfg80211_go_permissive_chan(rdev, chandef->chan))
+ prohibited_flags |= IEEE80211_CHAN_NO_IR;

if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
cfg80211_chandef_dfs_available(wiphy, chandef)) {
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index b0e1869..925c920 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -174,7 +174,8 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
scan_width);
}

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
+ NL80211_IFTYPE_MESH_POINT))
return -EINVAL;

err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 31bc8c7..267d37e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1870,7 +1870,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
result = -EBUSY;
break;
}
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) {
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
result = -EINVAL;
break;
}
@@ -3219,7 +3219,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
} else if (!nl80211_get_ap_channel(rdev, &params))
return -EINVAL;

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+ wdev->iftype))
return -EINVAL;

err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
@@ -5806,7 +5807,8 @@ skip_beacons:
if (err)
return err;

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+ wdev->iftype))
return -EINVAL;

if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
@@ -6577,7 +6579,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
+ NL80211_IFTYPE_ADHOC))
return -EINVAL;

switch (ibss.chandef.width) {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2449dce..212b5c2 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2460,6 +2460,28 @@ static void reg_timeout_work(struct work_struct *work)
rtnl_unlock();
}

+int cfg80211_get_unii(int freq)
+{
+ /* UNII-1 */
+ if (freq >= 5150 && freq <= 5250)
+ return 0;
+
+ /* UNII-2 */
+ if (freq > 5250 && freq <= 5350)
+ return 1;
+
+ /* UNII-2E */
+ if (freq >= 5470 && freq <= 5725)
+ return 2;
+
+ /* UNII-3 */
+ if (freq > 5725 && freq <= 5825)
+ return 3;
+
+ WARN_ON(1);
+ return -EINVAL;
+}
+
int __init regulatory_init(void)
{
int err = 0;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index cc4c2c0..1ef2daa 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -102,4 +102,16 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
*/
void regulatory_hint_disconnect(void);

+/**
+ * cfg80211_get_unii - get a value specifying the U-NII band the frequency
+ * belongs too.
+ * @freq: the frequency for which we want to get the UNII band.
+
+ * U-NII bands are defined by the FCC in C.F.R 47 part 15.
+ *
+ * Returns -EINVAL if freq is invalid, 1 for UNII-1, 2 for UNII-2,
+ * 3 for UNII-2e, 4 for UNII-3.
+ */
+int cfg80211_get_unii(int freq);
+
#endif /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index f7aa7a7..6687712 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2149,18 +2149,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
);

TRACE_EVENT(cfg80211_reg_can_beacon,
- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
- TP_ARGS(wiphy, chandef),
+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype),
+ TP_ARGS(wiphy, chandef, iftype),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_DEF_ENTRY
+ __field(enum nl80211_iftype, iftype)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
+ __entry->iftype = iftype;
),
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
);

TRACE_EVENT(cfg80211_chandef_dfs_required,
--
1.7.10.4


2013-12-03 19:15:33

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 4/6] cfg80211: Add an option to hint indoor operation

Add the option to hint the wireless core that it is operating in an indoor
environment.

In addition add regulatory_ir_allowed(), that can be used to
test if initiation radiation is allowed based on the channel flags
and the wireless core indoor hint.

Signed-off-by: Ilan Peer <[email protected]>
---
include/net/cfg80211.h | 12 +++++++++
include/uapi/linux/nl80211.h | 3 +++
net/wireless/nl80211.c | 18 ++++++-------
net/wireless/reg.c | 57 +++++++++++++++++++++++++++++++++++++++---
net/wireless/reg.h | 1 +
5 files changed, 78 insertions(+), 13 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 504d656..8c29b3d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3534,6 +3534,18 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
*/
const char *reg_initiator_name(enum nl80211_reg_initiator initiator);

+/**
+ * regulatory_ir_allowed - is it allowed to initiate radiation on the channel.
+ * @chan: the channel
+ *
+ * Generally, it is not allowed to initiate radiation on a channel marked with
+ * IEEE80211_CHAN_NO_IR. The exception is operation on channels marked with
+ * IEEE80211_CHAN_INDOOR_ONLY. For such channels, initiating radiation is
+ * allowed iff the wireless core was notified that it operates in an indoor
+ * environment.
+ */
+bool regulatory_ir_allowed(struct ieee80211_channel *chan);
+
/*
* callbacks for asynchronous cfg80211 methods, notification
* functions and BSS handling helpers
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b6721a1..6674444 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2489,10 +2489,13 @@ enum nl80211_dfs_regions {
* present has been registered with the wireless core that
* has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
* supported feature.
+ * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
+ * platform is operating in an indoor environment.
*/
enum nl80211_user_reg_hint_type {
NL80211_USER_REG_HINT_USER = 0,
NL80211_USER_REG_HINT_CELL_BASE = 1,
+ NL80211_USER_REG_HINT_INDOOR = 2,
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 267d37e..514170c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4614,7 +4614,6 @@ static int parse_reg_rule(struct nlattr *tb[],

static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
- int r;
char *data = NULL;
enum nl80211_user_reg_hint_type user_reg_hint_type;

@@ -4627,11 +4626,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
return -EINPROGRESS;

- if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
- return -EINVAL;
-
- data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
-
if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
user_reg_hint_type =
nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
@@ -4641,14 +4635,18 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
switch (user_reg_hint_type) {
case NL80211_USER_REG_HINT_USER:
case NL80211_USER_REG_HINT_CELL_BASE:
- break;
+ if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+ return -EINVAL;
+
+ data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+ return regulatory_hint_user(data, user_reg_hint_type);
+ case NL80211_USER_REG_HINT_INDOOR:
+ return regulatory_hint_indoor_user();
default:
return -EINVAL;
}

- r = regulatory_hint_user(data, user_reg_hint_type);
-
- return r;
+ return 0;
}

static int nl80211_get_mesh_config(struct sk_buff *skb,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 212b5c2..0361035 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -110,6 +110,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
*/
static int reg_num_devs_support_basehint;

+/*
+ * State variable indicating if the platform on which the devices
+ * are attached is operating in an indoor environment. The state variable
+ * is relevant for all registered devices.
+ * Note: currently not protected by any synchronization primitive.
+ */
+static bool reg_is_indoor;
+
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
return rtnl_dereference(cfg80211_regdomain);
@@ -987,6 +995,13 @@ static bool reg_request_cell_base(struct regulatory_request *request)
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
}

+static bool reg_request_indoor(struct regulatory_request *request)
+{
+ if (request->initiator != NL80211_REGDOM_SET_BY_USER)
+ return false;
+ return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
+}
+
bool reg_last_request_cell_base(void)
{
return reg_request_cell_base(get_last_request());
@@ -1423,6 +1438,9 @@ __reg_process_hint_user(struct regulatory_request *user_request)
{
struct regulatory_request *lr = get_last_request();

+ if (reg_request_indoor(user_request))
+ return REG_REQ_OK;
+
if (reg_request_cell_base(user_request))
return reg_ignore_cell_hint(user_request);

@@ -1475,6 +1493,11 @@ reg_process_hint_user(struct regulatory_request *user_request)
return treatment;
}

+ if (reg_request_indoor(user_request) && treatment == REG_REQ_OK) {
+ reg_is_indoor = true;
+ return REG_REQ_OK;
+ }
+
user_request->intersect = treatment == REG_REQ_INTERSECT;
user_request->processed = false;

@@ -1658,9 +1681,6 @@ static void reg_process_hint(struct regulatory_request *reg_request)
struct wiphy *wiphy = NULL;
enum reg_request_treatment treatment;

- if (WARN_ON(!reg_request->alpha2))
- return;
-
if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);

@@ -1820,6 +1840,22 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}

+int regulatory_hint_indoor_user(void)
+{
+ struct regulatory_request *request;
+
+ request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->wiphy_idx = WIPHY_IDX_INVALID;
+ request->initiator = NL80211_REGDOM_SET_BY_USER;
+ request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
+ queue_regulatory_request(request);
+
+ return 0;
+}
+
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
@@ -2482,6 +2518,19 @@ int cfg80211_get_unii(int freq)
return -EINVAL;
}

+bool regulatory_ir_allowed(struct ieee80211_channel *chan)
+{
+#ifdef CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS
+ if (reg_is_indoor && (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
+ return true;
+#endif /* CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS */
+
+ if (chan->flags & IEEE80211_CHAN_NO_IR)
+ return false;
+ return true;
+}
+EXPORT_SYMBOL(regulatory_ir_allowed);
+
int __init regulatory_init(void)
{
int err = 0;
@@ -2502,6 +2551,8 @@ int __init regulatory_init(void)
user_alpha2[0] = '9';
user_alpha2[1] = '7';

+ reg_is_indoor = false;
+
/* We always try to get an update for the static regdomain */
err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
if (err) {
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 1ef2daa..bd708d1 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -24,6 +24,7 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);

int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
+int regulatory_hint_indoor_user(void);

int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
void wiphy_regulatory_register(struct wiphy *wiphy);
--
1.7.10.4


2013-12-05 13:59:59

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v3 5/6] cfg80211: Enable GO operation on indoor channels

Allow GO operation on a channel marked with IEEE80211_CHAN_INDOOR_ONLY
iff there is a user hint indicating that the platform is operating in
an indoor environment, i.e., the platform is a printer or media center
device.

Signed-off-by: Ilan Peer <[email protected]>
---
net/wireless/chan.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 2c1b319..49fef2a 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -610,6 +610,8 @@ EXPORT_SYMBOL(cfg80211_chandef_usable);
* IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
* associated to an AP on the same channel or on the same UNII band
* (assuming that the AP is an authorized master).
+ * In addition allow the GO to operate on a channel on which indoor operation is
+ * allowed, iff we are currently operating in an indoor environment.
*/
static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan)
@@ -619,6 +621,9 @@ static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,

ASSERT_RTNL();

+ if (regulatory_ir_allowed(chan))
+ return true;
+
if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
return false;

--
1.7.10.4


2013-12-04 09:15:45

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v3 4/6] cfg80211: Add an option to hint indoor operation

Add the option to hint the wireless core that it is operating in an indoor
environment.

In addition add regulatory_ir_allowed(), that can be used to
test if initiation radiation is allowed based on the channel flags
and the wireless core indoor hint.

Signed-off-by: Ilan Peer <[email protected]>
---
include/net/cfg80211.h | 12 ++++++++++
include/uapi/linux/nl80211.h | 3 +++
net/wireless/nl80211.c | 18 +++++++-------
net/wireless/reg.c | 54 +++++++++++++++++++++++++++++++++++++++---
net/wireless/reg.h | 1 +
5 files changed, 75 insertions(+), 13 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 504d656..8c29b3d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3534,6 +3534,18 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
*/
const char *reg_initiator_name(enum nl80211_reg_initiator initiator);

+/**
+ * regulatory_ir_allowed - is it allowed to initiate radiation on the channel.
+ * @chan: the channel
+ *
+ * Generally, it is not allowed to initiate radiation on a channel marked with
+ * IEEE80211_CHAN_NO_IR. The exception is operation on channels marked with
+ * IEEE80211_CHAN_INDOOR_ONLY. For such channels, initiating radiation is
+ * allowed iff the wireless core was notified that it operates in an indoor
+ * environment.
+ */
+bool regulatory_ir_allowed(struct ieee80211_channel *chan);
+
/*
* callbacks for asynchronous cfg80211 methods, notification
* functions and BSS handling helpers
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b6721a1..6674444 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2489,10 +2489,13 @@ enum nl80211_dfs_regions {
* present has been registered with the wireless core that
* has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
* supported feature.
+ * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
+ * platform is operating in an indoor environment.
*/
enum nl80211_user_reg_hint_type {
NL80211_USER_REG_HINT_USER = 0,
NL80211_USER_REG_HINT_CELL_BASE = 1,
+ NL80211_USER_REG_HINT_INDOOR = 2,
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 267d37e..514170c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4614,7 +4614,6 @@ static int parse_reg_rule(struct nlattr *tb[],

static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
- int r;
char *data = NULL;
enum nl80211_user_reg_hint_type user_reg_hint_type;

@@ -4627,11 +4626,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
return -EINPROGRESS;

- if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
- return -EINVAL;
-
- data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
-
if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
user_reg_hint_type =
nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
@@ -4641,14 +4635,18 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
switch (user_reg_hint_type) {
case NL80211_USER_REG_HINT_USER:
case NL80211_USER_REG_HINT_CELL_BASE:
- break;
+ if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
+ return -EINVAL;
+
+ data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
+ return regulatory_hint_user(data, user_reg_hint_type);
+ case NL80211_USER_REG_HINT_INDOOR:
+ return regulatory_hint_indoor_user();
default:
return -EINVAL;
}

- r = regulatory_hint_user(data, user_reg_hint_type);
-
- return r;
+ return 0;
}

static int nl80211_get_mesh_config(struct sk_buff *skb,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 212b5c2..2ab1503 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -110,6 +110,14 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
*/
static int reg_num_devs_support_basehint;

+/*
+ * State variable indicating if the platform on which the devices
+ * are attached is operating in an indoor environment. The state variable
+ * is relevant for all registered devices.
+ * Note: currently not protected by any synchronization primitive.
+ */
+static bool reg_is_indoor;
+
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
return rtnl_dereference(cfg80211_regdomain);
@@ -987,6 +995,13 @@ static bool reg_request_cell_base(struct regulatory_request *request)
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
}

+static bool reg_request_indoor(struct regulatory_request *request)
+{
+ if (request->initiator != NL80211_REGDOM_SET_BY_USER)
+ return false;
+ return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
+}
+
bool reg_last_request_cell_base(void)
{
return reg_request_cell_base(get_last_request());
@@ -1423,6 +1438,11 @@ __reg_process_hint_user(struct regulatory_request *user_request)
{
struct regulatory_request *lr = get_last_request();

+ if (reg_request_indoor(user_request)) {
+ reg_is_indoor = true;
+ return REG_REQ_ALREADY_SET;
+ }
+
if (reg_request_cell_base(user_request))
return reg_ignore_cell_hint(user_request);

@@ -1658,9 +1678,6 @@ static void reg_process_hint(struct regulatory_request *reg_request)
struct wiphy *wiphy = NULL;
enum reg_request_treatment treatment;

- if (WARN_ON(!reg_request->alpha2))
- return;
-
if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);

@@ -1820,6 +1837,22 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}

+int regulatory_hint_indoor_user(void)
+{
+ struct regulatory_request *request;
+
+ request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->wiphy_idx = WIPHY_IDX_INVALID;
+ request->initiator = NL80211_REGDOM_SET_BY_USER;
+ request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
+ queue_regulatory_request(request);
+
+ return 0;
+}
+
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
@@ -2482,6 +2515,19 @@ int cfg80211_get_unii(int freq)
return -EINVAL;
}

+bool regulatory_ir_allowed(struct ieee80211_channel *chan)
+{
+#ifdef CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS
+ if (reg_is_indoor && (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
+ return true;
+#endif /* CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS */
+
+ if (chan->flags & IEEE80211_CHAN_NO_IR)
+ return false;
+ return true;
+}
+EXPORT_SYMBOL(regulatory_ir_allowed);
+
int __init regulatory_init(void)
{
int err = 0;
@@ -2502,6 +2548,8 @@ int __init regulatory_init(void)
user_alpha2[0] = '9';
user_alpha2[1] = '7';

+ reg_is_indoor = false;
+
/* We always try to get an update for the static regdomain */
err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
if (err) {
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 1ef2daa..bd708d1 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -24,6 +24,7 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);

int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
+int regulatory_hint_indoor_user(void);

int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
void wiphy_regulatory_register(struct wiphy *wiphy);
--
1.7.10.4


2013-12-03 19:15:32

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 3/6] cfg80211: Enable GO operation on additional channels

Allow GO operation on a channel marked with IEEE80211_CHAN_GO_CONCURRENT
iff there is an active station interface that is associated to
an AP operating on the same channel in 2.4 or the same UNII band in 5.2
(assuming that the AP is an authorized master)

Note that this is a permissive approach to the FCC definitions,
that require a clear assessment that the device operating the AP is
an authorized master, i.e., with radar detection and DFS capabilities.

It is assumed that such restrictions are enforced by user space.
Furthermore, it is assumed, that if the conditions that allowed for
the operation of the GO on such a channel change, i.e., the station
interface disconnected from the AP, it is the responsibility of user
space to evacuate the GO from the channel.

Signed-off-by: Ilan Peer <[email protected]>
---
include/net/cfg80211.h | 4 ++-
net/mac80211/ibss.c | 9 ++++---
net/wireless/Kconfig | 9 +++++++
net/wireless/chan.c | 68 +++++++++++++++++++++++++++++++++++++++++++++---
net/wireless/mesh.c | 3 ++-
net/wireless/nl80211.c | 11 +++++---
net/wireless/reg.c | 22 ++++++++++++++++
net/wireless/reg.h | 12 +++++++++
net/wireless/trace.h | 11 +++++---
9 files changed, 133 insertions(+), 16 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f4289db..504d656 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4297,12 +4297,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
* cfg80211_reg_can_beacon - check if beaconing is allowed
* @wiphy: the wiphy
* @chandef: the channel definition
+ * @iftype: interface type
*
* Return: %true if there is no secondary channel or the secondary channel(s)
* can be used for beaconing (i.e. is not a radar channel etc.)
*/
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef);
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype);

/*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 2eda7b1..9d5688d 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -263,7 +263,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
/* make a copy of the chandef, it could be modified below. */
chandef = *req_chandef;
chan = chandef.chan;
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
+ NL80211_IFTYPE_ADHOC)) {
if (chandef.width == NL80211_CHAN_WIDTH_5 ||
chandef.width == NL80211_CHAN_WIDTH_10 ||
chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
@@ -275,7 +276,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
chandef.width = NL80211_CHAN_WIDTH_20;
chandef.center_freq1 = chan->center_freq;
/* check again for downgraded chandef */
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+ if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
+ NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata,
"Failed to join IBSS, beacons forbidden\n");
return;
@@ -865,7 +867,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
goto disconnect;
}

- if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) {
+ if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
+ NL80211_IFTYPE_ADHOC)) {
sdata_info(sdata,
"IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
ifibss->bssid,
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 81c05e4..f4012fc 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -102,6 +102,15 @@ config CFG80211_REG_CELLULAR_HINTS
This option adds support for drivers that can receive regulatory
hints from cellular base stations

+config CFG80211_REG_SOFT_CONFIGURATIONS
+ bool "cfg80211 support for GO operation on additional channels"
+ depends on CFG80211_CERTIFICATION_ONUS
+ ---help---
+ This option enables the operation of a P2P group owner on
+ additional channels, if there is an additional BSS interface
+ which is connected to an AP which is assumed to be an authorized
+ master, i.e., with radar detection support and DFS capabilities
+
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 78559b5..d47856b 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -605,15 +605,77 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_chandef_usable);

+#ifdef CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS
+/* For GO only, check if the channel can be used under permissive conditions
+ * mandated by the some regulatory bodies, i.e., the channel is marked with
+ * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
+ * associated to an AP on the same channel or on the same UNII band
+ * (assuming that the AP is an authorized master).
+ */
+static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
+ struct ieee80211_channel *chan)
+{
+ struct wireless_dev *wdev_iter;
+
+ ASSERT_RTNL();
+
+ if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
+ return false;
+
+ list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+ struct ieee80211_channel *other_chan = NULL;
+
+ if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
+ !netif_running(wdev_iter->netdev))
+ continue;
+
+ wdev_lock(wdev_iter);
+ if (wdev_iter->current_bss)
+ other_chan = wdev_iter->current_bss->pub.channel;
+ wdev_unlock(wdev_iter);
+
+ if (!other_chan)
+ continue;
+
+ if (chan == other_chan) {
+ return true;
+ } else if (chan->band == IEEE80211_BAND_5GHZ) {
+ int r1 = cfg80211_get_unii(chan->center_freq);
+ int r2 = cfg80211_get_unii(other_chan->center_freq);
+
+ if (r1 != -EINVAL && r1 == r2)
+ return true;
+ }
+ }
+ return false;
+}
+#else
+static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
+ struct ieee80211_channel *chan)
+{
+ return false;
+}
+#endif /* CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS */
+
bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype)
{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
bool res;
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_RADAR;

- trace_cfg80211_reg_can_beacon(wiphy, chandef);
+ trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
+
+ /* Under certain conditions suggested by the some regulatory bodies
+ * a GO can operate on channels marked with IEEE80211_NO_IR
+ * so set this flag only if such relaxations are not enabled and
+ * the conditions are not met.
+ */
+ if (iftype != NL80211_IFTYPE_P2P_GO ||
+ !cfg80211_go_permissive_chan(rdev, chandef->chan))
+ prohibited_flags |= IEEE80211_CHAN_NO_IR;

if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
cfg80211_chandef_dfs_available(wiphy, chandef)) {
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index b0e1869..925c920 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -174,7 +174,8 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
scan_width);
}

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
+ NL80211_IFTYPE_MESH_POINT))
return -EINVAL;

err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 31bc8c7..267d37e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1870,7 +1870,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
result = -EBUSY;
break;
}
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) {
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
result = -EINVAL;
break;
}
@@ -3219,7 +3219,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
} else if (!nl80211_get_ap_channel(rdev, &params))
return -EINVAL;

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+ wdev->iftype))
return -EINVAL;

err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
@@ -5806,7 +5807,8 @@ skip_beacons:
if (err)
return err;

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+ wdev->iftype))
return -EINVAL;

if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
@@ -6577,7 +6579,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;

- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
+ if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
+ NL80211_IFTYPE_ADHOC))
return -EINVAL;

switch (ibss.chandef.width) {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2449dce..212b5c2 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2460,6 +2460,28 @@ static void reg_timeout_work(struct work_struct *work)
rtnl_unlock();
}

+int cfg80211_get_unii(int freq)
+{
+ /* UNII-1 */
+ if (freq >= 5150 && freq <= 5250)
+ return 0;
+
+ /* UNII-2 */
+ if (freq > 5250 && freq <= 5350)
+ return 1;
+
+ /* UNII-2E */
+ if (freq >= 5470 && freq <= 5725)
+ return 2;
+
+ /* UNII-3 */
+ if (freq > 5725 && freq <= 5825)
+ return 3;
+
+ WARN_ON(1);
+ return -EINVAL;
+}
+
int __init regulatory_init(void)
{
int err = 0;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index cc4c2c0..1ef2daa 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -102,4 +102,16 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
*/
void regulatory_hint_disconnect(void);

+/**
+ * cfg80211_get_unii - get a value specifying the U-NII band the frequency
+ * belongs too.
+ * @freq: the frequency for which we want to get the UNII band.
+
+ * U-NII bands are defined by the FCC in C.F.R 47 part 15.
+ *
+ * Returns -EINVAL if freq is invalid, 1 for UNII-1, 2 for UNII-2,
+ * 3 for UNII-2e, 4 for UNII-3.
+ */
+int cfg80211_get_unii(int freq);
+
#endif /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index f7aa7a7..6687712 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2149,18 +2149,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
);

TRACE_EVENT(cfg80211_reg_can_beacon,
- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
- TP_ARGS(wiphy, chandef),
+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype),
+ TP_ARGS(wiphy, chandef, iftype),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_DEF_ENTRY
+ __field(enum nl80211_iftype, iftype)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
+ __entry->iftype = iftype;
),
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
);

TRACE_EVENT(cfg80211_chandef_dfs_required,
--
1.7.10.4


2013-12-03 19:15:33

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 5/6] cfg80211: Enable GO operation on indoor channels

Signed-off-by: Ilan Peer <[email protected]>
---
net/wireless/chan.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index d47856b..36f2f5f 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -611,6 +611,8 @@ EXPORT_SYMBOL(cfg80211_chandef_usable);
* IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
* associated to an AP on the same channel or on the same UNII band
* (assuming that the AP is an authorized master).
+ * In addition allow the GO to operate on a channel on which indoor operation is
+ * allowed, iff we are currently operating in an indoor environment.
*/
static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan)
@@ -619,6 +621,9 @@ static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,

ASSERT_RTNL();

+ if (regulatory_ir_allowed(chan))
+ return true;
+
if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
return false;

--
1.7.10.4


2013-12-03 19:15:33

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 6/6] mac80211: Enable initiating radiation on indoor channels

Allow active scanning and frame injection on channels marked with
IEEE80211_CHAN_NO_IR iff the channel is also marked with
IEEE80211_CHAN_INDOOR_ONLY and the wireless core thinks that it
operates in an indoor environment.

Signed-off-by: Ilan Peer <[email protected]>
---
net/mac80211/scan.c | 8 +++-----
net/mac80211/tx.c | 2 +-
2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4d73c46..fd4f58a 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -525,8 +525,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
/* We need to ensure power level is at max for scanning. */
ieee80211_hw_config(local, 0);

- if ((req->channels[0]->flags &
- IEEE80211_CHAN_NO_IR) ||
+ if (!regulatory_ir_allowed(req->channels[0]) ||
!local->scan_req->n_ssids) {
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
} else {
@@ -572,7 +571,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
* TODO: channel switching also consumes quite some time,
* add that delay as well to get a better estimation
*/
- if (chan->flags & IEEE80211_CHAN_NO_IR)
+ if (!regulatory_ir_allowed(chan))
return IEEE80211_PASSIVE_CHANNEL_TIME;
return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
}
@@ -696,8 +695,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
*
* In any case, it is not necessary for a passive scan.
*/
- if (chan->flags & IEEE80211_CHAN_NO_IR ||
- !local->scan_req->n_ssids) {
+ if (!regulatory_ir_allowed(chan) || !local->scan_req->n_ssids) {
*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->next_scan_state = SCAN_DECISION;
return;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 6d59e21..596caa8 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1727,7 +1727,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
* radar detection by itself. We can do that later by adding a
* monitor flag interfaces used for AP support.
*/
- if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)))
+ if (!regulatory_ir_allowed(chan) || chan->flags & IEEE80211_CHAN_RADAR)
goto fail_rcu;

ieee80211_xmit(sdata, skb, chan->band);
--
1.7.10.4


2013-12-03 19:15:31

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 1/6] cfg80211: Add indoor only and GO concurrent channel attributes

From: David Spinadel <[email protected]>

The FCC are clarifying some soft configuration requirements,
which among other include the following:

1. Indoor operation, where a device can use channels requiring indoor
operation, subject to that it can guarantee indoor operation,
i.e., the device is connected to AC Power or the device is under
the control of a local master that is acting as an AP and is
connected to AC Power.
2. Concurrent GO operation, where devices may instantiate a P2P GO
while they are under the guidance of an authorized master. For example,
on a channel on which a BSS is connected to an authorized master, i.e.,
with DFS and radar detection capability in the UNII band.

See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122

Add support for advertising Indoor-only and GO-Concurrent channel
properties.

Signed-off-by: David Spinadel <[email protected]>
Signed-off-by: Ilan Peer <[email protected]>
---
include/net/cfg80211.h | 23 +++++++++++++++++++++++
include/uapi/linux/nl80211.h | 7 +++++++
net/wireless/nl80211.c | 6 ++++++
net/wireless/reg.c | 2 ++
4 files changed, 38 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e9abc7b..f4289db 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -109,6 +109,27 @@ enum ieee80211_band {
* channel as the control or any of the secondary channels.
* This may be due to the driver or due to regulatory bandwidth
* restrictions.
+ * @IEEE80211_CHAN_INDOOR_ONLY: Only indoor use is permitted on this channel.
+ * A channel marked with IEEE80211_CHAN_INDOOR_ONLY can only be used when
+ * there is a clear assessment that the device is operating in an indoor
+ * surroundings, i.e., it is connected to AC power (and not through
+ * portable DC inverters) or is under the control of a master that is
+ * acting as an AP and is connected to AC power.
+ * @IEEE80211_CHAN_GO_CONCURRENT: GO operation is allowed on this channel if
+ * it's connected concurrently to a BSS on the same channel on 2.4 or
+ * to a channel in the same UNII band on 5.2.
+ * Instantiating a GO on a channel marked with IEEE80211_CHAN_GO_CONCURRENT
+ * can be done when there is a clear assessment that the device is
+ * operating under the guidance of an authorized master, i.e., setting up a
+ * GO while the device is also connected to an AP with DFS and radar
+ * detection on the UNII band (however, this example does not imply that
+ * all channels marked with IEEE80211_CHAN_RADAR must also be marked with
+ * IEEE80211_CHAN_GO_CONCURRENT and vise versa).
+ *
+ * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
+ * for more information on the FCC description of the relaxations allowed
+ * by IEEE80211_CHAN_INDOOR_ONLY and IEEE80211_CHAN_GO_CONCURRENT.
+ *
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
@@ -120,6 +141,8 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_NO_OFDM = 1<<6,
IEEE80211_CHAN_NO_80MHZ = 1<<7,
IEEE80211_CHAN_NO_160MHZ = 1<<8,
+ IEEE80211_CHAN_INDOOR_ONLY = 1<<9,
+ IEEE80211_CHAN_GO_CONCURRENT = 1<<10,
};

#define IEEE80211_CHAN_NO_HT40 \
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 129b7b0..b6721a1 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2260,6 +2260,11 @@ enum nl80211_band_attr {
* @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
* using this channel as the primary or any of the secondary channels
* isn't possible
+ * @NL80211_FREQUENCY_ATTR_INDOOR_ONLY: Indoor only use is permitted
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
+ * channel if it's connected concurrently to a BSS on the same channel on
+ * 2.4 or to a channel in the same UNII band on 5.2.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -2278,6 +2283,8 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
NL80211_FREQUENCY_ATTR_NO_80MHZ,
NL80211_FREQUENCY_ATTR_NO_160MHZ,
+ NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
+ NL80211_FREQUENCY_ATTR_GO_CONCURRENT,

/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a693f86..31bc8c7 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -600,6 +600,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT))
+ goto nla_put_failure;
}

if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index ec54e1a..80fe9b3 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -749,6 +749,8 @@ static u32 map_regdom_flags(u32 rd_flags)
channel_flags |= IEEE80211_CHAN_RADAR;
if (rd_flags & NL80211_RRF_NO_OFDM)
channel_flags |= IEEE80211_CHAN_NO_OFDM;
+ if (rd_flags & NL80211_RRF_NO_OUTDOOR)
+ channel_flags |= IEEE80211_CHAN_INDOOR_ONLY;
return channel_flags;
}

--
1.7.10.4


2013-12-05 13:10:22

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 5/6] cfg80211: Enable GO operation on indoor channels

On Tue, 2013-12-03 at 21:16 +0200, Ilan Peer wrote:
> Signed-off-by: Ilan Peer <[email protected]>

Some commit log maybe? :)

johannes


2013-12-05 13:09:19

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 3/6] cfg80211: Enable GO operation on additional channels

On Tue, 2013-12-03 at 21:16 +0200, Ilan Peer wrote:

> +#ifdef CONFIG_CFG80211_REG_SOFT_CONFIGURATIONS
> +/* For GO only, check if the channel can be used under permissive conditions
> + * mandated by the some regulatory bodies, i.e., the channel is marked with
> + * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
> + * associated to an AP on the same channel or on the same UNII band
> + * (assuming that the AP is an authorized master).
> + */
> +static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
> + struct ieee80211_channel *chan)
> +{

Seems like you could move the ifdef here ...

> + struct wireless_dev *wdev_iter;
> +
> + ASSERT_RTNL();
> +
> + if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
> + return false;
> +
> + list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
> + struct ieee80211_channel *other_chan = NULL;
> +
> + if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
> + !netif_running(wdev_iter->netdev))
> + continue;
> +
> + wdev_lock(wdev_iter);
> + if (wdev_iter->current_bss)
> + other_chan = wdev_iter->current_bss->pub.channel;
> + wdev_unlock(wdev_iter);
> +
> + if (!other_chan)
> + continue;
> +
> + if (chan == other_chan) {
> + return true;
> + } else if (chan->band == IEEE80211_BAND_5GHZ) {
> + int r1 = cfg80211_get_unii(chan->center_freq);
> + int r2 = cfg80211_get_unii(other_chan->center_freq);
> +
> + if (r1 != -EINVAL && r1 == r2)
> + return true;
> + }
> + }

and here instead of duplicating the function prototype

> + return false;
> +}

johannes


2013-12-03 19:15:32

by Ilan Peer

[permalink] [raw]
Subject: [PATCH v2 2/6] cfg80211: Add Kconfig option for cellular BS hints

Move the regulatory cellular base station hints support under
a specific configuration option and make the option depend
on CFG80211_CERTIFICATION_ONUS.

Signed-off-by: Ilan Peer <[email protected]>
---
net/wireless/Kconfig | 7 +++++++
net/wireless/reg.c | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 16d08b3..81c05e4 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -95,6 +95,13 @@ config CFG80211_CERTIFICATION_ONUS
you are a wireless researcher and are working in a controlled
and approved environment by your local regulatory agency.

+config CFG80211_REG_CELLULAR_HINTS
+ bool "cfg80211 regulatory support for cellular base station hints"
+ depends on CFG80211_CERTIFICATION_ONUS
+ ---help---
+ This option adds support for drivers that can receive regulatory
+ hints from cellular base stations
+
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 80fe9b3..2449dce 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -992,7 +992,7 @@ bool reg_last_request_cell_base(void)
return reg_request_cell_base(get_last_request());
}

-#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
+#ifdef CONFIG_CFG80211_REG_CELLULAR_HINTS
/* Core specific check */
static enum reg_request_treatment
reg_ignore_cell_hint(struct regulatory_request *pending_request)
--
1.7.10.4


2014-01-26 22:22:05

by Ilan Peer

[permalink] [raw]
Subject: RE: [PATCH v2 3/6] cfg80211: Enable GO operation on additional channels

> -----Original Message-----
> From: Luis R. Rodriguez [mailto:[email protected]] On Behalf Of Luis R.
> Rodriguez
> Sent: Saturday, January 25, 2014 02:09
> To: Peer, Ilan
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH v2 3/6] cfg80211: Enable GO operation on additional
> channels
>
>
> <--
>
> > + wdev_lock(wdev_iter);
> > + if (wdev_iter->current_bss)
> > + other_chan = wdev_iter->current_bss-
> >pub.channel;
> > + wdev_unlock(wdev_iter);
>
> -->
>
> This is begging to be added as a helper.

Rethinking this ... currently this is not really used by other code paths other than the wext ones. Do u still want the helper function?

Ilan.