[PATCH v2] brcmfmac: Fix a memory leak in error handling path in 'brcmf_cfg80211_attach'

2017-06-20 Thread Christophe JAILLET
If 'wiphy_new()' fails, we leak 'ops'. Add a new label in the error
handling path to free it in such a case.

Cc: sta...@vger.kernel.org
Fixes: 5c22fb85102a7 ("brcmfmac: add wowl gtk rekeying offload support")
Signed-off-by: Christophe JAILLET 
---
v2: Add CC tag
Change prefix
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c 
b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 2443c71a202f..032d823c53c2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -6861,7 +6861,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct 
brcmf_pub *drvr,
wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
if (!wiphy) {
brcmf_err("Could not allocate wiphy device\n");
-   return NULL;
+   goto ops_out;
}
memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN);
set_wiphy_dev(wiphy, busdev);
@@ -7012,6 +7012,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct 
brcmf_pub *drvr,
ifp->vif = NULL;
 wiphy_out:
brcmf_free_wiphy(wiphy);
+ops_out:
kfree(ops);
return NULL;
 }
-- 
2.11.0



Re: [RFC] mac80211: support non-data TXQs

2017-06-20 Thread Igor Mitsyanko

On 06/20/2017 02:03 PM, Johannes Berg wrote:

From: Johannes Berg 

Some drivers may want to also use the TXQ abstraction with
non-data packets, so add a hardware flag to allow this.

Signed-off-by: Johannes Berg 

---
  include/net/mac80211.h |  9 +++--
  net/mac80211/debugfs.c |  1 +
  net/mac80211/debugfs_sta.c |  4 +++-
  net/mac80211/sta_info.c| 15 ---
  net/mac80211/tx.c  | 20 ++--
  5 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 13c59e6f88d4..b64148c49db0 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1908,7 +1908,7 @@ struct ieee80211_sta {
bool support_p2p_ps;
u16 max_rc_amsdu_len;
  
-	struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];

+   struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];


Isn't that a little confusing? Wouldn't it be better to have a separate 
member for non-data txq and name it accordingly (something like 
txq_nodata). You have to handle it specially in most cases anyway I guess.
With this approach you won't have to replace ARRAY_SIZE(sta->txq) by 
IEEE80211_NUM_TIDS anywhere.


  
  	/* must be last */

