* [ath9k-devel] [RFC 1/4] mac80211: Allow 5/10 MHz channel setting (for OCB)
2014-02-17 13:22 [ath9k-devel] [RFC 0/4] mac80211 & ath9k: ITS-G5 (IEEE 802.11p) basic support Rostislav Lisovy
@ 2014-02-17 13:22 ` Rostislav Lisovy
2014-02-17 13:49 ` Johannes Berg
2014-02-17 13:22 ` [ath9k-devel] [RFC 2/4] ath9k: " Rostislav Lisovy
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Rostislav Lisovy @ 2014-02-17 13:22 UTC (permalink / raw)
To: ath9k-devel
Signed-off-by: Rostislav Lisovy <lisovy@gmail.com>
---
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
^ permalink raw reply related [flat|nested] 9+ messages in thread* [ath9k-devel] [RFC 2/4] ath9k: Allow 5/10 MHz channel setting (for OCB)
2014-02-17 13:22 [ath9k-devel] [RFC 0/4] mac80211 & ath9k: ITS-G5 (IEEE 802.11p) basic support Rostislav Lisovy
2014-02-17 13:22 ` [ath9k-devel] [RFC 1/4] mac80211: Allow 5/10 MHz channel setting (for OCB) Rostislav Lisovy
@ 2014-02-17 13:22 ` Rostislav Lisovy
2014-02-17 13:22 ` [ath9k-devel] [RFC 3/4] mac80211: Add OCB (IEEE 802.11p) mode Rostislav Lisovy
2014-02-17 13:22 ` [ath9k-devel] [RFC 4/4] ath9k: " Rostislav Lisovy
3 siblings, 0 replies; 9+ messages in thread
From: Rostislav Lisovy @ 2014-02-17 13:22 UTC (permalink / raw)
To: ath9k-devel
Signed-off-by: Rostislav Lisovy <lisovy@gmail.com>
---
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
^ permalink raw reply related [flat|nested] 9+ messages in thread* [ath9k-devel] [RFC 3/4] mac80211: Add OCB (IEEE 802.11p) mode
2014-02-17 13:22 [ath9k-devel] [RFC 0/4] mac80211 & ath9k: ITS-G5 (IEEE 802.11p) basic support Rostislav Lisovy
2014-02-17 13:22 ` [ath9k-devel] [RFC 1/4] mac80211: Allow 5/10 MHz channel setting (for OCB) Rostislav Lisovy
2014-02-17 13:22 ` [ath9k-devel] [RFC 2/4] ath9k: " Rostislav Lisovy
@ 2014-02-17 13:22 ` Rostislav Lisovy
2014-02-17 13:50 ` Johannes Berg
2014-02-17 13:22 ` [ath9k-devel] [RFC 4/4] ath9k: " Rostislav Lisovy
3 siblings, 1 reply; 9+ messages in thread
From: Rostislav Lisovy @ 2014-02-17 13:22 UTC (permalink / raw)
To: ath9k-devel
Signed-off-by: Rostislav Lisovy <lisovy@gmail.com>
---
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 <robert.budde@tu-dortmund.de>
+ * 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
^ permalink raw reply related [flat|nested] 9+ messages in thread