This patch-set is a RFC of the ongoing work of adding main features of
the Intelligent Transport Systems (ITS) G5 standard into the Linux
kernel. ITS-G5 is the European version of the car2car DSRC wireless
communication protocol stack. It uses the OCB mode defined in IEEE
802.11p. To access the medium the so called DCC (Decentralized
Congestion Control Mechanism) is used -- that is slightly modified
combination of the 802.11e EDCA, Transmit Rate Control (TRC), Transmit
Datarate Control (TDC) and per packet Transmit Power Control (TPC).
The higher layer protocols are specific (different from the IEEE 1609
WAVE).
The ITS-G5 standards are freely available on-line. The ones describing
ITS-G5 PHY and MAC are ETSI EN 302 663 [1] and ETSI TS 102 687 [2].
[1] http://www.etsi.org/deliver/etsi_en/302600_302699/302663/01.02.01_60/en_302663v010201p.pdf
[2] http://www.etsi.org/deliver/etsi_ts/102600_102699/102687/01.01.01_60/ts_102687v010101p.pdf
This patch-set modifies mac80211 subsystem and ath9k driver to enable
setting of the OCB mode, setting channel type to 5 or 10 MHz and
setting frequency between 5850 and 5925 MHz. To make this fully
functional changes in CRDA (+wireless-regdb) and 'iw' tool are
necessary (these are not included in this patch-set).
The OCB (i.e. 'Out of Context of the BSS') is a special mode enabling
STAs communication without being associated to an AP or to each other.
The BSSID is set to all FF's. Every STA receives all frames from every
STA in range and transmits to every STA tuned to the same channel
(the motivation behind that is that there will be no time for
authentication/association when there are two cars going against each
other in high speed).
The main frequency used (for the Control Channel -- CCH) is set once
and stays fixed. No beacons are sent or received.
Summary of the first two patches (5/10 MHz channel setting):
* New channel TYPE flags are added -- i.e. NL80211_CHAN_WIDTH_5 and
NL80211_CHAN_WIDTH_10. The reason is to make it possible to
configure the ITS-G5 from user-space with commands like
sudo iw dev wlan0 set freq 5890 10MHZ
* New channel restricting flags are added -- the most important is the
one restricting the channel for OCB mode only (necessary for
frequency range 5850--5925)
* The commit fe7ef5e9ba0c60bab01390493a4c6790f7b093af has been
reverted to make the regd probing possible for 5/10 MHz channels
* Add frequencies ranging from 5850 to 5925 as supported in the ath9k
driver
The second two patches (adding the OCB mode) do the following:
* Add new 'interface mode' -- NL80211_IFTYPE_OCB
* Add new 'struct ieee80211_if_ocb' containing data specific for the
interface in the OCB mode
* Instead of modifying the ieee80211_set_wmm_default() add new
ieee80211_set_wmm_itsg5() with configuration specific for ITS-G5 --
This will be merged in single function in the future.
* Add the ieee80211_set_ocb_channel() function.
Since the 'set_channel()' function is not present anymore (the only
remnant is now in the 'set_monitor_channel()'), I was not able to
figure out how to set a fixed channel by user on interface
configuration (there is no 'ocb_join()' function), thus I am using the
deprecated '_oper_chandef' field in 'struct ieee80211_local *local'.
Any suggestions how to make it properly are very welcome.
* Modify __ieee80211_recalc_idle() to disable idle if the interface is
in the OCB mode (this will be probably unnecessary when the chanctx
will be used properly)
* The most important part is the initialization of the OCB mode in the
ieee80211_do_open() function
* Add ocb.c file containing the OCB specific functions -- i.e. add STA,
process management frame, do the housekeeping, setup sdata
* Modify the RX/TX path to be able to process frames when in the OCB
mode
Rostislav Lisovy (4):
mac80211: Allow 5/10 MHz channel setting (for OCB)
ath9k: Allow 5/10 MHz channel setting (for OCB)
mac80211: Add OCB (IEEE 802.11p) mode
ath9k: Add OCB (IEEE 802.11p) mode
drivers/net/wireless/ath/ath9k/ani.c | 1 +
drivers/net/wireless/ath/ath9k/ath9k.h | 1 +
drivers/net/wireless/ath/ath9k/debug.c | 4 +-
drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 +-
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 5 +
drivers/net/wireless/ath/ath9k/hw.c | 1 +
drivers/net/wireless/ath/ath9k/hw.h | 3 +-
drivers/net/wireless/ath/ath9k/init.c | 23 ++-
drivers/net/wireless/ath/ath9k/main.c | 5 +-
drivers/net/wireless/ath/ath9k/recv.c | 8 +-
drivers/net/wireless/ath/ath9k/xmit.c | 6 +
drivers/net/wireless/ath/regd.c | 11 +-
drivers/net/wireless/rtlwifi/regd.c | 9 +-
include/net/cfg80211.h | 21 ++-
include/net/mac80211.h | 4 +-
include/uapi/linux/nl80211.h | 24 ++-
net/mac80211/Kconfig | 11 ++
net/mac80211/Makefile | 3 +-
net/mac80211/cfg.c | 43 ++++-
net/mac80211/debug.h | 10 ++
net/mac80211/driver-ops.h | 3 +-
net/mac80211/ieee80211_i.h | 46 ++++++
net/mac80211/iface.c | 63 +++++++-
net/mac80211/main.c | 12 +-
net/mac80211/ocb.c | 219 ++++++++++++++++++++++++++
net/mac80211/rx.c | 30 ++++
net/mac80211/tx.c | 21 ++-
net/mac80211/util.c | 72 +++++++++
net/mac80211/wme.c | 4 +
net/wireless/chan.c | 27 +++-
net/wireless/core.c | 3 -
net/wireless/core.h | 4 +
net/wireless/nl80211.c | 18 +++
net/wireless/rdev-ops.h | 11 ++
net/wireless/reg.c | 117 ++++++++++++--
net/wireless/util.c | 7 +-
36 files changed, 805 insertions(+), 48 deletions(-)
create mode 100644 net/mac80211/ocb.c
--
1.8.5.1
Signed-off-by: Rostislav Lisovy <[email protected]>
---
include/net/cfg80211.h | 19 ++++++-
include/net/mac80211.h | 4 +-
include/uapi/linux/nl80211.h | 17 ++++++-
net/wireless/chan.c | 8 +++
net/wireless/core.c | 3 --
net/wireless/nl80211.c | 14 ++++++
net/wireless/reg.c | 115 ++++++++++++++++++++++++++++++++++++++-----
7 files changed, 161 insertions(+), 19 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3eae46c..14f8cc1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -110,6 +110,11 @@ 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_NO_20MHZ: 20 MHz bandwidth is not permitted
+ * on this channel.
+ * @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
+ * on this channel.
+ * @IEEE80211_CHAN_OCB_ONLY: only OCB is allowed on this channel.
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
@@ -121,6 +126,9 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_NO_OFDM = 1<<6,
IEEE80211_CHAN_NO_80MHZ = 1<<7,
IEEE80211_CHAN_NO_160MHZ = 1<<8,
+ IEEE80211_CHAN_NO_20MHZ = 1<<9,
+ IEEE80211_CHAN_NO_10MHZ = 1<<10,
+ IEEE80211_CHAN_OCB_ONLY = 1<<11,
};
#define IEEE80211_CHAN_NO_HT40 \
@@ -362,6 +370,10 @@ static inline enum nl80211_channel_type
cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef)
{
switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_5:
+ return NL80211_CHAN_5MHZ;
+ case NL80211_CHAN_WIDTH_10:
+ return NL80211_CHAN_10MHZ;
case NL80211_CHAN_WIDTH_20_NOHT:
return NL80211_CHAN_NO_HT;
case NL80211_CHAN_WIDTH_20:
@@ -3480,6 +3492,10 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
* freq_reg_info - get regulatory information for the given frequency
* @wiphy: the wiphy for which we want to process this rule for
* @center_freq: Frequency in KHz for which we want regulatory information for
+ * @desired_bw_khz: the desired max bandwidth you want to use per
+ * channel. Note that this is still 20 MHz if you want to use HT40
+ * as HT40 makes use of two channels for its 40 MHz width bandwidth.
+ * If set to 0 we'll assume you want the standard 20 MHz.
*
* Use this function to get the regulatory rule for a specific frequency on
* a given wireless device. If the device has a specific regulatory domain
@@ -3495,7 +3511,8 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
* purely subjective and right now it's 802.11 specific.
*/
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
- u32 center_freq);
+ u32 center_freq,
+ u32 desired_bw_khz);
/**
* reg_initiator_name - map regulatory request initiator enum to name
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 7ceed99..01c8a1f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -517,6 +517,8 @@ enum mac80211_tx_info_flags {
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
+ IEEE80211_TX_CTL_10MHZ = BIT(1),
+ IEEE80211_TX_CTL_5MHZ = BIT(2),
};
/*
@@ -4516,7 +4518,7 @@ conf_is_ht40(struct ieee80211_conf *conf)
static inline bool
conf_is_ht(struct ieee80211_conf *conf)
{
- return conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
+ return conf_is_ht20(conf) || conf_is_ht40(conf);
}
static inline enum nl80211_iftype
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f752e98..f2d3f67 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2246,6 +2246,14 @@ 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_NO_20MHZ: 20 MHz operation is not allowed
+ * on this channel in current regulatory domain.
+ * - this still allows 10 MHz and 5 MHz operation
+ * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
+ * on this channel in current regulatory domain.
+ * - this still allows 20 MHz and 5 MHz operation
+ * @NL80211_FREQUENCY_ATTR_OCB_ONLY: no other than OCB networks are
+ * permitted on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -2264,6 +2272,9 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
NL80211_FREQUENCY_ATTR_NO_80MHZ,
NL80211_FREQUENCY_ATTR_NO_160MHZ,
+ NL80211_FREQUENCY_ATTR_NO_20MHZ,
+ NL80211_FREQUENCY_ATTR_NO_10MHZ,
+ NL80211_FREQUENCY_ATTR_OCB_ONLY,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2822,12 +2833,16 @@ enum nl80211_ac {
* below the control channel
* @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
* above the control channel
+ * @NL80211_CHAN_5MHZ: normal, 5 MHz bandwidth
+ * @NL80211_CHAN_10MHZ: normal, 10 MHz bandwidth
*/
enum nl80211_channel_type {
NL80211_CHAN_NO_HT,
NL80211_CHAN_HT20,
NL80211_CHAN_HT40MINUS,
- NL80211_CHAN_HT40PLUS
+ NL80211_CHAN_HT40PLUS,
+ NL80211_CHAN_5MHZ,
+ NL80211_CHAN_10MHZ,
};
/**
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 9b8cc87..729a30c 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -22,6 +22,14 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
chandef->center_freq2 = 0;
switch (chan_type) {
+ case NL80211_CHAN_5MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_5;
+ chandef->center_freq1 = chan->center_freq;
+ break;
+ case NL80211_CHAN_10MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_10;
+ chandef->center_freq1 = chan->center_freq;
+ break;
case NL80211_CHAN_NO_HT:
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = chan->center_freq;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 52b865f..507e71f 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -451,9 +451,6 @@ int wiphy_register(struct wiphy *wiphy)
int i;
u16 ifmodes = wiphy->interface_modes;
- /* support for 5/10 MHz is broken due to nl80211 API mess - disable */
- wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
-
/*
* There are major locking problems in nl80211/mac80211 for CSA,
* disable for all drivers until this has been reworked.
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 138dc3b..a62d716 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -570,6 +570,16 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
+ goto nla_put_failure;
+
+ if ((chan->flags & IEEE80211_CHAN_OCB_ONLY) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_OCB_ONLY))
+ goto nla_put_failure;
if (chan->flags & IEEE80211_CHAN_RADAR) {
if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
goto nla_put_failure;
@@ -1800,6 +1810,8 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
switch (chantype) {
+ case NL80211_CHAN_5MHZ:
+ case NL80211_CHAN_10MHZ:
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
case NL80211_CHAN_HT40PLUS:
@@ -2195,6 +2207,8 @@ static int nl80211_send_chandef(struct sk_buff *msg,
chandef->chan->center_freq))
return -ENOBUFS;
switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_40:
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 7da67fd..992432c 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -710,13 +710,17 @@ static u32 map_regdom_flags(u32 rd_flags)
}
static const struct ieee80211_reg_rule *
-freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
+freq_reg_info_regd(struct wiphy *wiphy,
+ u32 center_freq, u32 desired_bw_khz,
const struct ieee80211_regdomain *regd)
{
int i;
bool band_rule_found = false;
bool bw_fits = false;
+ if (!desired_bw_khz)
+ desired_bw_khz = MHZ_TO_KHZ(20);
+
if (!regd)
return ERR_PTR(-EINVAL);
@@ -735,7 +739,16 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
if (!band_rule_found)
band_rule_found = freq_in_rule_band(fr, center_freq);
- bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
+ bw_fits = reg_does_bw_fit(fr, center_freq, desired_bw_khz);
+
+ if (band_rule_found && bw_fits) {
+ u32 allowed_bw = regd->reg_rules[i].freq_range.max_bandwidth_khz;
+ if (desired_bw_khz > allowed_bw) {
+ return ERR_PTR(-ENOENT);
+ } else {
+ return rr;
+ }
+ }
if (band_rule_found && bw_fits)
return rr;
@@ -748,7 +761,8 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
}
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
- u32 center_freq)
+ u32 center_freq,
+ u32 desired_bw_khz)
{
const struct ieee80211_regdomain *regd;
struct regulatory_request *lr = get_last_request();
@@ -764,7 +778,7 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
else
regd = get_cfg80211_regdom();
- return freq_reg_info_regd(wiphy, center_freq, regd);
+ return freq_reg_info_regd(wiphy, center_freq, desired_bw_khz, regd);
}
EXPORT_SYMBOL(freq_reg_info);
@@ -788,6 +802,7 @@ EXPORT_SYMBOL(reg_initiator_name);
#ifdef CONFIG_CFG80211_REG_DEBUG
static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
+ u32 desired_bw_khz,
const struct ieee80211_reg_rule *reg_rule)
{
const struct ieee80211_power_rule *power_rule;
@@ -802,8 +817,8 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
else
snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain);
- REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
- chan->center_freq);
+ REG_DBG_PRINT("Updating information on frequency %d MHz for a %d MHz width channel with regulatory rule:\n",
+ chan->center_freq, KHZ_TO_MHZ(desired_bw_khz));
REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n",
freq_range->start_freq_khz, freq_range->end_freq_khz,
@@ -812,6 +827,7 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
}
#else
static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
+ u32 desired_bw_khz,
const struct ieee80211_reg_rule *reg_rule)
{
return;
@@ -821,13 +837,18 @@ static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan,
/*
* Note that right now we assume the desired channel bandwidth
* is always 20 MHz for each individual channel (HT40 uses 20 MHz
- * per channel, the primary and the extension channel).
+ * per channel, the primary and the extension channel). To support
+ * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a
+ * new ieee80211_channel.target_bw and re run the regulatory check
+ * on the wiphy with the target_bw specified. Then we can simply use
+ * that below for the desired_bw_khz below.
*/
static void handle_channel(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ieee80211_channel *chan)
{
u32 flags, bw_flags = 0;
+ u32 desired_bw_khz = MHZ_TO_KHZ(20);
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
const struct ieee80211_freq_range *freq_range = NULL;
@@ -838,7 +859,33 @@ static void handle_channel(struct wiphy *wiphy,
flags = chan->orig_flags;
- reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
+ do {
+ reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), desired_bw_khz);
+ if ((IS_ERR(reg_rule)) && ((u32)reg_rule == -ENOENT)) {
+ bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+ } else {
+ break;
+ }
+
+ /* check for 10 MHz BW */
+ desired_bw_khz = MHZ_TO_KHZ(10);
+ reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), desired_bw_khz);
+ if ((IS_ERR(reg_rule)) && ((u32)reg_rule == -ENOENT)) {
+ bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+ } else {
+ break;
+ }
+
+ /* check for 5 MHz BW */
+ desired_bw_khz = MHZ_TO_KHZ(5);
+ reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), desired_bw_khz);
+ if ((IS_ERR(reg_rule)) && ((u32)reg_rule == -ENOENT)) {
+
+ } else {
+ break;
+ }
+ } while (0);
+
if (IS_ERR(reg_rule)) {
/*
* We will disable all channels that do not match our
@@ -859,11 +906,15 @@ static void handle_channel(struct wiphy *wiphy,
return;
}
- chan_reg_rule_print_dbg(chan, reg_rule);
+ chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule);
power_rule = ®_rule->power_rule;
freq_range = ®_rule->freq_range;
+ if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(10))
+ bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+ if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(20))
+ bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40;
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80))
@@ -871,9 +922,18 @@ static void handle_channel(struct wiphy *wiphy,
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160))
bw_flags |= IEEE80211_CHAN_NO_160MHZ;
+#if 0
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
request_wiphy && request_wiphy == wiphy &&
request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+#else
+ /*
+ * FIXME FIXME FIXME
+ * we always want to use the last requested reg domain
+ * do NOT use old values as a base
+ */
+ if (1) {
+#endif
/*
* This guarantees the driver's requested regulatory domain
* will always be used as a base for further regulatory
@@ -1253,25 +1313,54 @@ static void handle_channel_custom(struct wiphy *wiphy,
const struct ieee80211_regdomain *regd)
{
u32 bw_flags = 0;
+ u32 desired_bw_khz = MHZ_TO_KHZ(20);
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
const struct ieee80211_freq_range *freq_range = NULL;
reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
- regd);
+ desired_bw_khz, regd);
+
+ if ((IS_ERR(reg_rule)) && !(PTR_ERR(reg_rule) == -ERANGE &&
+ last_request->initiator ==
+ NL80211_REGDOM_SET_BY_COUNTRY_IE)) { /* FFIXME Wat? */
+ /*
+ * if 20 MHz BW is not ok apply further tests
+ * avoid catching the below exception (-ERANGE...) to exhibit
+ * exactly the same behaviour (not disable anything in this case)
+ * "bw_flags" have to be used to impose restrictions because "flags"
+ * is only applied in case of disabling the whole channel!
+ */
+ bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+
+ /* check for 10 MHz BW */
+ reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
+ MHZ_TO_KHZ(10), regd);
+ if (IS_ERR(reg_rule)) {
+ bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+ }
+
+ /* check for 5 MHz BW */
+ reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
+ MHZ_TO_KHZ(5), regd);
+ }
if (IS_ERR(reg_rule)) {
- REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
- chan->center_freq);
+ REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits a %d MHz wide channel\n",
+ chan->center_freq, KHZ_TO_MHZ(desired_bw_khz));
chan->flags = IEEE80211_CHAN_DISABLED;
return;
}
- chan_reg_rule_print_dbg(chan, reg_rule);
+ chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule);
power_rule = ®_rule->power_rule;
freq_range = ®_rule->freq_range;
+ if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(10))
+ bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+ if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(20))
+ bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags = IEEE80211_CHAN_NO_HT40;
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80))
--
1.8.5.1
Signed-off-by: Rostislav Lisovy <[email protected]>
---
include/net/cfg80211.h | 2 +
include/uapi/linux/nl80211.h | 7 +-
net/mac80211/Kconfig | 11 +++
net/mac80211/Makefile | 3 +-
net/mac80211/cfg.c | 43 ++++++++-
net/mac80211/debug.h | 10 ++
net/mac80211/driver-ops.h | 3 +-
net/mac80211/ieee80211_i.h | 46 +++++++++
net/mac80211/iface.c | 63 ++++++++++++-
net/mac80211/main.c | 12 ++-
net/mac80211/ocb.c | 219 +++++++++++++++++++++++++++++++++++++++++++
net/mac80211/rx.c | 30 ++++++
net/mac80211/tx.c | 21 ++++-
net/mac80211/util.c | 72 ++++++++++++++
net/mac80211/wme.c | 4 +
net/wireless/chan.c | 19 +++-
net/wireless/core.h | 4 +
net/wireless/nl80211.c | 4 +
net/wireless/rdev-ops.h | 11 +++
net/wireless/reg.c | 2 +
net/wireless/util.c | 7 +-
21 files changed, 578 insertions(+), 15 deletions(-)
create mode 100644 net/mac80211/ocb.c
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 14f8cc1..7f85547 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2285,6 +2285,8 @@ struct cfg80211_ops {
int (*set_monitor_channel)(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef);
+ int (*set_ocb_channel)(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef);
int (*scan)(struct wiphy *wiphy,
struct cfg80211_scan_request *request);
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f2d3f67..a78990e 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -852,7 +852,6 @@ enum nl80211_commands {
NL80211_CMD_SET_COALESCE,
NL80211_CMD_CHANNEL_SWITCH,
-
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1823,7 +1822,6 @@ enum nl80211_attrs {
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
NL80211_ATTR_HANDLE_DFS,
-
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1898,6 +1896,8 @@ enum nl80211_attrs {
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: outside context of a bss
+ * this mode corresponds to the MIB variable dot11OCBActivated=true
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
@@ -1917,6 +1917,7 @@ enum nl80211_iftype {
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,
+ NL80211_IFTYPE_OCB,
/* keep last */
NUM_NL80211_IFTYPES,
@@ -2426,6 +2427,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
* @NL80211_RRF_PASSIVE_SCAN: passive scan is required
* @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ * @NL80211_RRF_OCB_ONLY: no other than OCB is allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -2437,6 +2439,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_PTMP_ONLY = 1<<6,
NL80211_RRF_PASSIVE_SCAN = 1<<7,
NL80211_RRF_NO_IBSS = 1<<8,
+ NL80211_RRF_OCB_ONLY = 1<<11,
};
/**
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 97b5dca..c1d5d04 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -186,6 +186,17 @@ config MAC80211_HT_DEBUG
Do not select this option.
+config MAC80211_OCB_DEBUG
+ bool "Verbose OCB debugging"
+ depends on MAC80211_DEBUG_MENU
+ ---help---
+ Selecting this option causes mac80211 to print out
+ very verbose OCB debugging messages. It should not
+ be selected on production systems as those messages
+ are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_IBSS_DEBUG
bool "Verbose IBSS debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 9d7d840..aee99a7 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -25,7 +25,8 @@ mac80211-y := \
wme.o \
event.o \
chan.o \
- trace.o mlme.o
+ trace.o mlme.o \
+ ocb.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 364ce0c..13f69ee 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -806,6 +806,42 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
+/* Copied from ieee80211_set_monitor_channel */
+static int ieee80211_set_ocb_channel(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_sub_if_data *sdata;
+ int ret = 0;
+
+
+ mutex_lock(&local->iflist_mtx);
+ //if (local->use_chanctx) {
+ // sdata = rcu_dereference_protected(
+ // local->monitor_sdata,
+ // lockdep_is_held(&local->iflist_mtx));
+ // if (sdata) {
+ // ieee80211_vif_release_channel(sdata);
+ // ret = ieee80211_vif_use_channel(sdata, chandef,
+ // IEEE80211_CHANCTX_EXCLUSIVE);
+ // }
+ //} else if (local->open_count == local->monitors) {
+ // printk("%s: local->use_chanctx != TRUE\n", __func__);
+
+ /* FIXME
+ * I know this is wrong but how do I obtain the sdata?
+ */
+ local->_oper_chandef = *chandef;
+ ieee80211_hw_config(local, 0);
+ //}
+
+ //if (ret == 0)
+ // local->monitor_chandef = *chandef;
+ mutex_unlock(&local->iflist_mtx);
+
+ return ret;
+}
+
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
@@ -3771,9 +3807,11 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
if (chanctx_conf) {
*chandef = chanctx_conf->def;
ret = 0;
- } else if (local->open_count > 0 &&
+ } else if ((local->open_count > 0 &&
local->open_count == local->monitors &&
- sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ (sdata->vif.type == NL80211_IFTYPE_MONITOR))
+ || sdata->vif.type == NL80211_IFTYPE_OCB)
+ {
if (local->use_chanctx)
*chandef = local->monitor_chandef;
else
@@ -3826,6 +3864,7 @@ struct cfg80211_ops mac80211_config_ops = {
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
.set_monitor_channel = ieee80211_set_monitor_channel,
+ .set_ocb_channel = ieee80211_set_ocb_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 493d680..1956b31 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -2,6 +2,12 @@
#define __MAC80211_DEBUG_H
#include <net/cfg80211.h>
+#ifdef CONFIG_MAC80211_OCB_DEBUG
+#define MAC80211_OCB_DEBUG 1
+#else
+#define MAC80211_OCB_DEBUG 0
+#endif
+
#ifdef CONFIG_MAC80211_IBSS_DEBUG
#define MAC80211_IBSS_DEBUG 1
#else
@@ -131,6 +137,10 @@ do { \
_sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \
sdata, fmt, ##__VA_ARGS__)
+#define ocb_dbg(sdata, fmt, ...) \
+ _sdata_dbg(MAC80211_OCB_DEBUG, \
+ sdata, fmt, ##__VA_ARGS__)
+
#define ibss_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_IBSS_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 5d03c47..396d2ef 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -212,7 +212,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
BSS_CHANGED_BEACON_ENABLED) &&
sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_OCB))
return;
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4aea4e7..883ed31 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -527,6 +527,41 @@ struct ieee80211_if_ibss {
};
/**
+ * enum ocb_deferred_task_flags - mac80211 ocb deferred tasks
+ *
+ * @OCB_WORK_HOUSEKEEPING: run the periodic ocb housekeeping tasks
+ * - expire station that has not been seen for long
+ */
+enum ocb_deferred_task_flags {
+ OCB_WORK_HOUSEKEEPING,
+};
+
+/**
+ * struct ieee80211_if_ocb - the specific struct for ocb-mode
+ *
+ * In this struct all ocb-specific information of an interface is stored.
+ *
+ * @timer: the timer used for all tasks in the ocb-code
+ * @work: holds the workqueue
+ * @skb_queue: holds all queued skb to be processed
+ * @wrkq_flags: bitmask telling what work is pending
+ * @timer_running: tells if the timer is running (true = not running!?)
+ * @bssid: holds the bssid (normally IEEE802.11p defines this to be
+ * ff:ff:ff:ff:ff:ff - but this is more flexible)
+ */
+struct ieee80211_if_ocb {
+ struct timer_list timer;
+ struct work_struct work;
+
+ struct sk_buff_head skb_queue;
+
+ unsigned long wrkq_flags;
+
+ bool timer_running;
+ u8 bssid[ETH_ALEN];
+};
+
+/**
* struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface
*
* these declarations define the interface, which enables
@@ -771,6 +806,7 @@ struct ieee80211_sub_if_data {
struct ieee80211_if_managed mgd;
struct ieee80211_if_ibss ibss;
struct ieee80211_if_mesh mesh;
+ struct ieee80211_if_ocb ocb;
u32 mntr_flags;
} u;
@@ -963,6 +999,7 @@ struct ieee80211_local {
int open_count;
int monitors, cooked_mntrs;
+ int ocbs;
/* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
fif_probe_req;
@@ -1364,6 +1401,13 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
+/* OCB code */
+void ieee80211_ocb_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
+struct sta_info *ieee80211_ocb_add_sta(struct ieee80211_sub_if_data *sdata,
+ u8 *addr, u32 supp_rates);
+void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata);
+
/* mesh code */
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -1574,6 +1618,8 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
bool bss_notify);
+void ieee80211_set_wmm_itsg5(struct ieee80211_sub_if_data *sdata,
+ bool bss_notify);
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
enum ieee80211_band band);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index a075791..73ab0a6 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -109,7 +109,9 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local,
active = force_active ||
!list_empty(&local->chanctx_list) ||
- local->monitors;
+ local->monitors ||
+ local->ocbs;
+ printk(" ### %s: active: %d; local->ocbs: %d\n", __func__, active, local->ocbs);
if (!local->ops->remain_on_channel) {
list_for_each_entry(roc, &local->roc_list, list) {
@@ -261,6 +263,15 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(nsdata, &local->interfaces, list) {
if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
+ if ((sdata->vif.type == NL80211_IFTYPE_OCB
+ && nsdata->vif.type != NL80211_IFTYPE_MONITOR)
+ || (sdata->vif.type != NL80211_IFTYPE_MONITOR
+ && nsdata->vif.type == NL80211_IFTYPE_OCB))
+ {
+ ocb_dbg(sdata, "only ocb- and monitor-mode may coexist!\n");
+ return -EBUSY;
+ }
+
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
@@ -508,6 +519,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_DEVICE:
+ case NL80211_IFTYPE_OCB:
/* no special treatment */
break;
case NL80211_IFTYPE_UNSPECIFIED:
@@ -611,6 +623,32 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE)
changed |= ieee80211_reset_erp_info(sdata);
+
+ if (sdata->vif.type == NL80211_IFTYPE_OCB) {
+ local->ocbs++;
+
+ /* Disable beacons */
+ sdata->vif.bss_conf.enable_beacon = false;
+ changed |= BSS_CHANGED_BEACON;
+
+ /*
+ * Disable idle -- when chanctx will be used,
+ * this will be unnecessary
+ */
+ sdata->vif.bss_conf.idle = false;
+ changed |= BSS_CHANGED_IDLE;
+
+ /* Receive all data frames */
+ local->fif_other_bss++;
+ ieee80211_configure_filter(local);
+
+ mutex_lock(&local->mtx);
+ ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
+
+ netif_carrier_on(dev);
+ }
+
ieee80211_bss_info_change_notify(sdata, changed);
switch (sdata->vif.type) {
@@ -620,6 +658,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_MESH_POINT:
netif_carrier_off(dev);
break;
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_P2P_DEVICE:
break;
@@ -633,7 +672,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
* need to initialise the hardware if the hardware
* doesn't start up with sane defaults
*/
- ieee80211_set_wmm_default(sdata, true);
+ if (sdata->vif.type == NL80211_IFTYPE_OCB) {
+ sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+ ieee80211_set_wmm_itsg5(sdata, true);
+ } else {
+ ieee80211_set_wmm_default(sdata, true);
+ }
}
set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -878,6 +922,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_adjust_monitor_flags(sdata, -1);
break;
+ case NL80211_IFTYPE_OCB:
+ local->ocbs--;
+ if (local->ocbs == 0) {
+ /* Do some cleaning */
+ }
+ break;
case NL80211_IFTYPE_P2P_DEVICE:
/* relies on synchronize_rcu() below */
rcu_assign_pointer(local->p2p_sdata, NULL);
@@ -1222,6 +1272,9 @@ static void ieee80211_iface_work(struct work_struct *work)
break;
ieee80211_mesh_rx_queued_mgmt(sdata, skb);
break;
+ case NL80211_IFTYPE_OCB:
+ ieee80211_ocb_rx_queued_mgmt(sdata, skb);
+ break;
default:
WARN(1, "frame for unexpected interface type");
break;
@@ -1309,6 +1362,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
ieee80211_sta_setup_sdata(sdata);
break;
+ case NL80211_IFTYPE_OCB:
+ ieee80211_ocb_setup_sdata(sdata);
+ sdata->vif.bss_conf.bssid = sdata->u.ocb.bssid;
+ break;
case NL80211_IFTYPE_ADHOC:
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
ieee80211_ibss_setup_sdata(sdata);
@@ -1356,6 +1413,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_OCB:
/*
* Could maybe also all others here?
* Just not sure how that interacts
@@ -1371,6 +1429,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_OCB:
/*
* Could probably support everything
* but WDS here (WDS do_open can fail
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 7d1c3ac..13c026e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -954,14 +954,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_rate;
}
+ /* add one default OCB interface if supported */
+ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_OCB)) {
+ result = ieee80211_if_add(local, "wlan%d", NULL,
+ NL80211_IFTYPE_OCB, NULL);
/* add one default STA interface if supported */
- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
+ } else if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
result = ieee80211_if_add(local, "wlan%d", NULL,
NL80211_IFTYPE_STATION, NULL);
- if (result)
- wiphy_warn(local->hw.wiphy,
- "Failed to add default virtual iface\n");
}
+ if (result)
+ wiphy_warn(local->hw.wiphy, "Failed to add default virtual iface\n");
+
rtnl_unlock();
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
new file mode 100644
index 0000000..4e2aaee
--- /dev/null
+++ b/net/mac80211/ocb.c
@@ -0,0 +1,219 @@
+/*
+ * OCB mode implementation
+ * Copyright 2009, Robert Budde <[email protected]>
+ * Copyright 2014, Czech Technical University in Prague, Rostislav Lisovy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "driver-ops.h"
+#include "rate.h"
+
+#define IEEE80211_OCB_HOUSEKEEPING_INTERVAL (10 * HZ)
+#define IEEE80211_OCB_PEER_INACTIVITY_LIMIT (60 * HZ)
+#define IEEE80211_OCB_MAX_STA_ENTRIES 128
+
+/**
+ * ieee80211_ocb_add_sta - Adds a new OCB station
+ *
+ * @sdata: The &struct ieee80211_sub_if_data containing the interface data
+ * @addr: The stations mac-address
+ * @supp_rates: The supported rates of that station encoded in a bitmask
+ *
+ * This function adds a new OCB station to the station list. It is called by
+ * the mac80211 rx code whenever a new station appears (a frame is received).
+ *
+ * Returns: A pointer to the new station record.
+ */
+struct sta_info *ieee80211_ocb_add_sta(struct ieee80211_sub_if_data *sdata,
+ u8 *addr, u32 supp_rates)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_supported_band *sband;
+ enum nl80211_bss_scan_width scan_width;
+ struct sta_info *sta;
+ int band;
+
+ /*
+ * XXX: Consider removing the least recently used entry and
+ * allow new one to be added.
+ */
+ if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) {
+ //if (net_ratelimit())
+ ocb_dbg(sdata, "No room for a new OCB STA entry %pM\n",
+ addr);
+ return NULL;
+ }
+
+ ocb_dbg(sdata, "Adding new OCB station %pM\n", addr);
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (!chanctx_conf) {
+ band = local->_oper_chandef.chan->band;
+ scan_width = local->_oper_chandef.width;
+ } else {
+ band = chanctx_conf->def.chan->band;
+ scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
+ }
+ rcu_read_unlock();
+
+ sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+ if (!sta)
+ return NULL;
+
+ sta->last_rx = jiffies;
+
+ /* FIXME
+ * We are skipping some states thus we cannot use
+ * sta_info_move_state_checked() --
+ * in this case set_sta_flag will invoke WARN_ON
+ */
+ set_sta_flag(sta, WLAN_STA_AUTHORIZED);
+
+ /* make sure mandatory rates are always added */
+ sband = local->hw.wiphy->bands[band];
+ sta->sta.supp_rates[band] = supp_rates |
+ ieee80211_mandatory_rates(sband, scan_width);
+ rate_control_rate_init(sta);
+
+ /* If it fails, maybe we raced another insertion? */
+ if (sta_info_insert(sta))
+ return sta_info_get(sdata, addr);
+ return sta;
+}
+
+/* This might be unnecessary at all */
+void ieee80211_ocb_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status;
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ rx_status = IEEE80211_SKB_RXCB(skb);
+ mgmt = (struct ieee80211_mgmt *)skb->data;
+ fc = le16_to_cpu(mgmt->frame_control);
+
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ ocb_dbg(sdata, "recv mgmt-frame of subtype ACTION\n");
+ break;
+ default:
+ ocb_dbg(sdata, "recv mgmt-frame of unknown subtype\n");
+ break;
+ }
+}
+
+/**
+ * ieee80211_ocb_housekeeping - Housekeeping function (expires stations)
+ *
+ * @sdata:
+ * @ifocb:
+ *
+ * This function is used for all periodical clean up work.
+ * It expires all stations that have not shown up for a given period of time.
+ * After all cleanups have been done it schedules the next run.
+ */
+static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_ocb *ifocb)
+{
+ ocb_dbg(sdata, "running ocb housekeeping\n");
+
+ ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT);
+
+ mod_timer(&ifocb->timer,
+ round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL));
+}
+
+/**
+ * ieee80211_ocb_work - Workqueue function
+ *
+ * @work:
+ *
+ * This function is called once the interface is started and periodically
+ * by the timer function when the timer expires.
+ * It checks whether the interface is suspended, running, scanning and of
+ * the right type. After all queued skbs have been processed it checks what
+ * tasks are to be done and calls the corresponding functions.
+ */
+static void ieee80211_ocb_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, u.ocb.work);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+
+ if (WARN_ON(local->suspended))
+ return;
+
+ if (!netif_running(sdata->dev))
+ return;
+
+ if (local->scanning)
+ return;
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_OCB))
+ return;
+
+ if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags))
+ ieee80211_ocb_housekeeping(sdata, ifocb);
+}
+
+/**
+ * ieee80211_ocb_timer - Timer function called when the timer expires
+ *
+ * @data:
+ *
+ * This function is called everytime the timer expires (periodically)
+ * To make sure the housekeeping is done it sets the corresponding bit and
+ * then calls the workqueue.
+ */
+static void ieee80211_ocb_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata = (void *)data;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+ if (local->quiescing) {
+ ifocb->timer_running = true;
+ return;
+ }
+
+ set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
+ ieee80211_queue_work(&local->hw, &ifocb->work);
+}
+
+/**
+ * ieee80211_ocb_setup_sdata - Setups all the interface data
+ *
+ * @sdata:
+ *
+ * This needs to be called before the interface is brought up.
+ */
+void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+ /* Wildcard BSSID */
+ memset(ifocb->bssid, 0xff, ETH_ALEN);
+
+ INIT_WORK(&ifocb->work, ieee80211_ocb_work);
+ setup_timer(&ifocb->timer, ieee80211_ocb_timer,
+ (unsigned long) sdata);
+ skb_queue_head_init(&ifocb->skb_queue);
+}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2b0debb..9375c6e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1022,6 +1022,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
ieee80211_is_pspoll(hdr->frame_control)) &&
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
+ rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
/*
* accept port control frames from the AP even when it's not
@@ -1251,6 +1252,11 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->last_rx_rate_vht_nss = status->vht_nss;
}
}
+ } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
+ u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
+ NL80211_IFTYPE_OCB);
+ if (ieee80211_bssid_match(bssid, rx->sdata->u.ocb.bssid))
+ sta->last_rx = jiffies;
} else if (!is_multicast_ether_addr(hdr->addr1)) {
/*
* Mesh beacons will update last_rx when if they are found to
@@ -2789,6 +2795,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_OCB &&
sdata->vif.type != NL80211_IFTYPE_STATION)
return RX_DROP_MONITOR;
@@ -3099,6 +3106,29 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
BIT(rate_idx));
}
break;
+ case NL80211_IFTYPE_OCB:
+ if (!bssid)
+ return 0;
+ if (ieee80211_is_beacon(hdr->frame_control)) {
+ return 0;
+ } else if (!ieee80211_bssid_match(bssid, sdata->u.ocb.bssid)) {
+ ocb_dbg(sdata, "BSSID mismatch in OCB -mode!\n");
+ return 0;
+ } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
+ // if we are in promisc mode we also accept packets not destined for us
+ if (!(sdata->dev->flags & IFF_PROMISC))
+ return 0;
+ rx->flags &= ~IEEE80211_RX_RA_MATCH;
+ } else if (!rx->sta) {
+ int rate_idx;
+ if (status->flag & RX_FLAG_HT)
+ rate_idx = 0; /* TODO: HT rates */
+ else
+ rate_idx = status->rate_idx;
+ rx->sta = ieee80211_ocb_add_sta(sdata, hdr->addr2,
+ BIT(rate_idx));
+ }
+ break;
case NL80211_IFTYPE_MESH_POINT:
if (!multicast &&
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ca7fa7f..3344382 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -293,6 +293,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
*/
return TX_DROP;
+ if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
+ return TX_CONTINUE;
+
if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
return TX_CONTINUE;
@@ -1728,7 +1731,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
* monitor flag interfaces used for AP support.
*/
if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
- IEEE80211_CHAN_PASSIVE_SCAN)))
+ IEEE80211_CHAN_PASSIVE_SCAN))
+ && (!(chan->flags & (IEEE80211_CHAN_OCB_ONLY))))
goto fail_rcu;
ieee80211_xmit(sdata, skb, chan->band);
@@ -1970,6 +1974,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
goto fail_rcu;
band = chanctx_conf->def.chan->band;
break;
+ case NL80211_IFTYPE_OCB:
+ /* DA SA BSSID */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memset(hdr.addr3, 0xff, ETH_ALEN);
+ hdrlen = 24;
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ if (!chanctx_conf) {
+ //goto fail_rcu;
+ band = local->_oper_chandef.chan->band;
+ } else {
+ band = chanctx_conf->def.chan->band;
+ }
+ break;
case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -2014,6 +2032,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
* EAPOL frames from the local station.
*/
if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
+ (sdata->vif.type != NL80211_IFTYPE_OCB) &&
!multicast && !authorized &&
(cpu_to_be16(ethertype) != sdata->control_port_protocol ||
!ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9f9b9bd..3b34385 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -991,6 +991,9 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
if (!local->ops->conf_tx)
return;
+ /* this function should never be used in ocb-mode */
+ BUG_ON(sdata->vif.type == NL80211_IFTYPE_OCB);
+
if (local->hw.queues < IEEE80211_NUM_ACS)
return;
@@ -1077,6 +1080,71 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
}
}
+/**
+ * ieee80211_set_wmm_itsg5 - sets up the WMM queue parameters for ITS-G5
+ *
+ * Sets up the WMM queue parameters for each queue according to ITS-G5.
+ *
+ * @sdata:
+ * @bss_notify:
+ */
+void ieee80211_set_wmm_itsg5(struct ieee80211_sub_if_data *sdata, bool bss_notify)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_queue_params qparam;
+ int ac;
+ int aCWmin, aCWmax;
+
+ if (!local->ops->conf_tx)
+ return;
+
+ ocb_dbg(sdata, "setting wmm-params up for ocb-mode\n");
+
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ return;
+
+ memset(&qparam, 0, sizeof(qparam));
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ /* Set defaults according to 802.11-2007 Table 7-37 and 802.11p 7-37a */
+ aCWmax = 1023;
+ aCWmin = 15;
+
+ switch (ac) {
+ case IEEE80211_AC_BK:
+ qparam.cw_min = aCWmin;
+ qparam.cw_max = aCWmax;
+ qparam.aifs = 9;
+ qparam.txop = 0;
+ break;
+ case IEEE80211_AC_BE:
+ qparam.cw_min = aCWmin;
+ qparam.cw_max = aCWmax;
+ qparam.aifs = 6;
+ qparam.txop = 0;
+ break;
+ case IEEE80211_AC_VI:
+ qparam.cw_min = (aCWmin + 1) / 2 - 1;
+ qparam.cw_max = aCWmin;
+ qparam.aifs = 3;
+ qparam.txop = 0;
+ break;
+ case IEEE80211_AC_VO:
+ qparam.cw_min = (aCWmin + 1) / 4 - 1;
+ qparam.cw_max = (aCWmin + 1) / 2 - 1;
+ qparam.aifs = 2;
+ qparam.txop = 0;
+ break;
+ }
+
+ sdata->tx_conf[ac] = qparam;
+ drv_conf_tx(local, sdata, ac, &qparam);
+ }
+ sdata->vif.bss_conf.qos = true;
+ if (bss_notify)
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+}
+
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *da,
@@ -1614,6 +1682,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
ieee80211_bss_info_change_notify(sdata, changed);
sdata_unlock(sdata);
break;
+ case NL80211_IFTYPE_OCB:
+ changed |= BSS_CHANGED_IBSS | BSS_CHANGED_BEACON_ENABLED;
+ ieee80211_bss_info_change_notify(sdata, changed);
+ break;
case NL80211_IFTYPE_ADHOC:
changed |= BSS_CHANGED_IBSS;
/* fall through */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index afba19c..ab3e970 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -137,6 +137,10 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_ADHOC:
ra = skb->data;
break;
+ case NL80211_IFTYPE_OCB:
+ /* all stations are required to support WME */
+ qos = true;
+ break;
default:
break;
}
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 729a30c..8c325f4 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -477,13 +477,29 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_PASSIVE_SCAN |
IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR);
+ IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_OCB_ONLY);
+ /* Is this correct?
+ * IEEE80211_CHAN_OCB_ONLY flag prohibited
+ * when enabling beacons
+ */
trace_cfg80211_return_bool(res);
return res;
}
EXPORT_SYMBOL(cfg80211_reg_can_beacon);
+int cfg80211_set_ocb_channel(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef)
+{
+ if (!rdev->ops->set_ocb_channel)
+ return -EOPNOTSUPP;
+
+
+ return rdev_set_ocb_channel(rdev, chandef);
+}
+
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef)
{
@@ -542,6 +558,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
*chanmode = CHAN_MODE_SHARED;
}
return;
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_WDS:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index af10e59..873ebf8 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -436,6 +436,10 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef);
+int cfg80211_set_ocb_channel(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_chan_def *chandef);
+
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
u32 *mask);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a62d716..d4e1431 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1777,6 +1777,7 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
* operation to set the monitor channel if possible.
*/
return !wdev ||
+ wdev->iftype == NL80211_IFTYPE_OCB ||
wdev->iftype == NL80211_IFTYPE_AP ||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
wdev->iftype == NL80211_IFTYPE_MONITOR ||
@@ -1888,6 +1889,9 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MONITOR:
result = cfg80211_set_monitor_channel(rdev, &chandef);
break;
+ case NL80211_IFTYPE_OCB:
+ result = cfg80211_set_ocb_channel(rdev, wdev, &chandef);
+ break;
default:
result = -EINVAL;
}
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 37ce9fd..eeb963e 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -359,6 +359,17 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev,
}
static inline int
+rdev_set_ocb_channel(struct cfg80211_registered_device *rdev,
+ struct cfg80211_chan_def *chandef)
+{
+ int ret;
+ //trace_rdev_set_ocb_channel(&rdev->wiphy, chandef);
+ ret = rdev->ops->set_ocb_channel(&rdev->wiphy, chandef);
+ //trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int
rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef)
{
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 992432c..48fb075 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -706,6 +706,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_OCB_ONLY)
+ channel_flags |= IEEE80211_CHAN_OCB_ONLY;
return channel_flags;
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 935dea9..7bb5bf8 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -440,7 +440,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
break;
case cpu_to_le16(0):
if (iftype != NL80211_IFTYPE_ADHOC &&
- iftype != NL80211_IFTYPE_STATION)
+ iftype != NL80211_IFTYPE_STATION &&
+ iftype != NL80211_IFTYPE_OCB)
return -1;
break;
}
@@ -516,6 +517,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
memcpy(hdr.addr3, skb->data, ETH_ALEN);
hdrlen = 24;
break;
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -902,6 +904,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
if (dev->ieee80211_ptr->use_4addr)
break;
/* fall through */
+ case NL80211_IFTYPE_OCB:
+ /* fall through */
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_ADHOC:
dev->priv_flags |= IFF_DONT_BRIDGE;
@@ -1274,6 +1278,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
}
radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
break;
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_DEVICE:
--
1.8.5.1
Signed-off-by: Rostislav Lisovy <[email protected]>
---
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 5 +++++
drivers/net/wireless/ath/ath9k/hw.h | 3 ++-
drivers/net/wireless/ath/ath9k/init.c | 20 ++++++++++++++++++++
drivers/net/wireless/ath/ath9k/recv.c | 6 ++++++
drivers/net/wireless/ath/ath9k/xmit.c | 6 ++++++
drivers/net/wireless/ath/regd.c | 9 ++++++---
drivers/net/wireless/rtlwifi/regd.c | 9 ++++++---
7 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index c028df7..348864e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -1095,6 +1095,11 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
rx_status->antenna = rxbuf->rxstatus.rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_END;
+ if (IS_CHAN_HALF_RATE(priv->ah->curchan))
+ rx_status->flag |= RX_FLAG_10MHZ;
+ else if (IS_CHAN_QUARTER_RATE(priv->ah->curchan))
+ rx_status->flag |= RX_FLAG_5MHZ;
+
return true;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index a2c9a5d..88e44c7 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -69,7 +69,7 @@
#define ATH9K_RSSI_BAD -128
-#define ATH9K_NUM_CHANNELS 38
+#define ATH9K_NUM_CHANNELS 54
/* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) \
@@ -422,6 +422,7 @@ struct ath9k_channel {
#define IS_CHAN_HALF_RATE(_c) (!!((_c)->channelFlags & CHANNEL_HALF))
#define IS_CHAN_QUARTER_RATE(_c) (!!((_c)->channelFlags & CHANNEL_QUARTER))
+
#define IS_CHAN_A_FAST_CLOCK(_ah, _c) \
(IS_CHAN_5GHZ(_c) && ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK))
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 710192e..7bad46f 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -128,6 +128,26 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
CHAN5G(5785, 35), /* Channel 157 */
CHAN5G(5805, 36), /* Channel 161 */
CHAN5G(5825, 37), /* Channel 165 */
+
+ CHAN5G(5850, 38), /* Channel 170 */
+ /* ITA-G5B */
+ CHAN5G(5855, 39), /* Channel 171 */
+ CHAN5G(5860, 40), /* Channel 172 */
+ CHAN5G(5865, 41), /* Channel 173 */
+ CHAN5G(5870, 42), /* Channel 174 */
+ /* ITS-G5A */
+ CHAN5G(5875, 43), /* Channel 175 */
+ CHAN5G(5880, 44), /* Channel 176 */
+ CHAN5G(5885, 45), /* Channel 177 */
+ CHAN5G(5890, 46), /* Channel 178 */
+ CHAN5G(5895, 47), /* Channel 179 */
+ CHAN5G(5900, 48), /* Channel 180 */
+ CHAN5G(5905, 49), /* Channel 181 */
+ /* ITS-G5D */
+ CHAN5G(5910, 50), /* Channel 182 */
+ CHAN5G(5915, 51), /* Channel 183 */
+ CHAN5G(5920, 52), /* Channel 184 */
+ CHAN5G(5925, 53), /* Channel 185 */
};
/* Atheros hardware rate code addition for short premble */
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 95ddca5..ea8d15d 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1435,6 +1435,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
retval = ath9k_rx_skb_preprocess(sc, hdr_skb, &rs, rxs,
&decrypt_error, tsf);
+
+ if (IS_CHAN_HALF_RATE(ah->curchan))
+ rxs->flag |= RX_FLAG_10MHZ;
+ else if (IS_CHAN_QUARTER_RATE(ah->curchan))
+ rxs->flag |= RX_FLAG_5MHZ;
+
if (retval)
goto requeue_drop_frag;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b5a19e0..7770f4a 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2335,6 +2335,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ if (IS_CHAN_HALF_RATE(sc->sc_ah->curchan))
+ tx_info->flags |= IEEE80211_TX_CTL_10MHZ;
+ else if (IS_CHAN_QUARTER_RATE(sc->sc_ah->curchan))
+ tx_info->flags |= IEEE80211_TX_CTL_5MHZ;
+
+
padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len>padpos+padsize) {
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 1217c52..9a7b934 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -195,6 +195,7 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
+ u32 bandwidth = 0;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
@@ -212,7 +213,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq,
+ bandwidth);
if (IS_ERR(reg_rule))
continue;
/*
@@ -249,6 +251,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
+ u32 bandwidth = 0;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
@@ -276,7 +279,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq, bandwidth);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
@@ -284,7 +287,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
}
ch = &sband->channels[12]; /* CH 13 */
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq, bandwidth);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index d7d0d49..89836b0 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -158,6 +158,7 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
+ u32 bandwidth = 0;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
@@ -172,7 +173,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
(ch->flags & IEEE80211_CHAN_RADAR))
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq,
+ bandwidth);
if (IS_ERR(reg_rule))
continue;
@@ -208,6 +210,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
+ u32 bandwidth = 0;
if (!wiphy->bands[IEEE80211_BAND_2GHZ])
return;
@@ -235,7 +238,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq, bandwidth);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
@@ -243,7 +246,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
}
ch = &sband->channels[12]; /* CH 13 */
- reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ reg_rule = freq_reg_info(wiphy, ch->center_freq, bandwidth);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
--
1.8.5.1
Dear Johannes;
Thank you for your feedback.
On Mon, 2014-02-17 at 14:49 +0100, Johannes Berg wrote:
> On Mon, 2014-02-17 at 14:22 +0100, Rostislav Lisovy wrote:
> > Signed-off-by: Rostislav Lisovy <[email protected]>
>
> Err, some text is definitely needed.
>
> > ---
> > include/net/cfg80211.h | 19 ++++++-
> > include/net/mac80211.h | 4 +-
> > include/uapi/linux/nl80211.h | 17 ++++++-
> > net/wireless/chan.c | 8 +++
> > net/wireless/core.c | 3 --
> > net/wireless/nl80211.c | 14 ++++++
> > net/wireless/reg.c | 115 ++++++++++++++++++++++++++++++++++++++-----
> > 7 files changed, 161 insertions(+), 19 deletions(-)
>
> Umm.
>
> Might have mentioned that in your 0/4 that you want help on specific
> things :)
>
> [I haven't even really reviewed the regulatory code]
As you have already noticed, this is work in progress. I agree it is
necessary to keep the code clean if I want others to read it -- I try to
do so but it does not always go very well.
One thing I am not sure about (mentioned in 0/4) and need some
suggestions is frequency setting in the OCB mode.
Since there are no beacons containing the information about the
frequency to set, the frequency is set manually. Since the
'set_channel()' function is not present anymore (and we do not have
'ocb_join()' function, thus we cannot use 'preset_chandef'), I was not
able to figure out how to set a fixed channel.
If I would want to set the frequency with the
ieee80211_vif_use_channel() function, I would need to somehow obtain the
*sdata. If I check ieee80211_set_monitor_channel() I see how *sdata is
obtained there, but I am not sure if it is a good idea to add *ocb_sdata
to struct ieee80211_local?
Best regards;
Rostislav Lisovy
Signed-off-by: Rostislav Lisovy <[email protected]>
---
drivers/net/wireless/ath/ath9k/ani.c | 1 +
drivers/net/wireless/ath/ath9k/ath9k.h | 1 +
drivers/net/wireless/ath/ath9k/debug.c | 4 ++--
drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 ++-
drivers/net/wireless/ath/ath9k/hw.c | 1 +
drivers/net/wireless/ath/ath9k/init.c | 3 ++-
drivers/net/wireless/ath/ath9k/main.c | 5 ++++-
drivers/net/wireless/ath/ath9k/recv.c | 2 +-
drivers/net/wireless/ath/regd.c | 2 +-
9 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index d28923b..72820fd 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -326,6 +326,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
if (is_scanning ||
(ah->opmode != NL80211_IFTYPE_STATION &&
+ ah->opmode != NL80211_IFTYPE_OCB &&
ah->opmode != NL80211_IFTYPE_ADHOC)) {
/*
* If we're scanning or in AP mode, the defaults (ini)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 60a5da5..1528661 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -685,6 +685,7 @@ struct ath9k_vif_iter_data {
int nstations; /* number of station vifs */
int nwds; /* number of WDS vifs */
int nadhocs; /* number of adhoc vifs */
+ int nocbs; /* number of OCB vifs */
};
/* enum spectral_mode:
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 83a2c59..9ef53fe 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -788,9 +788,9 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
len += scnprintf(buf + len, sizeof(buf) - len,
"VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
- " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
+ " ADHOC: %i OCB: %i TOTAL: %hi BEACON-VIF: %hi\n",
iter_data.naps, iter_data.nstations, iter_data.nmeshes,
- iter_data.nwds, iter_data.nadhocs,
+ iter_data.nwds, iter_data.nadhocs, iter_data.nocbs,
sc->nvifs, sc->nbcnvifs);
if (len > sizeof(buf))
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index c3676bf..6822b60 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -737,7 +737,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_MESH_POINT);
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_OCB);
hw->wiphy->iface_combinations = &if_comb;
hw->wiphy->n_iface_combinations = 1;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8918035..3ee2787 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1245,6 +1245,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
u32 set = AR_STA_ID1_KSRCH_MODE;
switch (opmode) {
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_ADHOC:
set |= AR_STA_ID1_ADHOC;
REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 7bad46f..b9f7529 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -938,7 +938,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_WDS) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_MESH_POINT);
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_OCB);
hw->wiphy->iface_combinations = if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 21aa09e..072764f 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -929,6 +929,7 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
case NL80211_IFTYPE_STATION:
iter_data->nstations++;
break;
+ case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_ADHOC:
iter_data->nadhocs++;
break;
@@ -1006,6 +1007,8 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
if (iter_data.nmeshes)
ah->opmode = NL80211_IFTYPE_MESH_POINT;
+ else if (iter_data.nocbs)
+ ah->opmode = NL80211_IFTYPE_OCB;
else if (iter_data.nwds)
ah->opmode = NL80211_IFTYPE_AP;
else if (iter_data.nadhocs)
@@ -1016,7 +1019,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
ath9k_hw_setopmode(ah);
- if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
+ if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes + iter_data.nocbs) > 0)
ah->imask |= ATH9K_INT_TSFOOR;
else
ah->imask &= ~ATH9K_INT_TSFOOR;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ea8d15d..c6c716e 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -403,7 +403,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
(sc->nvifs <= 1) &&
!(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
- else
+ else if (sc->sc_ah->opmode != NL80211_IFTYPE_OCB)
rfilt |= ATH9K_RX_FILTER_BEACON;
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 9a7b934..ae82221 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -612,7 +612,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
const struct ieee80211_regdomain *regd;
wiphy->reg_notifier = reg_notifier;
- wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+ /* wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; */
if (ath_is_world_regd(reg)) {
/*
--
1.8.5.1
On Mon, 2014-02-17 at 14:22 +0100, Rostislav Lisovy wrote:
> Signed-off-by: Rostislav Lisovy <[email protected]>
Err, some text is definitely needed.
> ---
> include/net/cfg80211.h | 19 ++++++-
> include/net/mac80211.h | 4 +-
> include/uapi/linux/nl80211.h | 17 ++++++-
> net/wireless/chan.c | 8 +++
> net/wireless/core.c | 3 --
> net/wireless/nl80211.c | 14 ++++++
> net/wireless/reg.c | 115 ++++++++++++++++++++++++++++++++++++++-----
> 7 files changed, 161 insertions(+), 19 deletions(-)
This is mostly a cfg80211 patch - please remove the non-cfg80211 parts
from this one and label it appropriately.
> + * @IEEE80211_CHAN_NO_20MHZ: 20 MHz bandwidth is not permitted
> + * on this channel.
> + * @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
> + * on this channel.
> + * @IEEE80211_CHAN_OCB_ONLY: only OCB is allowed on this channel.
That's not very clear - does no-20 also imply no-higher-than-20? Also,
why no flag for 5MHz? Maybe there should be flags for _5MHZ_ONLY,
_10MHZ_ONLY and _OCB_ONLY?
> +++ b/include/net/mac80211.h
> @@ -517,6 +517,8 @@ enum mac80211_tx_info_flags {
> */
> enum mac80211_tx_control_flags {
> IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
> + IEEE80211_TX_CTL_10MHZ = BIT(1),
> + IEEE80211_TX_CTL_5MHZ = BIT(2),
> };
This doesn't belong here.
> @@ -4516,7 +4518,7 @@ conf_is_ht40(struct ieee80211_conf *conf)
> static inline bool
> conf_is_ht(struct ieee80211_conf *conf)
> {
> - return conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
> + return conf_is_ht20(conf) || conf_is_ht40(conf);
> }
This also doesn't, but is also wrong - consider VHT.
> +++ b/net/wireless/core.c
> @@ -451,9 +451,6 @@ int wiphy_register(struct wiphy *wiphy)
> int i;
> u16 ifmodes = wiphy->interface_modes;
>
> - /* support for 5/10 MHz is broken due to nl80211 API mess - disable */
> - wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
Err, what tree are you basing your code on? Consider updating it.
Besides, that wouldn't even belong into this patch anyway.
> +++ b/net/wireless/nl80211.c
> @@ -570,6 +570,16 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
> if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
> nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
> goto nla_put_failure;
> + if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
> + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
> + goto nla_put_failure;
> + if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
> + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
> + goto nla_put_failure;
> +
> + if ((chan->flags & IEEE80211_CHAN_OCB_ONLY) &&
> + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_OCB_ONLY))
> + goto nla_put_failure;
This has to depend on the split format here, otherwise we overrun the
buffer used by older userspace tools. Also, such channels should be
removed from the nl80211 advertisement for userspace that can't cope
with non-split information.
> + if (band_rule_found && bw_fits) {
> + u32 allowed_bw = regd->reg_rules[i].freq_range.max_bandwidth_khz;
> + if (desired_bw_khz > allowed_bw) {
> + return ERR_PTR(-ENOENT);
> + } else {
> + return rr;
> + }
> + }
code style
> const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
> - u32 center_freq)
> + u32 center_freq,
> + u32 desired_bw_khz)
> EXPORT_SYMBOL(freq_reg_info);
This function is exported but you haven't updated any of its users ...
> + do {
> + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), desired_bw_khz);
> + if ((IS_ERR(reg_rule)) && ((u32)reg_rule == -ENOENT)) {
> + bw_flags |= IEEE80211_CHAN_NO_20MHZ;
> + } else {
> + break;
> + }
> +
> + /* check for 10 MHz BW */
> + desired_bw_khz = MHZ_TO_KHZ(10);
> + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), desired_bw_khz);
> + if ((IS_ERR(reg_rule)) && ((u32)reg_rule == -ENOENT)) {
> + bw_flags |= IEEE80211_CHAN_NO_10MHZ;
> + } else {
> + break;
> + }
> +
> + /* check for 5 MHz BW */
> + desired_bw_khz = MHZ_TO_KHZ(5);
> + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), desired_bw_khz);
> + if ((IS_ERR(reg_rule)) && ((u32)reg_rule == -ENOENT)) {
> +
> + } else {
> + break;
> + }
> + } while (0);
That is one of the ugliest code constructs I've ever seen. You should
rewrite it.
> +#if 0
Umm.
Might have mentioned that in your 0/4 that you want help on specific
things :)
[I haven't even really reviewed the regulatory code]
johannes
On Mon, 2014-02-17 at 14:22 +0100, Rostislav Lisovy wrote:
> Signed-off-by: Rostislav Lisovy <[email protected]>
No description, lots of FIXMEs, lots of // comments, again a mashup of
cfg80211 and mac80211 changes ... I'll just stop looking right now.
johannes
On Mon, 2014-02-17 at 16:49 +0100, Rostislav Lisovy wrote:
> As you have already noticed, this is work in progress. I agree it is
> necessary to keep the code clean if I want others to read it -- I try to
> do so but it does not always go very well.
:-)
> One thing I am not sure about (mentioned in 0/4) and need some
> suggestions is frequency setting in the OCB mode.
> Since there are no beacons containing the information about the
> frequency to set, the frequency is set manually. Since the
> 'set_channel()' function is not present anymore (and we do not have
> 'ocb_join()' function, thus we cannot use 'preset_chandef'), I was not
> able to figure out how to set a fixed channel.
I don't really see why you didn't add an obc_join() method. I know that
it's not strictly a BSS concept, but still there should be *some*
indication that you want to participate in the OBC now, so you should
still have something like obc_join() that starts everything.
> If I would want to set the frequency with the
> ieee80211_vif_use_channel() function, I would need to somehow obtain the
> *sdata. If I check ieee80211_set_monitor_channel() I see how *sdata is
> obtained there, but I am not sure if it is a good idea to add *ocb_sdata
> to struct ieee80211_local?
That doesn't seem right, no; it seems in theory multiple OBC interfaces
could be present.
johannes