u8 drv_priv[0] __aligned(sizeof(void *));
@@ -1942,7 +1942,8 @@ struct ieee80211_tx_control {
   *
   * @vif:  ieee80211_vif pointer from the add_interface callback.
   * @sta: station table entry, %NULL for per-vif queue
- * @tid: the TID for this queue (unused for per-vif queue)
+ * @tid: the TID for this queue (unused for per-vif queue),
+ * %IEEE80211_NUM_TIDS for non-data (if enabled)
   * @ac: the AC for this queue
   * @drv_priv: driver private area, sized by hw->txq_data_size
   *
@@ -2141,6 +2142,9 @@ struct ieee80211_txq {
   *The stack will not do fragmentation.
   *The callback for @set_frag_threshold should be set as well.
   *
+ * @IEEE80211_HW_WANT_NONDATA_TXQ: The driver/hardware wants to have a TXQ
+ * ( ieee80211_txq) for non-data frames
+ *
   * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
   */
  enum ieee80211_hw_flags {
@@ -2183,6 +2187,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TX_FRAG_LIST,
IEEE80211_HW_REPORTS_LOW_ACK,
IEEE80211_HW_SUPPORTS_TX_FRAG,
+   IEEE80211_HW_WANT_NONDATA_TXQ,
  
  	/* keep last, obviously */

NUM_IEEE80211_HW_FLAGS
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index d40ec17829a9..d754dc9ff56f 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -791,6 +791,7 @@ static const char *hw_flag_names[] = {
FLAG(TX_FRAG_LIST),
FLAG(REPORTS_LOW_ACK),
FLAG(SUPPORTS_TX_FRAG),
+   FLAG(WANT_NONDATA_TXQ),
  #undef FLAG
  };
  
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c

index 0f122a554d2e..48984f6cabd9 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -171,7 +171,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user 
*userbuf,
   bufsz+buf-p,
   "tid ac backlog-bytes backlog-packets new-flows drops marks 
overlimit collisions tx-bytes tx-packets\n");
  
-	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {

+   for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+   if (!sta->sta.txq[i])
+   continue;
txqi = to_txq_info(sta->sta.txq[i]);
p += scnprintf(p, bufsz+buf-p,
   "%d %d %u %u %u %u %u %u %u %u %u\n",
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 0297f544e0cc..8b71960eb2a0 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -112,7 +112,12 @@ static void __cleanup_single_sta(struct sta_info *sta)
  
  	if (sta->sta.txq[0]) {

for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-   struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
+   struct txq_info *txqi;
+
+   if (!sta->sta.txq[i])
+   continue;
+
+   txqi = to_txq_info(sta->sta.txq[i]);
  
  			spin_lock_bh(>lock);

ieee80211_txq_purge(local, txqi);
@@ -384,15 +389,19 @@ struct sta_info *sta_info_alloc(struct 
ieee80211_sub_if_data *sdata,
ewma_signal_init(>rx_stats_avg.chain_signal[i]);
  
  	if (local->ops->wake_tx_queue) {

+   int num_queues = IEEE80211_NUM_TIDS;
void *txq_data;
int size = sizeof(struct txq_info) +
   ALIGN(hw->txq_data_size, sizeof(void *));
  
-		txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);

+   if (ieee80211_hw_check(>hw, WANT_NONDATA_TXQ))
+   num_queues++;
+
+   txq_data = kcalloc(num_queues, size, gfp);
if (!txq_data)

Re: [PATCH] mac80211: don't look at the PM bit of BAR frames

2017-06-20 Thread Igor Mitsyanko

On 06/08/2017 04:00 AM, Emmanuel Grumbach wrote:

When a peer sends a BAR frame with PM bit clear, we should
not modify its PM state as madated by the spec in
802.11-20012 10.2.1.2.

Signed-off-by: Emmanuel Grumbach 

---
  net/mac80211/rx.c | 6 +-
  1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index e48724a6725e..bb1e4bbf55e2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1558,12 +1558,16 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 */
if (!ieee80211_hw_check(>local->hw, AP_LINK_PS) &&
!ieee80211_has_morefrags(hdr->frame_control) &&
+   !ieee80211_is_back_req(hdr->frame_control) &&


BTW latest spec also notes that PSPOLL frame has PM bit reserved too, 
because it may not result in ACK frame from AP.



!(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
(rx->sdata->vif.type == NL80211_IFTYPE_AP ||
 rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
-   /* PM bit is only checked in frames where it isn't reserved,
+   /*
+* PM bit is only checked in frames where it isn't reserved,
 * in AP mode it's reserved in non-bufferable management frames
 * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field)
+* BAR frames should be ignored as specified in
+* IEEE 802.11-2012 10.2.1.2.


Comment placement is a little confusing IMO. Maybe move 
ieee80211_is_back_req() check to this position?



 */
(!ieee80211_is_mgmt(hdr->frame_control) ||
 ieee80211_is_bufferable_mmpdu(hdr->frame_control))) {





Re: [RFC] mac80211: support non-data TXQs

2017-06-20 Thread Johannes Berg
On Tue, 2017-06-20 at 23:03 +0200, Johannes Berg wrote:
> From: Johannes Berg 
> 
> Some drivers may want to also use the TXQ abstraction with
> non-data packets, so add a hardware flag to allow this.

Need to replace various ARRAY_SIZE(sta->txq) in ath9k/ath10k by
IEEE80211_NUM_TIDS.

johannes


[RFC] mac80211: don't put null-data frames on the normal TXQ

2017-06-20 Thread Johannes Berg
From: Johannes Berg 

Since (QoS) NDP frames shouldn't be put into aggregation nor are
assigned real sequence numbers, etc. it's better to treat them as
non-data packets and not put them on the normal TXQs.

Signed-off-by: Johannes Berg 
---
 net/mac80211/tx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d1cef5ad91ee..726fb3b02a23 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1256,7 +1256,7 @@ static struct txq_info *ieee80211_get_txq(struct 
ieee80211_local *local,
return NULL;
} else if (!sta) {
txq = vif->txq;
-   } else if (!ieee80211_is_data(hdr->frame_control)) {
+   } else if (!ieee80211_is_data_present(hdr->frame_control)) {
if (!sta->uploaded)
return NULL;
 
-- 
2.11.0



[RFC] mac80211: support non-data TXQs

2017-06-20 Thread Johannes Berg
From: Johannes Berg 

Some drivers may want to also use the TXQ abstraction with
non-data packets, so add a hardware flag to allow this.

Signed-off-by: Johannes Berg 
---
 include/net/mac80211.h |  9 +++--
 net/mac80211/debugfs.c |  1 +
 net/mac80211/debugfs_sta.c |  4 +++-
 net/mac80211/sta_info.c| 15 ---
 net/mac80211/tx.c  | 20 ++--
 5 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 13c59e6f88d4..b64148c49db0 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1908,7 +1908,7 @@ struct ieee80211_sta {
bool support_p2p_ps;
u16 max_rc_amsdu_len;
 
-   struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
+   struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
 
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
@@ -1942,7 +1942,8 @@ struct ieee80211_tx_control {
  *
  * @vif:  ieee80211_vif pointer from the add_interface callback.
  * @sta: station table entry, %NULL for per-vif queue
- * @tid: the TID for this queue (unused for per-vif queue)
+ * @tid: the TID for this queue (unused for per-vif queue),
+ * %IEEE80211_NUM_TIDS for non-data (if enabled)
  * @ac: the AC for this queue
  * @drv_priv: driver private area, sized by hw->txq_data_size
  *
@@ -2141,6 +2142,9 @@ struct ieee80211_txq {
  * The stack will not do fragmentation.
  * The callback for @set_frag_threshold should be set as well.
  *
+ * @IEEE80211_HW_WANT_NONDATA_TXQ: The driver/hardware wants to have a TXQ
+ * ( ieee80211_txq) for non-data frames
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -2183,6 +2187,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TX_FRAG_LIST,
IEEE80211_HW_REPORTS_LOW_ACK,
IEEE80211_HW_SUPPORTS_TX_FRAG,
+   IEEE80211_HW_WANT_NONDATA_TXQ,
 
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index d40ec17829a9..d754dc9ff56f 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -791,6 +791,7 @@ static const char *hw_flag_names[] = {
FLAG(TX_FRAG_LIST),
FLAG(REPORTS_LOW_ACK),
FLAG(SUPPORTS_TX_FRAG),
+   FLAG(WANT_NONDATA_TXQ),
 #undef FLAG
 };
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 0f122a554d2e..48984f6cabd9 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -171,7 +171,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user 
*userbuf,
   bufsz+buf-p,
   "tid ac backlog-bytes backlog-packets new-flows drops 
marks overlimit collisions tx-bytes tx-packets\n");
 
-   for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+   for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+   if (!sta->sta.txq[i])
+   continue;
txqi = to_txq_info(sta->sta.txq[i]);
p += scnprintf(p, bufsz+buf-p,
   "%d %d %u %u %u %u %u %u %u %u %u\n",
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 0297f544e0cc..8b71960eb2a0 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -112,7 +112,12 @@ static void __cleanup_single_sta(struct sta_info *sta)
 
if (sta->sta.txq[0]) {
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-   struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
+   struct txq_info *txqi;
+
+   if (!sta->sta.txq[i])
+   continue;
+
+   txqi = to_txq_info(sta->sta.txq[i]);
 
spin_lock_bh(>lock);
ieee80211_txq_purge(local, txqi);
@@ -384,15 +389,19 @@ struct sta_info *sta_info_alloc(struct 
ieee80211_sub_if_data *sdata,
ewma_signal_init(>rx_stats_avg.chain_signal[i]);
 
if (local->ops->wake_tx_queue) {
+   int num_queues = IEEE80211_NUM_TIDS;
void *txq_data;
int size = sizeof(struct txq_info) +
   ALIGN(hw->txq_data_size, sizeof(void *));
 
-   txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
+   if (ieee80211_hw_check(>hw, WANT_NONDATA_TXQ))
+   num_queues++;
+
+   txq_data = kcalloc(num_queues, size, gfp);
if (!txq_data)
goto free;
 
-   for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+   for (i = 0; i < num_queues; i++) {
struct txq_info *txq = txq_data + i * size;
 
ieee80211_txq_init(sdata, sta, txq, i);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3d3e37f29bcb..d1cef5ad91ee 100644
--- 

Re: [PATCH 5/8] qtnfmac: enable reporting the current operating channel

2017-06-20 Thread Johannes Berg
On Tue, 2017-06-20 at 23:09 +0300, Sergey Matyukevich wrote:
> > 
> > > + if (sme->channel) {
> > > + /* FIXME: need to set proper nl80211_channel_type
> > > value */
> > > + cfg80211_chandef_create(, sme->channel,
> > > + NL80211_CHAN_HT20);
> > > + /* fall-back to minimal safe chandef description */
> > > + if (!cfg80211_chandef_valid())
> > > + cfg80211_chandef_create(, sme-
> > > > channel,
> > > 
> > > + NL80211_CHAN_HT20);
> > > 
> > 
> > This seems odd since you just do the same thing over again? Not
> > that I
> > could see how it would be invalid anyway.
> 
> The first call of cfg80211_chandef_create will be replaced by proper
> chandef calculation based on current h/w channel settings. This piece
> is still in work. NL80211_CHAN_HT20 is going to be used as a safe
> fallback when channel info turns out to be inconsistent.

Yeah, ok. I guess I'd advocate doing that when the code is actually
there, but I suppose it doesn't really matter much.

johannes


Re: [PATCH 5/8] qtnfmac: enable reporting the current operating channel

2017-06-20 Thread Sergey Matyukevich
> 
> > + if (sme->channel) {
> > + /* FIXME: need to set proper nl80211_channel_type
> > value */
> > + cfg80211_chandef_create(, sme->channel,
> > + NL80211_CHAN_HT20);
> > + /* fall-back to minimal safe chandef description */
> > + if (!cfg80211_chandef_valid())
> > + cfg80211_chandef_create(, sme-
> > >channel,
> > + NL80211_CHAN_HT20);
> >
> This seems odd since you just do the same thing over again? Not that I
> could see how it would be invalid anyway.

The first call of cfg80211_chandef_create will be replaced by proper chandef
calculation based on current h/w channel settings. This piece is still in work.
NL80211_CHAN_HT20 is going to be used as a safe fallback when channel info
turns out to be inconsistent.

Regards,
Sergey


Re: [PATCH 5/8] qtnfmac: enable reporting the current operating channel

2017-06-20 Thread Johannes Berg
On Tue, 2017-06-20 at 22:55 +0300, Sergey Matyukevich wrote:

> + if (sme->channel) {
> + /* FIXME: need to set proper nl80211_channel_type
> value */
> + cfg80211_chandef_create(, sme->channel,
> + NL80211_CHAN_HT20);
> + /* fall-back to minimal safe chandef description */
> + if (!cfg80211_chandef_valid())
> + cfg80211_chandef_create(, sme-
> >channel,
> + NL80211_CHAN_HT20);
> 
This seems odd since you just do the same thing over again? Not that I
could see how it would be invalid anyway.

johannes


[PATCH 7/8] qtnfmac: implement cfg80211 channel_switch handler

2017-06-20 Thread Sergey Matyukevich
This patch implements cfg80211 channel_switch handler enabling CSA
channel-switch procedure.

At the moment qtnfmac host driver performs only basic validation of
the requested new channel and then sends command to firmware.
Beacon IEs are not sent since beacon update is handled by firmware.

Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 60 ++-
 drivers/net/wireless/quantenna/qtnfmac/commands.c | 55 +
 drivers/net/wireless/quantenna/qtnfmac/commands.h |  2 +
 drivers/net/wireless/quantenna/qtnfmac/core.h |  6 +++
 drivers/net/wireless/quantenna/qtnfmac/event.c|  8 +++
 drivers/net/wireless/quantenna/qtnfmac/qlink.h| 17 +++
 6 files changed, 146 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 3f90f57ed595..097f29189339 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -977,6 +977,59 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev 
*wdev,
return 0;
 }
 
+static int qtnf_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+  struct cfg80211_csa_settings *params)
+{
+   struct qtnf_wmac *mac = wiphy_priv(wiphy);
+   struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
+   int ret;
+
+   pr_info("%s: chan(%u) count(%u) radar(%u) block_tx(%u)\n", dev->name,
+   params->chandef.chan->hw_value, params->count,
+   params->radar_required, params->block_tx);
+
+   switch (vif->wdev.iftype) {
+   case NL80211_IFTYPE_AP:
+   if (!(vif->bss_status & QTNF_STATE_AP_START)) {
+   pr_warn("AP not started on %s\n", dev->name);
+   return -ENOTCONN;
+   }
+   break;
+   default:
+   pr_err("unsupported vif type (%d) on %s\n",
+  vif->wdev.iftype, dev->name);
+   return -EOPNOTSUPP;
+   }
+
+   if (vif->vifid != 0) {
+   if (!(mac->status & QTNF_MAC_CSA_ACTIVE))
+   return -EOPNOTSUPP;
+
+   if (!cfg80211_chandef_identical(>chandef,
+   >csa_chandef))
+   return -EINVAL;
+
+   return 0;
+   }
+
+   if (!cfg80211_chandef_valid(>chandef)) {
+   pr_err("%s: invalid channel\n", dev->name);
+   return -EINVAL;
+   }
+
+   if (cfg80211_chandef_identical(>chandef, >chandef)) {
+   pr_err("%s: switch request to the same channel\n", dev->name);
+   return -EALREADY;
+   }
+
+   ret = qtnf_cmd_send_chan_switch(mac, params);
+   if (ret)
+   pr_warn("%s: failed to switch to channel (%u)\n",
+   dev->name, params->chandef.chan->hw_value);
+
+   return ret;
+}
+
 static struct cfg80211_ops qtn_cfg80211_ops = {
.add_virtual_intf   = qtnf_add_virtual_intf,
.change_virtual_intf= qtnf_change_virtual_intf,
@@ -999,7 +1052,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
.connect= qtnf_connect,
.disconnect = qtnf_disconnect,
.dump_survey= qtnf_dump_survey,
-   .get_channel= qtnf_get_channel
+   .get_channel= qtnf_get_channel,
+   .channel_switch = qtnf_channel_switch
 };
 
 static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
@@ -1149,6 +1203,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, 
struct qtnf_wmac *mac)
 
wiphy->iface_combinations = iface_comb;
wiphy->n_iface_combinations = 1;
+   wiphy->max_num_csa_counters = 2;
 
/* Initialize cipher suits */
wiphy->cipher_suites = qtnf_cipher_suites;
@@ -1156,7 +1211,8 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, 
struct qtnf_wmac *mac)
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
-   WIPHY_FLAG_AP_UAPSD;
+   WIPHY_FLAG_AP_UAPSD |
+   WIPHY_FLAG_HAS_CHANNEL_SWITCH;
 
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c 
b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index f44ae71047c3..900159e82bc8 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -2334,3 +2334,58 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 
channel,
consume_skb(resp_skb);
return ret;
 }
+
+int 

[PATCH 8/8] qtnfmac: implement scan timeout

2017-06-20 Thread Sergey Matyukevich
Userspace tools may hang on scan in the case when scan completion event
is not returned by firmware. This patch implements the scan timeout
to avoid such situation.

Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 22 ++
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.h |  4 
 drivers/net/wireless/quantenna/qtnfmac/core.c |  2 ++
 drivers/net/wireless/quantenna/qtnfmac/core.h | 13 +
 drivers/net/wireless/quantenna/qtnfmac/event.c|  2 ++
 5 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 097f29189339..a0ab7d289684 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -741,19 +741,33 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device 
*dev,
return ret;
 }
 
+static void qtnf_scan_timeout(unsigned long data)
+{
+   struct qtnf_wmac *mac = (struct qtnf_wmac *)data;
+
+   pr_warn("mac%d scan timed out\n", mac->macid);
+   qtnf_scan_done(mac, true);
+}
+
 static int
 qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 {
struct qtnf_wmac *mac = wiphy_priv(wiphy);
-   int ret;
 
mac->scan_req = request;
 
-   ret = qtnf_cmd_send_scan(mac);
-   if (ret)
+   if (qtnf_cmd_send_scan(mac)) {
pr_err("MAC%u: failed to start scan\n", mac->macid);
+   mac->scan_req = NULL;
+   return -EFAULT;
+   }
 
-   return ret;
+   mac->scan_timeout.data = (unsigned long)mac;
+   mac->scan_timeout.function = qtnf_scan_timeout;
+   mod_timer(>scan_timeout,
+ jiffies + QTNF_SCAN_TIMEOUT_SEC * HZ);
+
+   return 0;
 }
 
 static int
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h
index 5bd33124a7c8..eddd040b8869 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h
@@ -34,10 +34,14 @@ static inline void qtnf_scan_done(struct qtnf_wmac *mac, 
bool aborted)
.aborted = aborted,
};
 
+   qtnf_wmac_lock(mac);
+
if (mac->scan_req) {
cfg80211_scan_done(mac->scan_req, );
mac->scan_req = NULL;
}
+
+   qtnf_wmac_unlock(mac);
 }
 
 #endif /* _QTN_FMAC_CFG80211_H_ */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c 
b/drivers/net/wireless/quantenna/qtnfmac/core.c
index 3d9b217790ed..8ce9c370dc94 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/core.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/core.c
@@ -336,6 +336,8 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct 
qtnf_bus *bus,
mac->iflist[i].vifid = i;
qtnf_list_init(>iflist[i].sta_list);
qtnf_list_init(>iflist[i].vlan_list);
+   mutex_init(>mac_lock);
+   init_timer(>scan_timeout);
}
 
qtnf_mac_init_primary_intf(mac);
diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h 
b/drivers/net/wireless/quantenna/qtnfmac/core.h
index efe078a6d1d3..883b052ccb01 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/core.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/core.h
@@ -46,6 +46,7 @@
 #define QTNF_MAX_EVENT_QUEUE_LEN   255
 #define QTNF_DEFAULT_BG_SCAN_PERIOD300
 #define QTNF_MAX_BG_SCAN_PERIOD0x
+#define QTNF_SCAN_TIMEOUT_SEC  15
 
 #define QTNF_DEF_BSS_PRIORITY  0
 #define QTNF_DEF_WDOG_TIMEOUT  5
@@ -161,6 +162,8 @@ struct qtnf_wmac {
struct cfg80211_scan_request *scan_req;
struct cfg80211_chan_def chandef;
struct cfg80211_chan_def csa_chandef;
+   struct mutex mac_lock;  /* lock during wmac speicific ops */
+   struct timer_list scan_timeout;
 };
 
 struct qtnf_hw_info {
@@ -197,4 +200,14 @@ static inline struct qtnf_vif *qtnf_netdev_get_priv(struct 
net_device *dev)
return *((void **)netdev_priv(dev));
 }
 
+static __always_inline void qtnf_wmac_lock(struct qtnf_wmac *mac)
+{
+   mutex_lock(>mac_lock);
+}
+
+static __always_inline void qtnf_wmac_unlock(struct qtnf_wmac *mac)
+{
+   mutex_unlock(>mac_lock);
+}
+
 #endif /* _QTN_FMAC_CORE_H_ */
diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c 
b/drivers/net/wireless/quantenna/qtnfmac/event.c
index b48d9e8b6935..2c0d6095544f 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/event.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/event.c
@@ -345,6 +345,8 @@ qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
return -EINVAL;
}
 
+   if (timer_pending(>scan_timeout))
+   del_timer_sync(>scan_timeout);
qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
 
return 0;
-- 
2.11.0



[PATCH 5/8] qtnfmac: enable reporting the current operating channel

2017-06-20 Thread Sergey Matyukevich
This patch implements all the necessary features needed to keep
operating channel information in sync between firmware and driver:

- implement cfg80211 qtnf_get_channel handler
- implement QLINK_EVENT_FREQ_CHANGE event handling
  using this event firmware notifies host when operating channel is changed
- update qtnf_dump_survey
  specify current channel in use in survey report
- update qtnf_connect
  pass to firmware channel number rather than frequency

Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 66 ++-
 drivers/net/wireless/quantenna/qtnfmac/commands.c |  2 +-
 drivers/net/wireless/quantenna/qtnfmac/event.c| 60 -
 drivers/net/wireless/quantenna/qtnfmac/qlink.h| 15 +-
 4 files changed, 136 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index eb648f02aa40..77afc0fc8c03 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -755,6 +755,7 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
 struct cfg80211_connect_params *sme)
 {
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
+   struct cfg80211_chan_def chandef;
struct qtnf_bss_config *bss_cfg;
int ret;
 
@@ -767,9 +768,20 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
bss_cfg = >bss_cfg;
memset(bss_cfg, 0, sizeof(*bss_cfg));
 
+   if (sme->channel) {
+   /* FIXME: need to set proper nl80211_channel_type value */
+   cfg80211_chandef_create(, sme->channel,
+   NL80211_CHAN_HT20);
+   /* fall-back to minimal safe chandef description */
+   if (!cfg80211_chandef_valid())
+   cfg80211_chandef_create(, sme->channel,
+   NL80211_CHAN_HT20);
+
+   memcpy(_cfg->chandef, , sizeof(bss_cfg->chandef));
+   }
+
bss_cfg->ssid_len = sme->ssid_len;
memcpy(_cfg->ssid, sme->ssid, bss_cfg->ssid_len);
-   bss_cfg->chandef.chan = sme->channel;
bss_cfg->auth_type = sme->auth_type;
bss_cfg->privacy = sme->privacy;
bss_cfg->mfp = sme->mfp;
@@ -845,10 +857,15 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device 
*dev,
 {
struct qtnf_wmac *mac = wiphy_priv(wiphy);
struct ieee80211_supported_band *sband;
+   struct cfg80211_chan_def *bss_chandef;
struct ieee80211_channel *chan;
struct qtnf_chan_stats stats;
+   struct qtnf_vif *vif;
int ret;
 
+   vif = qtnf_netdev_get_priv(dev);
+   bss_chandef = >bss_cfg.chandef;
+
sband = wiphy->bands[NL80211_BAND_2GHZ];
if (sband && idx >= sband->n_channels) {
idx -= sband->n_channels;
@@ -867,6 +884,10 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device 
*dev,
survey->channel = chan;
survey->filled = 0x0;
 
+   if (bss_chandef->chan)
+   if (chan->hw_value == bss_chandef->chan->hw_value)
+   survey->filled |= SURVEY_INFO_IN_USE;
+
ret = qtnf_cmd_get_chan_stats(mac, chan->hw_value, );
switch (ret) {
case 0:
@@ -905,6 +926,46 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device 
*dev,
return ret;
 }
 
+static int
+qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+struct cfg80211_chan_def *chandef)
+{
+   struct net_device *ndev = wdev->netdev;
+   struct qtnf_bss_config *bss_cfg;
+   struct qtnf_vif *vif;
+
+   if (!ndev)
+   return -ENODEV;
+
+   vif = qtnf_netdev_get_priv(wdev->netdev);
+   bss_cfg = >bss_cfg;
+
+   switch (vif->wdev.iftype) {
+   case NL80211_IFTYPE_STATION:
+   if (vif->sta_state == QTNF_STA_DISCONNECTED) {
+   pr_warn("%s: STA disconnected\n", ndev->name);
+   return -ENODATA;
+   }
+   break;
+   case NL80211_IFTYPE_AP_VLAN:
+   /* AP_VLAN: get primary vif and pass through to AP */
+   vif = vif->u.vlan.parent;
+   bss_cfg = >bss_cfg;
+   case NL80211_IFTYPE_AP:
+   if (!(vif->bss_status & QTNF_STATE_AP_START)) {
+   pr_warn("%s: AP not started\n", ndev->name);
+   return -ENODATA;
+   }
+   break;
+   default:
+   pr_err("unsupported vif type (%d)\n", vif->wdev.iftype);
+   return -ENODATA;
+   }
+
+   memcpy(chandef, _cfg->chandef, sizeof(*chandef));
+   return 0;
+}
+
 static struct cfg80211_ops qtn_cfg80211_ops = {
.add_virtual_intf   = qtnf_add_virtual_intf,
.change_virtual_intf= qtnf_change_virtual_intf,
@@ 

[PATCH 6/8] qtnfmac: move current channel info from vif to mac

2017-06-20 Thread Sergey Matyukevich
Wireless cfg80211 core supplies channel settings in cfg80211_ap_settings
structure for each BSS in multiple BSS configuration. On the other hand
all the virtual interfaces on one radio are using the same PHY settings
including channel.

Move chandef structure from vif to mac structure in order to mantain
the only instance of cfg80211_chan_def structure in qtnf_wmac
rather than its multiple copies in qtnf_vif.

Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 39 +++
 drivers/net/wireless/quantenna/qtnfmac/commands.c |  6 ++--
 drivers/net/wireless/quantenna/qtnfmac/core.h |  2 +-
 drivers/net/wireless/quantenna/qtnfmac/event.c|  7 ++--
 4 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 77afc0fc8c03..3f90f57ed595 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -408,11 +408,19 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct 
net_device *dev,
 struct cfg80211_ap_settings *settings)
 {
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
+   struct qtnf_wmac *mac = wiphy_priv(wiphy);
struct qtnf_bss_config *bss_cfg;
int ret;
 
-   bss_cfg = >bss_cfg;
+   if (!cfg80211_chandef_identical(>chandef, >chandef)) {
+   memcpy(>chandef, >chandef, sizeof(mac->chandef));
+   if (vif->vifid != 0)
+   pr_warn("%s: unexpected chan %u (%u MHz)\n", dev->name,
+   settings->chandef.chan->hw_value,
+   settings->chandef.chan->center_freq);
+   }
 
+   bss_cfg = >bss_cfg;
memset(bss_cfg, 0, sizeof(*bss_cfg));
 
bss_cfg->bcn_period = settings->beacon_interval;
@@ -423,8 +431,6 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct 
net_device *dev,
bss_cfg->ssid_len = settings->ssid_len;
memcpy(_cfg->ssid, settings->ssid, bss_cfg->ssid_len);
 
-   memcpy(_cfg->chandef, >chandef,
-  sizeof(struct cfg80211_chan_def));
memcpy(_cfg->crypto, >crypto,
   sizeof(struct cfg80211_crypto_settings));
 
@@ -755,6 +761,7 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
 struct cfg80211_connect_params *sme)
 {
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
+   struct qtnf_wmac *mac = wiphy_priv(wiphy);
struct cfg80211_chan_def chandef;
struct qtnf_bss_config *bss_cfg;
int ret;
@@ -777,7 +784,7 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,
cfg80211_chandef_create(, sme->channel,
NL80211_CHAN_HT20);
 
-   memcpy(_cfg->chandef, , sizeof(bss_cfg->chandef));
+   memcpy(>chandef, , sizeof(mac->chandef));
}
 
bss_cfg->ssid_len = sme->ssid_len;
@@ -857,14 +864,14 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device 
*dev,
 {
struct qtnf_wmac *mac = wiphy_priv(wiphy);
struct ieee80211_supported_band *sband;
-   struct cfg80211_chan_def *bss_chandef;
+   struct cfg80211_chan_def *chandef;
struct ieee80211_channel *chan;
struct qtnf_chan_stats stats;
struct qtnf_vif *vif;
int ret;
 
vif = qtnf_netdev_get_priv(dev);
-   bss_chandef = >bss_cfg.chandef;
+   chandef = >chandef;
 
sband = wiphy->bands[NL80211_BAND_2GHZ];
if (sband && idx >= sband->n_channels) {
@@ -884,9 +891,10 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device 
*dev,
survey->channel = chan;
survey->filled = 0x0;
 
-   if (bss_chandef->chan)
-   if (chan->hw_value == bss_chandef->chan->hw_value)
-   survey->filled |= SURVEY_INFO_IN_USE;
+   if (chandef->chan) {
+   if (chan->hw_value == chandef->chan->hw_value)
+   survey->filled = SURVEY_INFO_IN_USE;
+   }
 
ret = qtnf_cmd_get_chan_stats(mac, chan->hw_value, );
switch (ret) {
@@ -898,7 +906,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device 
*dev,
break;
}
 
-   survey->filled = SURVEY_INFO_TIME |
+   survey->filled |= SURVEY_INFO_TIME |
 SURVEY_INFO_TIME_SCAN |
 SURVEY_INFO_TIME_BUSY |
 SURVEY_INFO_TIME_RX |
@@ -930,15 +938,14 @@ static int
 qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
 struct cfg80211_chan_def *chandef)
 {
+   struct qtnf_wmac *mac = wiphy_priv(wiphy);
struct net_device *ndev = wdev->netdev;
-   struct qtnf_bss_config *bss_cfg;
struct qtnf_vif *vif;
 
if 

[PATCH 3/8] qtnfmac: implement AP_VLAN iftype support

2017-06-20 Thread Sergey Matyukevich
This patch implements AP_VLAN interface type support enabling
the use of dynamic VLAN mode in hostapd.

Implementation notes.

1. Passing dynamic VLAN tag to firmware
Currently there is no established way to pass VLAN tag assigned to STA
by Radius server to wireless driver. It is assumed that hostapd is able
to setup all the bridging and tagging on its own. However qtnf firmware
needs to know the assigned dynamic VLAN tags in order to perform various
internal tasks including group key management, filtering, acceleration,
and more.

Current implementation makes use of the following workaround.
Driver obtains dynamic VLAN tags assigned by Radius server
from AP/VLAN interface names:
- for primary interfaces: wlanX.Z
  where X and Z are macid and vlan tag respectively
- for MBSS virtual interfaces: wlanX_Y.Z
  where X, Y, Z are macid, vifid, and vlan tag respectively

Such a naming convention can be configured using
hostapd vlan_file configuration file.

2. Packet routing to/from AP/VLAN interfaces
Firmware operates with tagged packets after dynamic VLAN mode is
configured. In particular, packets destined to STAs should be
properly tagged before they can be passed to firmware. Packets
received from STAs are properly tagged by firmware and then
passed to wireless driver. As a result, packet routing to AP/VLAN
interfaces is straightforward: it is enough to check VLAN tags.

Normally hostapd expects untagged packets from AP/VLAN interfaces.
Meanwhile firmware performs tagging using h/w acceleration. That
is why it makes sense to avoid untagging packets in driver if
they are supposed to by tagged again on host. To enable this
behavior a new module parameter 'dyn_vlan_tagged' has been
introduced:

- dyn_vlan_tagged = 0 (default)
In this case untagged packets are sent to and expected from AP/VLAN interfaces.
Driver tags/untags packets going to/from firmware. This behaviour is expected
by hostapd which is able to create bridges and VLAN interfaces automatically
when hostapd is built with CONFIG_FULL_DYNAMIC_VLAN option enabled.

- dyn_vlan_tagged = 1
In this case tagged packets are sent to and expected from AP/VLAN interfaces.
Hostapd build option CONFIG_FULL_DYNAMIC_VLAN should be disabled. Setup of
networking topology on host is left up to the implementers.

Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/bus.h   |   1 +
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c  | 247 ++---
 drivers/net/wireless/quantenna/qtnfmac/commands.c  |  28 ++-
 drivers/net/wireless/quantenna/qtnfmac/core.c  |  78 ++-
 drivers/net/wireless/quantenna/qtnfmac/core.h  |  25 ++-
 .../net/wireless/quantenna/qtnfmac/pearl/pcie.c|   5 +
 drivers/net/wireless/quantenna/qtnfmac/qlink.h |  10 +-
 .../net/wireless/quantenna/qtnfmac/qlink_util.c|   3 +
 drivers/net/wireless/quantenna/qtnfmac/util.c  |  74 --
 drivers/net/wireless/quantenna/qtnfmac/util.h  |  34 ++-
 10 files changed, 428 insertions(+), 77 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h 
b/drivers/net/wireless/quantenna/qtnfmac/bus.h
index dda05003d522..819ba3ba0f05 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/bus.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h
@@ -52,6 +52,7 @@ struct qtnf_bus {
enum qtnf_fw_state fw_state;
u32 chip;
u32 chiprev;
+   u8 dyn_vlan_tagged;
const struct qtnf_bus_ops *bus_ops;
struct qtnf_wmac *mac[QTNF_MAX_MAC];
struct qtnf_qlink_transport trans;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 825a6334fbfe..e222e8d038d3 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -77,6 +77,35 @@ qtnf_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
 };
 
+static int qtnf_vlan_vif_exists(struct qtnf_vif *vif, u16 vlanid)
+{
+   struct qtnf_vif *vlan_vif;
+
+   vlan_vif = qtnf_vlan_list_lookup(>vlan_list, vlanid);
+   if (vlan_vif)
+   return 1;
+
+   return 0;
+}
+
+static struct qtnf_vif *qtnf_add_vlan_vif(struct qtnf_vif *vif, u16 vlanid)
+{
+   struct qtnf_vif *vlan_vif;
+
+   vlan_vif = qtnf_vlan_list_add(>vlan_list, vlanid);
+   if (vlan_vif) {
+   vlan_vif->u.vlan.parent = vif;
+   vlan_vif->u.vlan.vlanid = vlanid;
+   }
+
+   return vlan_vif;
+}
+
+static int qtnf_del_vlan_vif(struct qtnf_vif *vif, u16 vlanid)
+{
+   return qtnf_vlan_list_del(>vlan_list, vlanid);
+}
+
 static int
 qtnf_change_virtual_intf(struct wiphy *wiphy,
 struct net_device *dev,
@@ -92,7 +121,15 @@ qtnf_change_virtual_intf(struct wiphy *wiphy,
else
mac_addr = NULL;
 
-   qtnf_scan_done(vif->mac, true);
+   switch (type) {
+   case NL80211_IFTYPE_STATION:
+   case NL80211_IFTYPE_AP:
+  

[PATCH 4/8] qtnfmac: implement cfg80211 dump_survey handler

2017-06-20 Thread Sergey Matyukevich
This patch implements cfg80211 dump_survey handler enabling
per-channel survey data reports.

Signed-off-by: Avinash Patil 
Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c |  69 +-
 drivers/net/wireless/quantenna/qtnfmac/commands.c | 107 ++
 drivers/net/wireless/quantenna/qtnfmac/commands.h |   2 +
 drivers/net/wireless/quantenna/qtnfmac/core.h |   9 ++
 drivers/net/wireless/quantenna/qtnfmac/qlink.h|  31 +++
 5 files changed, 217 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index e222e8d038d3..eb648f02aa40 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -839,6 +839,72 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device 
*dev,
return 0;
 }
 
+static int
+qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+int idx, struct survey_info *survey)
+{
+   struct qtnf_wmac *mac = wiphy_priv(wiphy);
+   struct ieee80211_supported_band *sband;
+   struct ieee80211_channel *chan;
+   struct qtnf_chan_stats stats;
+   int ret;
+
+   sband = wiphy->bands[NL80211_BAND_2GHZ];
+   if (sband && idx >= sband->n_channels) {
+   idx -= sband->n_channels;
+   sband = NULL;
+   }
+
+   if (!sband)
+   sband = wiphy->bands[NL80211_BAND_5GHZ];
+
+   if (!sband || idx >= sband->n_channels)
+   return -ENOENT;
+
+   chan = >channels[idx];
+   memset(, 0, sizeof(stats));
+
+   survey->channel = chan;
+   survey->filled = 0x0;
+
+   ret = qtnf_cmd_get_chan_stats(mac, chan->hw_value, );
+   switch (ret) {
+   case 0:
+   if (unlikely(stats.chan_num != chan->hw_value)) {
+   pr_err("received stats for channel %d instead of %d\n",
+  stats.chan_num, chan->hw_value);
+   ret = -EINVAL;
+   break;
+   }
+
+   survey->filled = SURVEY_INFO_TIME |
+SURVEY_INFO_TIME_SCAN |
+SURVEY_INFO_TIME_BUSY |
+SURVEY_INFO_TIME_RX |
+SURVEY_INFO_TIME_TX |
+SURVEY_INFO_NOISE_DBM;
+
+   survey->time_scan = stats.cca_try;
+   survey->time = stats.cca_try;
+   survey->time_tx = stats.cca_tx;
+   survey->time_rx = stats.cca_rx;
+   survey->time_busy = stats.cca_busy;
+   survey->noise = stats.chan_noise;
+   break;
+   case -ENOENT:
+   pr_debug("no stats for channel %u\n", chan->hw_value);
+   ret = 0;
+   break;
+   default:
+   pr_debug("failed to get chan(%d) stats from card\n",
+chan->hw_value);
+   ret = -EINVAL;
+   break;
+   }
+
+   return ret;
+}
+
 static struct cfg80211_ops qtn_cfg80211_ops = {
.add_virtual_intf   = qtnf_add_virtual_intf,
.change_virtual_intf= qtnf_change_virtual_intf,
@@ -859,7 +925,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
.set_default_mgmt_key   = qtnf_set_default_mgmt_key,
.scan   = qtnf_scan,
.connect= qtnf_connect,
-   .disconnect = qtnf_disconnect
+   .disconnect = qtnf_disconnect,
+   .dump_survey= qtnf_dump_survey
 };
 
 static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c 
b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index 221804f8c43a..22741bf6f4ac 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -1358,6 +1358,62 @@ static int qtnf_cmd_resp_proc_phy_params(struct 
qtnf_wmac *mac,
return 0;
 }
 
+static int
+qtnf_cmd_resp_proc_chan_stat_info(struct qtnf_chan_stats *stats,
+ const u8 *payload, size_t payload_len)
+{
+   struct qlink_chan_stats *qlink_stats;
+   const struct qlink_tlv_hdr *tlv;
+   size_t tlv_full_len;
+   u16 tlv_value_len;
+   u16 tlv_type;
+
+   tlv = (struct qlink_tlv_hdr *)payload;
+   while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
+   tlv_type = le16_to_cpu(tlv->type);
+   tlv_value_len = le16_to_cpu(tlv->len);
+   tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
+   if (tlv_full_len > payload_len) {
+   pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
+   tlv_type, tlv_value_len);
+  

[PATCH 2/8] qtnfmac: cleanup and fixes preparing AP_VLAN support

2017-06-20 Thread Sergey Matyukevich
This patch implements various cleanups and fixes aimed to
simplify adding AP_VLAN support to qtnfmac driver:

- Remove unused flag field from qlink_intf_info
- Add interface type to qlink_cmd_change_sta
- Modify qtnf_cmd_send_change_sta: add interface type to command
- Fix handling of iftype mask reported by firmware:
  Firmware sends supported interface type rather than mask. As a result,
  types field of ieee80211_iface_limit structure may end up having
  multiple iftype bits set. This leads to WARN_ON from
  wiphy_verify_combinations.

Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/commands.c  | 35 +-
 drivers/net/wireless/quantenna/qtnfmac/qlink.h |  4 +--
 .../net/wireless/quantenna/qtnfmac/qlink_util.c| 23 +++---
 .../net/wireless/quantenna/qtnfmac/qlink_util.h|  2 +-
 4 files changed, 43 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c 
b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index 2ee007ecb236..5a6caf5b685b 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -995,7 +995,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac 
*mac,
struct ieee80211_iface_limit *limits = NULL;
const struct qlink_iface_limit *limit_record;
size_t record_count = 0, rec = 0;
-   u16 tlv_type, tlv_value_len, mask;
+   u16 tlv_type, tlv_value_len;
struct qlink_iface_comb_num *comb;
size_t tlv_full_len;
const struct qlink_tlv_hdr *tlv;
@@ -1048,9 +1048,10 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac 
*mac,
 
limit_record = (void *)tlv->val;
limits[rec].max = le16_to_cpu(limit_record->max_num);
-   mask = le16_to_cpu(limit_record->type_mask);
-   limits[rec].types = qlink_iface_type_mask_to_nl(mask);
-   /* only AP and STA modes are supported */
+   limits[rec].types = qlink_iface_type_to_nl_mask(
+   le16_to_cpu(limit_record->type));
+
+   /* supported modes: STA, AP */
limits[rec].types &= BIT(NL80211_IFTYPE_AP) |
 BIT(NL80211_IFTYPE_STATION);
 
@@ -1063,6 +1064,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac 
*mac,
default:
break;
}
+
tlv_buf_size -= tlv_full_len;
tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
}
@@ -1808,10 +1810,27 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, 
const u8 *mac,
 
cmd = (struct qlink_cmd_change_sta *)cmd_skb->data;
ether_addr_copy(cmd->sta_addr, mac);
-   cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
- params->sta_flags_mask));
-   cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
-params->sta_flags_set));
+
+   switch (vif->wdev.iftype) {
+   case NL80211_IFTYPE_AP:
+   cmd->if_type = cpu_to_le16(QLINK_IFTYPE_AP);
+   cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
+ params->sta_flags_mask));
+   cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
+params->sta_flags_set));
+   break;
+   case NL80211_IFTYPE_STATION:
+   cmd->if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
+   cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
+ params->sta_flags_mask));
+   cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
+params->sta_flags_set));
+   break;
+   default:
+   pr_err("unsupported iftype %d\n", vif->wdev.iftype);
+   ret = -EINVAL;
+   goto out;
+   }
 
ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, _code);
if (unlikely(ret))
diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h 
b/drivers/net/wireless/quantenna/qtnfmac/qlink.h
index e27833b78940..8bcd8a55ad11 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h
@@ -90,7 +90,6 @@ enum qlink_iface_type {
  */
 struct qlink_intf_info {
__le16 if_type;
-   __le16 flags;
u8 mac_addr[ETH_ALEN];
u8 rsvd[2];
 } __packed;
@@ -350,6 +349,7 @@ struct qlink_cmd_change_sta {
struct qlink_cmd chdr;
__le32 sta_flags_mask;
__le32 sta_flags_set;
+   __le16 if_type;
u8 sta_addr[ETH_ALEN];
 } __packed;
 
@@ -823,7 +823,7 @@ struct qlink_tlv_hdr {
 
 struct 

[PATCH 1/8] qtnfmac: updates and fixes for regulatory support

2017-06-20 Thread Sergey Matyukevich
This patch introduces several changes for regulatory support
in qtnfmac driver:

* Introduce support for setting regdomain from host
New command is implemented to notify firmware about regdomain changes
performed by host. Firmware is supposed to check requested regdomain
changes. On success firmware enables updated hardware channel
configuration and then host driver updates channel info for each band.

* Introduce support of custom regulatory rules
Obtain custom regulatory rules from the firmware and
enable them during wiphy registration

* Regulatory for self-managed setup
Regdomain information needs to be registered with cfg80211
for devices with REGULATORY_WIPHY_SELF_MANAGED flag set.

* Misc fixes in regulatory code paths
  - add missing lock in qtnf_cmd_get_mac_chan_info
  - do not free band channel structure if channel count is the same
  - free allocated regdomain hw_info.rd structure on detach

Signed-off-by: Igor Mitsyanko 
Signed-off-by: Sergey Matyukevich 
---
 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c |  83 +++
 drivers/net/wireless/quantenna/qtnfmac/commands.c | 286 ++
 drivers/net/wireless/quantenna/qtnfmac/commands.h |   1 +
 drivers/net/wireless/quantenna/qtnfmac/core.c |   3 +
 drivers/net/wireless/quantenna/qtnfmac/core.h |   7 +-
 drivers/net/wireless/quantenna/qtnfmac/qlink.h| 126 +-
 6 files changed, 403 insertions(+), 103 deletions(-)

diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c 
b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index e3c090008125..825a6334fbfe 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -700,67 +700,45 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
.disconnect = qtnf_disconnect
 };
 
-static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy,
+static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,
   struct regulatory_request *req)
 {
-   struct qtnf_wmac *mac = wiphy_priv(wiphy);
-   struct qtnf_bus *bus;
-   struct qtnf_vif *vif;
-   struct qtnf_wmac *chan_mac;
-   int i;
+   struct qtnf_wmac *mac = wiphy_priv(wiphy_in);
+   struct wiphy *wiphy;
+   struct qtnf_bus *bus = mac->bus;
+   unsigned int mac_idx;
enum nl80211_band band;
-
-   bus = mac->bus;
+   int ret;
 
pr_debug("MAC%u: initiator=%d alpha=%c%c\n", mac->macid, req->initiator,
 req->alpha2[0], req->alpha2[1]);
 
-   vif = qtnf_mac_get_base_vif(mac);
-   if (!vif) {
-   pr_err("MAC%u: primary VIF is not configured\n", mac->macid);
-   return;
-   }
-
-   /* ignore non-ISO3166 country codes */
-   for (i = 0; i < sizeof(req->alpha2); i++) {
-   if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
-   pr_err("MAC%u: not an ISO3166 code\n", mac->macid);
-   return;
-   }
-   }
-   if (!strncasecmp(req->alpha2, bus->hw_info.alpha2_code,
-sizeof(req->alpha2))) {
-   pr_warn("MAC%u: unchanged country code\n", mac->macid);
-   return;
-   }
-
-   if (qtnf_cmd_send_regulatory_config(mac, req->alpha2)) {
-   pr_err("MAC%u: failed to configure regulatory\n", mac->macid);
+   ret = qtnf_cmd_reg_notify(bus, req);
+   if (ret) {
+   if (ret != -EOPNOTSUPP && ret != -EALREADY)
+   pr_err("failed to update reg domain to %c%c\n",
+  req->alpha2[0], req->alpha2[1]);
return;
}
 
-   for (i = 0; i < bus->hw_info.num_mac; i++) {
-   chan_mac = bus->mac[i];
-
-   if (!chan_mac)
+   for (mac_idx = 0; mac_idx < QTNF_MAX_MAC; ++mac_idx) {
+   if (!(bus->hw_info.mac_bitmap & (1 << mac_idx)))
continue;
 
-   if (!(bus->hw_info.mac_bitmap & BIT(i)))
-   continue;
+   mac = bus->mac[mac_idx];
+   wiphy = priv_to_wiphy(mac);
 
for (band = 0; band < NUM_NL80211_BANDS; ++band) {
if (!wiphy->bands[band])
continue;
 
-   if (qtnf_cmd_get_mac_chan_info(chan_mac,
-  wiphy->bands[band])) {
-   pr_err("MAC%u: can't get channel info\n",
-  chan_mac->macid);
-   qtnf_core_detach(bus);
-
-   return;
-   }
+   ret = qtnf_cmd_get_mac_chan_info(mac,
+wiphy->bands[band]);
+   if (ret)
+   

[PATCH 0/8] qtnfmac: add more features to driver

2017-06-20 Thread Sergey Matyukevich
This patch series adds more features to qtnfmac driver including
the following major pieces:
 - updates for regulatory support
 - AP/VLAN support
 - dump_survey handler
 - channel_switch handler

bus.h|1 
 cfg80211.c   |  560 +--
 cfg80211.h   |4 
 commands.c   |  515 --
 commands.h   |5 
 core.c   |   83 
 core.h   |   62 +-
 event.c  |   67 ++-
 pearl/pcie.c |5 
 qlink.h  |  201 +++--
 qlink_util.c |   26 +-
 qlink_util.h |2 
 util.c   |   74 +--
 util.h   |   34 ++-
 14 files changed, 1422 insertions(+), 217 deletions(-)


Re: [PATCH] cfg80211: Fix a memory leak in error handling path in 'brcmf_cfg80211_attach'

2017-06-20 Thread Arend van Spriel


On 20-06-17 08:22, Christophe JAILLET wrote:
> If 'wiphy_new()' fails, we leak 'ops'. Add a new label in the error
> handling path to free it in such a case.

Thanks. Please add the following tags:

Cc: sta...@vger.kernel.org
> Fixes: 5c22fb85102a7 ("brcmfmac: add wowl gtk rekeying offload support")
Acked-by: Arend van Spriel 
> Signed-off-by: Christophe JAILLET 
> ---
>  drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)


Re: pull-request: wireless-drivers 2017-06-20

2017-06-20 Thread David Miller
From: Kalle Valo 
Date: Tue, 20 Jun 2017 16:39:59 +0300

> here's a pull request to net tree, few important fixes still I would
> like to have in 4.12. Please let me know if there are any problems.

Pulled, thanks Kalle.


pull-request: wireless-drivers 2017-06-20

2017-06-20 Thread Kalle Valo
Hi Dave,

here's a pull request to net tree, few important fixes still I would
like to have in 4.12. Please let me know if there are any problems.

Kalle

The following changes since commit dc89481bb4c9af0700423e21c8371379d3d943b1:

  Merge tag 'iwlwifi-for-kalle-2017-06-05' of 
git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes (2017-06-05 
22:21:25 +0300)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git 
tags/wireless-drivers-for-davem-2017-06-20

for you to fetch changes up to 35abcd4f9f303ac4f10f99b3f7e993e5f2e6fa37:

  brcmfmac: fix uninitialized warning in brcmf_usb_probe_phase2() (2017-06-16 
11:52:36 +0300)


wireless-drivers fixes for 4.12

Two important fixes for brcmfmac. The rest of the brcmfmac patches are
either code preparation and fixing a new build warning.

brcmfmac

* fix a NULL pointer dereference during resume

* fix a NULL pointer dereference with USB devices, a regression from
  v4.12-rc1


Arend Van Spriel (5):
  brcmfmac: add parameter to pass error code in firmware callback
  brcmfmac: use firmware callback upon failure to load
  brcmfmac: unbind all devices upon failure in firmware callback
  brcmfmac: fix brcmf_fws_add_interface() for USB devices
  brcmfmac: fix uninitialized warning in brcmf_usb_probe_phase2()

 .../broadcom/brcm80211/brcmfmac/firmware.c | 35 +++---
 .../broadcom/brcm80211/brcmfmac/firmware.h |  4 +--
 .../broadcom/brcm80211/brcmfmac/fwsignal.c |  2 +-
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c| 17 +++
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c| 18 +++
 .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |  9 +++---
 6 files changed, 49 insertions(+), 36 deletions(-)


Re: [PATCH 2/6] rsi: use enum for FSM states

2017-06-20 Thread Amitkumar Karwar
On Mon, Jun 19, 2017 at 8:49 PM, Kalle Valo  wrote:
> Amitkumar Karwar  writes:
>
>> On Thu, Jun 15, 2017 at 8:14 PM, Kalle Valo  wrote:
>>> Amitkumar Karwar  writes:
>>>
 On Wed, Jun 14, 2017 at 2:43 PM, Kalle Valo  wrote:
> amit karwar  writes:
>
>> On Tue, Jun 13, 2017 at 12:17 PM, Kalle Valo  
>> wrote:
>>
>>> Also your name in patchwork is not capitalised (patchwork is idiotic and
>>> takes the name from patchwork user data and not from the patch):
>>>
>>>   [1/6] rsi: add usb RS9113 chipset support 2017-06-02 amit
>>> karwar New
>>>   [2/6] rsi: use enum for FSM states 2017-06-02 amit karwar New
>>>   [3/6] rsi: Register interrupt handler before firmware load
>>> 2017-06-02 amit karwar New
>>>   [4/6] rsi: receive path enhancement for RS9113 2017-06-02 amit
>>> karwar New
>>>   [5/6] rsi: configure new boot parameters to device 2017-06-02
>>> amit karwar New
>>>   [6/6] rsi: add tx frame for common device configuration
>>> 2017-06-02 amit karwar New
>>>
>>> To fix that could you please register to patchwork and capitalise your
>>> name correctly? You have only one chance, patchwork doesn't allow users
>>> edit the name afterwards, so don't do any typos :)
>>
>> Thanks. I have registered with patchwork and corrected my name.
>
> What address did you use? Patchwork still shows your name all lower:
>
> https://patchwork.kernel.org/project/linux-wireless/list/?submitter=173645
>
> I suspect you didn't register with gmail.com, but with some other
> address. I recommend that you link all your email addresses, including
> gmail.com, to the same patchwork account and hopefully that fixes it.
> You should be able to do that from the profile page in patchwork.

 I had registered with my gmail id. Also, other email id has also been
 linked to patchwork. But still patchwork took previous user name.
 I could not find a way to check my name in patchwork database after
 login. I have now corrected my display name in gmail's setting.
>>>
>>> Good, thanks. This name format bug in patchwork is really annoying, I'm
>>> suffering from frequently. Let's see how your next submission goes and
>>> hopefully we can sort it out.
>>
>> I just submitted a patch series. But patchwork is still showing older name.
>
> I think the best is that you now report this to kernel.org admins:
>
> https://korg.wiki.kernel.org/userdoc/support
>
> Hopefully they can easily fix it directly in the database.
>

Thanks for the pointers. I have dropped an email to helpdesk for this issue.


Re: [PATCH] cfg80211: Fix a memory leak in error handling path in 'brcmf_cfg80211_attach'

2017-06-20 Thread Kalle Valo
Christophe JAILLET  writes:

> If 'wiphy_new()' fails, we leak 'ops'. Add a new label in the error
> handling path to free it in such a case.
>
> Fixes: 5c22fb85102a7 ("brcmfmac: add wowl gtk rekeying offload support")
> Signed-off-by: Christophe JAILLET 

The prefix should be "brcmfmac:", like in the commit you are fixing.
"cfg80211:" is very misleading.

-- 
Kalle Valo