All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/2] ath10k: Add QCA vendor command/attr support to filter neighbor BSS frames
@ 2018-07-05 11:51 ` Karthikeyan Periyasamy
  0 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-07-05 11:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Karthikeyan Periyasamy

Allow AP to receive neighbor BSSs frames and user-space can get the
statistics of the stations associated with neighbor BSSs.

User-space can use QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER command to configure
RX filter to receive frames from stations that are active on the operating
channel, but not associated with the local device (e.g., STAs associated with
neighbor APs). Filtering is done based on a list of BSSIDs and STA MAC addresses
added by the user. This command is also used to fetch statistics of unassociated
stations. The attributes used with this command are defined in enum
qca_wlan_vendor_attr_bss_filter.

User can add/delete the filter by specifying the BSSID/STA MAC address in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type as BSSID/STA in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE and add/delete action in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION using the QCA vendor command
QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.

User can get the statistics of an unassociated station by specifying the MAC
address in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION using the QCA vendor command
QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER. User can also get the statistics of all
unassociated stations by specifying the Broadcast MAC address (ff:ff:ff:ff:ff:ff)
in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with above procedure. In response,
ath10k driver specify statistics information nested in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.

NOTE: Tested with debug firmware

Karthikeyan Periyasamy (2):
  ath10k: add wmi interface for vdev_set_neighbor_rx_param
  ath10k: Add QCA vendor command/attr support to filter neighbor BSS
    frames

 drivers/net/wireless/ath/ath10k/Makefile  |   3 +-
 drivers/net/wireless/ath/ath10k/core.h    |   3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c  |   5 +
 drivers/net/wireless/ath/ath10k/mac.c     |  15 +-
 drivers/net/wireless/ath/ath10k/vendor.c  | 770 ++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/vendor.h  | 289 +++++++++++
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  28 +-
 drivers/net/wireless/ath/ath10k/wmi.c     |  33 ++
 drivers/net/wireless/ath/ath10k/wmi.h     |  76 +++
 9 files changed, 1219 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.c
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [RFC 0/2] ath10k: Add QCA vendor command/attr support to filter neighbor BSS frames
@ 2018-07-05 11:51 ` Karthikeyan Periyasamy
  0 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-07-05 11:51 UTC (permalink / raw)
  To: ath10k; +Cc: Karthikeyan Periyasamy, linux-wireless

Allow AP to receive neighbor BSSs frames and user-space can get the
statistics of the stations associated with neighbor BSSs.

User-space can use QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER command to configure
RX filter to receive frames from stations that are active on the operating
channel, but not associated with the local device (e.g., STAs associated with
neighbor APs). Filtering is done based on a list of BSSIDs and STA MAC addresses
added by the user. This command is also used to fetch statistics of unassociated
stations. The attributes used with this command are defined in enum
qca_wlan_vendor_attr_bss_filter.

User can add/delete the filter by specifying the BSSID/STA MAC address in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type as BSSID/STA in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE and add/delete action in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION using the QCA vendor command
QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.

User can get the statistics of an unassociated station by specifying the MAC
address in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION using the QCA vendor command
QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER. User can also get the statistics of all
unassociated stations by specifying the Broadcast MAC address (ff:ff:ff:ff:ff:ff)
in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with above procedure. In response,
ath10k driver specify statistics information nested in
QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.

NOTE: Tested with debug firmware

Karthikeyan Periyasamy (2):
  ath10k: add wmi interface for vdev_set_neighbor_rx_param
  ath10k: Add QCA vendor command/attr support to filter neighbor BSS
    frames

 drivers/net/wireless/ath/ath10k/Makefile  |   3 +-
 drivers/net/wireless/ath/ath10k/core.h    |   3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c  |   5 +
 drivers/net/wireless/ath/ath10k/mac.c     |  15 +-
 drivers/net/wireless/ath/ath10k/vendor.c  | 770 ++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/vendor.h  | 289 +++++++++++
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  28 +-
 drivers/net/wireless/ath/ath10k/wmi.c     |  33 ++
 drivers/net/wireless/ath/ath10k/wmi.h     |  76 +++
 9 files changed, 1219 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.c
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.h

-- 
1.9.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [RFC 1/2] ath10k: add wmi interface for vdev_set_neighbor_rx_param
  2018-07-05 11:51 ` Karthikeyan Periyasamy
@ 2018-07-05 11:51   ` Karthikeyan Periyasamy
  -1 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-07-05 11:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Karthikeyan Periyasamy

Add WMI command interface support for receiving neighbor BSS frames from
the target. QCA9984, QCA4019 and QCA9888 support this WMI command with the
capability advertisement through wmi service map.

Hardware tested: QCA9984, QCA4019 and QCA9888
Firmware tested: 10.4-3.6-xxxxx

NOTE: Tested with debug firmware

Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/wmi-ops.h | 28 +++++++++++-
 drivers/net/wireless/ath/ath10k/wmi.c     | 33 ++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     | 76 +++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 5ecce04..8444b41 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -214,7 +214,12 @@ struct wmi_ops {
 	struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
 	struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
 							u32 param);
-
+	struct sk_buff *(*gen_vdev_set_neighbor_rx_param)(struct ath10k *ar,
+							  u32 vdev_id,
+							  const u8 *addr,
+							  u32 idx,
+							  u32 action,
+							  u32 type);
 };
 
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1543,4 +1548,25 @@ struct wmi_ops {
 				   ar->wmi.cmd->radar_found_cmdid);
 }
 
+static inline int
+ath10k_wmi_set_neighbor_rx_param(struct ath10k *ar, u32 vdev_id,
+				 const u8 *addr, u32 idx,
+				 u32 action, u32 type)
+{
+	struct sk_buff *skb;
+	u32 cmdid;
+
+	if (!ar->wmi.ops->gen_vdev_set_neighbor_rx_param)
+		return -EOPNOTSUPP;
+
+	cmdid = ar->wmi.cmd->vdev_filter_neighbor_rx_packets_cmdid;
+	skb = ar->wmi.ops->gen_vdev_set_neighbor_rx_param(ar,
+							  vdev_id, addr,
+							  idx, action, type);
+
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 877249a..fe62489 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -8662,6 +8662,37 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
 	return 0;
 }
 
+static struct sk_buff *
+ath10k_wmi_10_4_op_gen_vdev_set_neighbor_rx_param(struct ath10k *ar,
+						  u32 vdev_id,
+						  const u8 *addr,
+						  u32 idx, u32 action,
+						  u32 type)
+{
+	struct wmi_set_vdev_filter_nrp_10_4_cmd *cmd;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	cmd = (struct wmi_set_vdev_filter_nrp_10_4_cmd *)skb->data;
+
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->action = __cpu_to_le32(action);
+	cmd->type = __cpu_to_le32(type);
+	cmd->idx = __cpu_to_le32(idx);
+
+	ether_addr_copy(cmd->macaddr.addr, addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "vdev id:0x%x Macaddr[0x%x]:[0x%x] idx:0x%x action:0x%x type:0x%x flag:0x%x\n",
+		   cmd->vdev_id, cmd->macaddr.addr[0], cmd->macaddr.addr[5],
+		   cmd->idx, cmd->action, cmd->type, cmd->flag);
+
+	return skb;
+}
+
 static const struct wmi_ops wmi_ops = {
 	.rx = ath10k_wmi_op_rx,
 	.map_svc = wmi_main_svc_map,
@@ -9014,6 +9045,8 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
 	.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
 	.gen_echo = ath10k_wmi_op_gen_echo,
 	.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
+	.gen_vdev_set_neighbor_rx_param =
+		ath10k_wmi_10_4_op_gen_vdev_set_neighbor_rx_param,
 };
 
 int ath10k_wmi_attach(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index d68afb6..bc53d4c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -203,6 +203,13 @@ enum wmi_service {
 	WMI_SERVICE_TPC_STATS_FINAL,
 	WMI_SERVICE_RESET_CHIP,
 	WMI_SERVICE_SPOOF_MAC_SUPPORT,
+	WMI_SERVICE_CFR_CAPTURE_SUPPORT,
+	WMI_SERVICE_TX_DATA_ACK_RSSI,
+	WMI_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY,
+	WMI_SERVICE_PER_PACKET_SW_ENCRYPT,
+	WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+	WMI_SERVICE_VDEV_BCN_RATE_CONTROL,
+	WMI_SERVICE_VDEV_FILTER_NEIGHBOR,
 
 	/* keep last */
 	WMI_SERVICE_MAX,
@@ -350,6 +357,13 @@ enum wmi_10_4_service {
 	WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
 	WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
 	WMI_10_4_SERVICE_TPC_STATS_FINAL,
+	WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT,
+	WMI_10_4_SERVICE_TX_DATA_ACK_RSSI,
+	WMI_10_4_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY,
+	WMI_10_4_SERVICE_PER_PACKET_SW_ENCRYPT,
+	WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+	WMI_10_4_SERVICE_VDEV_BCN_RATE_CONTROL,
+	WMI_10_4_SERVICE_VDEV_FILTER_NEIGHBOR,
 };
 
 static inline char *wmi_service_name(int service_id)
@@ -462,6 +476,15 @@ static inline char *wmi_service_name(int service_id)
 	SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
 	SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
 	SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
+	SVCSTR(WMI_SERVICE_RESET_CHIP);
+	SVCSTR(WMI_SERVICE_CFR_CAPTURE_SUPPORT);
+	SVCSTR(WMI_SERVICE_TX_DATA_ACK_RSSI);
+	SVCSTR(WMI_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY);
+	SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT);
+	SVCSTR(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT);
+	SVCSTR(WMI_SERVICE_VDEV_BCN_RATE_CONTROL);
+	SVCSTR(WMI_SERVICE_VDEV_FILTER_NEIGHBOR);
+
 	default:
 		return NULL;
 	}
@@ -770,6 +793,20 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
 	       WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
 	SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
 	       WMI_SERVICE_TPC_STATS_FINAL, len);
+	SVCMAP(WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT,
+	       WMI_SERVICE_CFR_CAPTURE_SUPPORT, len);
+	SVCMAP(WMI_10_4_SERVICE_TX_DATA_ACK_RSSI,
+	       WMI_SERVICE_TX_DATA_ACK_RSSI, len);
+	SVCMAP(WMI_10_4_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY,
+	       WMI_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY, len);
+	SVCMAP(WMI_10_4_SERVICE_PER_PACKET_SW_ENCRYPT,
+	       WMI_SERVICE_PER_PACKET_SW_ENCRYPT, len);
+	SVCMAP(WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+	       WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, len);
+	SVCMAP(WMI_10_4_SERVICE_VDEV_BCN_RATE_CONTROL,
+	       WMI_SERVICE_VDEV_BCN_RATE_CONTROL, len);
+	SVCMAP(WMI_10_4_SERVICE_VDEV_FILTER_NEIGHBOR,
+	       WMI_SERVICE_VDEV_FILTER_NEIGHBOR, len);
 }
 
 #undef SVCMAP
@@ -7028,6 +7065,45 @@ struct wmi_pdev_chan_info_req_cmd {
 	__le32 reserved;
 } __packed;
 
+/* enum wmi_neighbor_rx_action - Neighbor Rx Packets add/remove filter */
+enum wmi_neighbor_rx_action {
+	WMI_NEIGHBOR_RX_ACTION_ADD = 1,
+	WMI_NEIGHBOR_RX_ACTION_DEL,
+};
+
+/* enum wmi_neighbor_rx_type - Neighbor Rx Packets ap/client addr */
+enum wmi_neighbor_rx_type {
+	WMI_NEIGHBOR_RX_TYPE_BSSID = 1,
+	WMI_NEIGHBOR_RX_TYPE_CLIENT,
+};
+
+/* enum wmi_neighbor_rx_capture_flag - Neighbor Rx Packets flags */
+enum wmi_neighbor_rx_capture_flag {
+	WMI_NEIGHBOR_RX_CAPTURE_ONLY_RX_PKT = 1,
+	WMI_NEIGHBOR_RX_CAPTURE_ONLY_TX_PKT,
+	WMI_NEIGHBOR_RX_CAPTURE_BOTH_TXRX_PKT
+};
+
+/* Filter for Neighbor Rx Packets  */
+struct wmi_set_vdev_filter_nrp_10_4_cmd {
+	__le32 vdev_id;
+
+	/* AP Bssid or Client Mac-addr */
+	struct wmi_mac_addr macaddr;
+
+	/* see enum wmi_neighbor_rx_action */
+	__le32 action;
+
+	/* see enum wmi_neighbor_rx_type */
+	__le32 type;
+
+	/* enum wmi_neighbor_rx_capture_flag */
+	__le32 flag;
+
+	/* BSSID index - index of the BSSID register */
+	__le32 idx;
+} __packed;
+
 struct ath10k;
 struct ath10k_vif;
 struct ath10k_fw_stats_pdev;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC 1/2] ath10k: add wmi interface for vdev_set_neighbor_rx_param
@ 2018-07-05 11:51   ` Karthikeyan Periyasamy
  0 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-07-05 11:51 UTC (permalink / raw)
  To: ath10k; +Cc: Karthikeyan Periyasamy, linux-wireless

Add WMI command interface support for receiving neighbor BSS frames from
the target. QCA9984, QCA4019 and QCA9888 support this WMI command with the
capability advertisement through wmi service map.

Hardware tested: QCA9984, QCA4019 and QCA9888
Firmware tested: 10.4-3.6-xxxxx

NOTE: Tested with debug firmware

Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/wmi-ops.h | 28 +++++++++++-
 drivers/net/wireless/ath/ath10k/wmi.c     | 33 ++++++++++++++
 drivers/net/wireless/ath/ath10k/wmi.h     | 76 +++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 5ecce04..8444b41 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -214,7 +214,12 @@ struct wmi_ops {
 	struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
 	struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
 							u32 param);
-
+	struct sk_buff *(*gen_vdev_set_neighbor_rx_param)(struct ath10k *ar,
+							  u32 vdev_id,
+							  const u8 *addr,
+							  u32 idx,
+							  u32 action,
+							  u32 type);
 };
 
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1543,4 +1548,25 @@ struct wmi_ops {
 				   ar->wmi.cmd->radar_found_cmdid);
 }
 
+static inline int
+ath10k_wmi_set_neighbor_rx_param(struct ath10k *ar, u32 vdev_id,
+				 const u8 *addr, u32 idx,
+				 u32 action, u32 type)
+{
+	struct sk_buff *skb;
+	u32 cmdid;
+
+	if (!ar->wmi.ops->gen_vdev_set_neighbor_rx_param)
+		return -EOPNOTSUPP;
+
+	cmdid = ar->wmi.cmd->vdev_filter_neighbor_rx_packets_cmdid;
+	skb = ar->wmi.ops->gen_vdev_set_neighbor_rx_param(ar,
+							  vdev_id, addr,
+							  idx, action, type);
+
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 877249a..fe62489 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -8662,6 +8662,37 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
 	return 0;
 }
 
+static struct sk_buff *
+ath10k_wmi_10_4_op_gen_vdev_set_neighbor_rx_param(struct ath10k *ar,
+						  u32 vdev_id,
+						  const u8 *addr,
+						  u32 idx, u32 action,
+						  u32 type)
+{
+	struct wmi_set_vdev_filter_nrp_10_4_cmd *cmd;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	cmd = (struct wmi_set_vdev_filter_nrp_10_4_cmd *)skb->data;
+
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->action = __cpu_to_le32(action);
+	cmd->type = __cpu_to_le32(type);
+	cmd->idx = __cpu_to_le32(idx);
+
+	ether_addr_copy(cmd->macaddr.addr, addr);
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "vdev id:0x%x Macaddr[0x%x]:[0x%x] idx:0x%x action:0x%x type:0x%x flag:0x%x\n",
+		   cmd->vdev_id, cmd->macaddr.addr[0], cmd->macaddr.addr[5],
+		   cmd->idx, cmd->action, cmd->type, cmd->flag);
+
+	return skb;
+}
+
 static const struct wmi_ops wmi_ops = {
 	.rx = ath10k_wmi_op_rx,
 	.map_svc = wmi_main_svc_map,
@@ -9014,6 +9045,8 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
 	.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
 	.gen_echo = ath10k_wmi_op_gen_echo,
 	.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
+	.gen_vdev_set_neighbor_rx_param =
+		ath10k_wmi_10_4_op_gen_vdev_set_neighbor_rx_param,
 };
 
 int ath10k_wmi_attach(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index d68afb6..bc53d4c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -203,6 +203,13 @@ enum wmi_service {
 	WMI_SERVICE_TPC_STATS_FINAL,
 	WMI_SERVICE_RESET_CHIP,
 	WMI_SERVICE_SPOOF_MAC_SUPPORT,
+	WMI_SERVICE_CFR_CAPTURE_SUPPORT,
+	WMI_SERVICE_TX_DATA_ACK_RSSI,
+	WMI_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY,
+	WMI_SERVICE_PER_PACKET_SW_ENCRYPT,
+	WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+	WMI_SERVICE_VDEV_BCN_RATE_CONTROL,
+	WMI_SERVICE_VDEV_FILTER_NEIGHBOR,
 
 	/* keep last */
 	WMI_SERVICE_MAX,
@@ -350,6 +357,13 @@ enum wmi_10_4_service {
 	WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
 	WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
 	WMI_10_4_SERVICE_TPC_STATS_FINAL,
+	WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT,
+	WMI_10_4_SERVICE_TX_DATA_ACK_RSSI,
+	WMI_10_4_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY,
+	WMI_10_4_SERVICE_PER_PACKET_SW_ENCRYPT,
+	WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+	WMI_10_4_SERVICE_VDEV_BCN_RATE_CONTROL,
+	WMI_10_4_SERVICE_VDEV_FILTER_NEIGHBOR,
 };
 
 static inline char *wmi_service_name(int service_id)
@@ -462,6 +476,15 @@ static inline char *wmi_service_name(int service_id)
 	SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
 	SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
 	SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
+	SVCSTR(WMI_SERVICE_RESET_CHIP);
+	SVCSTR(WMI_SERVICE_CFR_CAPTURE_SUPPORT);
+	SVCSTR(WMI_SERVICE_TX_DATA_ACK_RSSI);
+	SVCSTR(WMI_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY);
+	SVCSTR(WMI_SERVICE_PER_PACKET_SW_ENCRYPT);
+	SVCSTR(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT);
+	SVCSTR(WMI_SERVICE_VDEV_BCN_RATE_CONTROL);
+	SVCSTR(WMI_SERVICE_VDEV_FILTER_NEIGHBOR);
+
 	default:
 		return NULL;
 	}
@@ -770,6 +793,20 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
 	       WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
 	SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
 	       WMI_SERVICE_TPC_STATS_FINAL, len);
+	SVCMAP(WMI_10_4_SERVICE_CFR_CAPTURE_SUPPORT,
+	       WMI_SERVICE_CFR_CAPTURE_SUPPORT, len);
+	SVCMAP(WMI_10_4_SERVICE_TX_DATA_ACK_RSSI,
+	       WMI_SERVICE_TX_DATA_ACK_RSSI, len);
+	SVCMAP(WMI_10_4_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY,
+	       WMI_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_LAGACY, len);
+	SVCMAP(WMI_10_4_SERVICE_PER_PACKET_SW_ENCRYPT,
+	       WMI_SERVICE_PER_PACKET_SW_ENCRYPT, len);
+	SVCMAP(WMI_10_4_SERVICE_PEER_TID_CONFIGS_SUPPORT,
+	       WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, len);
+	SVCMAP(WMI_10_4_SERVICE_VDEV_BCN_RATE_CONTROL,
+	       WMI_SERVICE_VDEV_BCN_RATE_CONTROL, len);
+	SVCMAP(WMI_10_4_SERVICE_VDEV_FILTER_NEIGHBOR,
+	       WMI_SERVICE_VDEV_FILTER_NEIGHBOR, len);
 }
 
 #undef SVCMAP
@@ -7028,6 +7065,45 @@ struct wmi_pdev_chan_info_req_cmd {
 	__le32 reserved;
 } __packed;
 
+/* enum wmi_neighbor_rx_action - Neighbor Rx Packets add/remove filter */
+enum wmi_neighbor_rx_action {
+	WMI_NEIGHBOR_RX_ACTION_ADD = 1,
+	WMI_NEIGHBOR_RX_ACTION_DEL,
+};
+
+/* enum wmi_neighbor_rx_type - Neighbor Rx Packets ap/client addr */
+enum wmi_neighbor_rx_type {
+	WMI_NEIGHBOR_RX_TYPE_BSSID = 1,
+	WMI_NEIGHBOR_RX_TYPE_CLIENT,
+};
+
+/* enum wmi_neighbor_rx_capture_flag - Neighbor Rx Packets flags */
+enum wmi_neighbor_rx_capture_flag {
+	WMI_NEIGHBOR_RX_CAPTURE_ONLY_RX_PKT = 1,
+	WMI_NEIGHBOR_RX_CAPTURE_ONLY_TX_PKT,
+	WMI_NEIGHBOR_RX_CAPTURE_BOTH_TXRX_PKT
+};
+
+/* Filter for Neighbor Rx Packets  */
+struct wmi_set_vdev_filter_nrp_10_4_cmd {
+	__le32 vdev_id;
+
+	/* AP Bssid or Client Mac-addr */
+	struct wmi_mac_addr macaddr;
+
+	/* see enum wmi_neighbor_rx_action */
+	__le32 action;
+
+	/* see enum wmi_neighbor_rx_type */
+	__le32 type;
+
+	/* enum wmi_neighbor_rx_capture_flag */
+	__le32 flag;
+
+	/* BSSID index - index of the BSSID register */
+	__le32 idx;
+} __packed;
+
 struct ath10k;
 struct ath10k_vif;
 struct ath10k_fw_stats_pdev;
-- 
1.9.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC 2/2] ath10k: Add QCA vendor command/attr support to filter neighbor BSS frames
  2018-07-05 11:51 ` Karthikeyan Periyasamy
@ 2018-07-05 11:51   ` Karthikeyan Periyasamy
  -1 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-07-05 11:51 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Karthikeyan Periyasamy

Add operations to allow an AP to capture frames from stations that
are active on the operating channel, but not associated to the current AP.
Operations include add/delete the filter and get the statistics
information of the unassociated stations.

User can able to add/delete two type of filters,
	1. BSSID
	2. STA MAC address

BSSID filter achieved by HW through vdev_set_neighbor_rx_param WMI command.
Local device able to capture all frames of the specified BSS using the above
WMI command. STA filter achieved by SW through RX addr2 matching with
unassociated station rhash table list keyed by MAC address. rhash table used
for efficient search. rhash table can grow/shrink by the add/delete STA
filter request.

Hardware tested: QCA9984, QCA4019 and QCA9888
Firmware tested: 10.4-3.6-xxxxx

NOTE: Tested with debug firmware

Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/Makefile |   3 +-
 drivers/net/wireless/ath/ath10k/core.h   |   3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c |   5 +
 drivers/net/wireless/ath/ath10k/mac.c    |  15 +-
 drivers/net/wireless/ath/ath10k/vendor.c | 770 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/vendor.h | 289 ++++++++++++
 6 files changed, 1083 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.c
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.h

diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 44d60a6..65d824d 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -13,7 +13,8 @@ ath10k_core-y += mac.o \
 		 bmi.o \
 		 hw.o \
 		 p2p.o \
-		 swap.o
+		 swap.o \
+		 vendor.o
 
 ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o
 ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 427ee57..a723028 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -38,6 +38,7 @@
 #include "thermal.h"
 #include "wow.h"
 #include "swap.h"
+#include "vendor.h"
 
 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -1132,6 +1133,8 @@ struct ath10k {
 	struct ath10k_radar_found_info last_radar_info;
 	struct work_struct radar_confirmation_work;
 
+	struct ath10k_vendor vendor;
+
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 4d1cd90..e30ffad 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -23,6 +23,7 @@
 #include "debug.h"
 #include "trace.h"
 #include "mac.h"
+#include "vendor.h"
 
 #include <linux/log2.h>
 #include <linux/bitfield.h>
@@ -1773,6 +1774,10 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
 		return false;
 	}
 
+	/* Do the Neighbor BSSID filter if configured */
+	if (ath10k_vendor_rx_h_bssid_filter(&ar->vendor, amsdu, rx_status))
+		return false;
+
 	return true;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 95243b4..05c8c4f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5313,6 +5313,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 
 	mutex_lock(&ar->conf_mutex);
 
+	ath10k_vendor_bss_filter_cleanup(arvif);
+
 	spin_lock_bh(&ar->data_lock);
 	ath10k_mac_vif_beacon_cleanup(arvif);
 	spin_unlock_bh(&ar->data_lock);
@@ -8518,10 +8520,16 @@ int ath10k_mac_register(struct ath10k *ar)
 
 	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
 
+	ret = ath10k_vendor_register(ar);
+	if (ret) {
+		ath10k_err(ar, "failed to register vendor: %d\n", ret);
+		goto err_dfs_detector_exit;
+	}
+
 	ret = ieee80211_register_hw(ar->hw);
 	if (ret) {
 		ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
-		goto err_dfs_detector_exit;
+		goto err_vendor_unregister;
 	}
 
 	if (!ath_is_world_regd(&ar->ath_common.regulatory)) {
@@ -8536,6 +8544,9 @@ int ath10k_mac_register(struct ath10k *ar)
 err_unregister:
 	ieee80211_unregister_hw(ar->hw);
 
+err_vendor_unregister:
+	ath10k_vendor_unregister(ar);
+
 err_dfs_detector_exit:
 	if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
 		ar->dfs_detector->exit(ar->dfs_detector);
@@ -8552,6 +8563,8 @@ void ath10k_mac_unregister(struct ath10k *ar)
 {
 	ieee80211_unregister_hw(ar->hw);
 
+	ath10k_vendor_unregister(ar);
+
 	if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
 		ar->dfs_detector->exit(ar->dfs_detector);
 
diff --git a/drivers/net/wireless/ath/ath10k/vendor.c b/drivers/net/wireless/ath/ath10k/vendor.c
new file mode 100644
index 0000000..a6687d2
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/vendor.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <net/netlink.h>
+#include <net/mac80211.h>
+
+#include "core.h"
+#include "wmi-ops.h"
+#include "debug.h"
+
+static int ath10k_vendor_bss_filter_vendor_handler(struct wiphy *wiphy,
+						   struct wireless_dev *wdev,
+						   const void *data,
+						   int data_len);
+
+static const struct nla_policy
+ath10k_vendor_bss_filter_policy[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR] = { .len = ETH_ALEN },
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS] = { .type = NLA_NESTED },
+};
+
+static struct wiphy_vendor_command ath10k_vendor_commands[] = {
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = ath10k_vendor_bss_filter_vendor_handler,
+	}
+};
+
+static u32
+ath10k_vendor_unassoc_sta_table_hash(const void *addr, u32 len, u32 seed)
+{
+	/* Use last four bytes of hw addr as hash index */
+	return jhash_1word(*(u32 *)(addr + 2), seed);
+}
+
+static const struct rhashtable_params ath10k_vendor_unassoc_sta_rht = {
+	.nelem_hint = 2,
+	.automatic_shrinking = true,
+	.key_len = ETH_ALEN,
+	.key_offset = offsetof(struct ath10k_vendor_unassoc_sta, stats.addr),
+	.head_offset = offsetof(struct ath10k_vendor_unassoc_sta, rhash),
+	.hashfn = ath10k_vendor_unassoc_sta_table_hash,
+};
+
+struct ath10k_vendor_unassoc_sta *
+ath10k_vendor_unassoc_sta_lookup(struct ath10k_vendor_unassoc_sta_tbl *tbl,
+				 u8 *addr)
+{
+	return rhashtable_lookup_fast(&tbl->rhead,
+				      addr, ath10k_vendor_unassoc_sta_rht);
+}
+
+static u8 ath10k_vendor_bssid_filter_get_free_idx(struct ath10k *ar, u8 *addr)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	u8 idx = ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX, loop = 0;
+
+	while (loop < ar->vendor.bss_filter.max) {
+		bssid = &ar->vendor.bss_filter.bssid[loop];
+
+		/* check given MAC already configured */
+		if (addr && !is_zero_ether_addr(addr)) {
+			if (memcmp(bssid->addr, addr, ETH_ALEN) == 0) {
+				idx = loop;
+				break;
+			}
+		}
+
+		/* Get the least free index */
+		if (idx == ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX &&
+		    is_zero_ether_addr(bssid->addr)) {
+			idx = loop;
+		}
+
+		loop++;
+	}
+	return idx;
+}
+
+static int ath10k_vendor_bssid_filter_add(struct ath10k *ar, u8 *addr,
+					  u32 vdev_id)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	int ret;
+	u8 idx;
+
+	/* If monitor started then no point to enable other bss filter */
+	if (ar->monitor_started) {
+		ath10k_warn(ar, "not able to enable other bss filter if monitor alive\n");
+		return -EBUSY;
+	}
+
+	idx = ath10k_vendor_bssid_filter_get_free_idx(ar, addr);
+	if (idx == ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX) {
+		ath10k_warn(ar, "No Free idx to add BSS filter\n");
+		return -EBUSY;
+	}
+
+	bssid = &ar->vendor.bss_filter.bssid[idx];
+
+	/* If valid MAC already configured in the given index, check both are
+	 * same one or not. If its same, just add the reference count
+	 * otherwise throw error.
+	 */
+	if (!is_zero_ether_addr(bssid->addr)) {
+		if (memcmp(bssid->addr, addr, ETH_ALEN) != 0) {
+			ath10k_warn(ar, "Already used idx %d\n", idx);
+			return -EINVAL;
+		}
+		goto add_ref;
+	}
+
+	/* Send wmi message to receive the given BSSID frames, zeroth
+	 * index is reserved so we cannot use that index.
+	 */
+	ret = ath10k_wmi_set_neighbor_rx_param(ar, vdev_id,
+					       addr, idx + 1,
+					       WMI_NEIGHBOR_RX_ACTION_ADD,
+					       WMI_NEIGHBOR_RX_TYPE_BSSID);
+	if (ret) {
+		ath10k_warn(ar, "BSS Add Filter failed on idx %d addr %pM\n",
+			    idx, addr);
+		return ret;
+	}
+
+	ether_addr_copy(bssid->addr, addr);
+
+	spin_lock_bh(&ar->data_lock);
+	ar->vendor.bss_filter.n_bssid++;
+	spin_unlock_bh(&ar->data_lock);
+
+add_ref:
+	/*If the VAP already configured, then no need to add reference count */
+	if (!(bssid->vdev_map & (1LL << vdev_id))) {
+		bssid->ref++;
+		bssid->vdev_map |= 1LL << vdev_id;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Filter added vdev %d idx %d addr %pM\n",
+		   vdev_id, idx, addr);
+	return 0;
+}
+
+static int ath10k_vendor_bssid_filter_delete(struct ath10k *ar, u8 *addr,
+					     u8 idx, u32 vdev_id)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	int ret;
+
+	if (idx >= ar->vendor.bss_filter.max) {
+		ath10k_warn(ar, "Invalid idx %d\n", idx);
+		return -EINVAL;
+	}
+
+	bssid = ar->vendor.bss_filter.bssid;
+	/* Check this bssid filter configured by the given VAP */
+	if (!(bssid[idx].vdev_map & (1LL << vdev_id))) {
+		ath10k_warn(ar, "BSS Filter addr %pM not configured by vdev %d\n",
+			    addr, vdev_id);
+		return -EINVAL;
+	}
+
+	bssid[idx].ref--;
+	bssid[idx].vdev_map &= ~(1LL << vdev_id);
+
+	/* If no reference count, then Send wmi message to not receive
+	 * the given BSSID frames, zeroth index is reserved so we cannot
+	 * use that index.
+	 */
+	if (!bssid[idx].ref) {
+		ret = ath10k_wmi_set_neighbor_rx_param(ar,
+						       vdev_id,
+						       addr, idx + 1,
+						       WMI_NEIGHBOR_RX_ACTION_DEL,
+						       WMI_NEIGHBOR_RX_TYPE_BSSID);
+		if (ret) {
+			ath10k_warn(ar, "wmi filter delete failed ret %d\n", ret);
+			bssid[idx].ref++;
+			bssid[idx].vdev_map &= ~(1LL << vdev_id);
+			return ret;
+		}
+
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "Filter deleted vdev %d addr %pM\n",
+			   vdev_id, addr);
+
+		memset(bssid[idx].addr, 0, ETH_ALEN);
+
+		spin_lock_bh(&ar->data_lock);
+		ar->vendor.bss_filter.n_bssid--;
+		spin_unlock_bh(&ar->data_lock);
+	}
+
+	return ret;
+}
+
+static int
+ath10k_vendor_bssid_filter_action(struct ath10k *ar,
+				  u8 *addr,
+				  enum qca_wlan_vendor_bss_filter_type type,
+				  enum qca_wlan_vendor_bss_filter_action action,
+				  u32 vdev_id)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	int ret;
+	u8 loop, idx = ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX;
+
+	if (!is_valid_ether_addr(addr))
+		return -EINVAL;
+
+	if (action == QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD) {
+		ret = ath10k_vendor_bssid_filter_add(ar, addr, vdev_id);
+	} else if (action == QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL) {
+		if (!ar->vendor.bss_filter.n_bssid) {
+			ath10k_warn(ar, "No BSS Filter to delete\n");
+			return -EINVAL;
+		}
+
+		bssid = ar->vendor.bss_filter.bssid;
+		loop = 0;
+		while (loop < ar->vendor.bss_filter.max) {
+			if (memcmp(bssid[loop].addr,
+				   addr, ETH_ALEN) == 0) {
+				idx = loop;
+				break;
+			}
+
+			loop++;
+		}
+
+		if (idx == ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX) {
+			ath10k_warn(ar, "Invalid BSS addr %pM\n", addr);
+			return -EINVAL;
+		}
+
+		ret = ath10k_vendor_bssid_filter_delete(ar, addr, idx, vdev_id);
+	} else {
+		ath10k_warn(ar, "Invalid action %d\n", action);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int ath10k_vendor_unassoc_sta_filter_add(struct ath10k *ar, u8 *addr)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta, *tmp = NULL;
+	int ret;
+
+	if (!ar->vendor.bss_filter.max) {
+		ath10k_warn(ar, "Not supported by platform\n");
+		return -EOPNOTSUPP;
+	}
+
+	sta = kzalloc(sizeof(*sta), GFP_KERNEL);
+	if (!sta)
+		return -ENOMEM;
+
+	if (!tbl->entries)
+		rhashtable_init(&ar->vendor.bss_filter.tbl.rhead,
+				&ath10k_vendor_unassoc_sta_rht);
+
+	ether_addr_copy(sta->stats.addr, addr);
+
+	rcu_read_lock();
+	do {
+		ret = rhashtable_lookup_insert_fast(&tbl->rhead,
+						    &sta->rhash,
+						    ath10k_vendor_unassoc_sta_rht);
+		if (ret == -EEXIST)
+			tmp = rhashtable_lookup_fast(&tbl->rhead,
+						     sta->stats.addr,
+						     ath10k_vendor_unassoc_sta_rht);
+	} while (unlikely(ret == -EEXIST && !tmp));
+
+	if (ret)
+		goto error;
+
+	tbl->entries++;
+	rcu_read_unlock();
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Unassoc sta %pM added\n", addr);
+	return 0;
+
+error:
+	rcu_read_unlock();
+	kfree(sta);
+	return ret;
+}
+
+static void
+ath10k_vendor_unassoc_sta_delete(struct ath10k_vendor_unassoc_sta_tbl *tbl,
+				 struct ath10k_vendor_unassoc_sta *sta)
+{
+	if (!tbl || !sta)
+		return;
+
+	tbl->entries--;
+	kfree_rcu(sta, rcu);
+}
+
+static void ath10k_vendor_unassoc_sta_rht_free(void *ptr, void *tblptr)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = tblptr;
+	struct ath10k_vendor_unassoc_sta *sta = ptr;
+
+	ath10k_vendor_unassoc_sta_delete(tbl, sta);
+}
+
+static int ath10k_vendor_unassoc_sta_filter_delete(struct ath10k *ar, u8 *addr)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+
+	if (!tbl->entries) {
+		ath10k_warn(ar, "No sta to delete\n");
+		return -EINVAL;
+	}
+
+	rcu_read_lock();
+	sta = rhashtable_lookup_fast(&tbl->rhead,
+				     addr,
+				     ath10k_vendor_unassoc_sta_rht);
+	if (!sta) {
+		rcu_read_unlock();
+		ath10k_warn(ar, "Failed: Given addr %pM not in the list\n", addr);
+		return -ENXIO;
+	}
+
+	rhashtable_remove_fast(&tbl->rhead, &sta->rhash,
+			       ath10k_vendor_unassoc_sta_rht);
+	tbl->entries--;
+	kfree_rcu(sta, rcu);
+	rcu_read_unlock();
+
+	if (!tbl->entries)
+		rhashtable_destroy(&tbl->rhead);
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Unassoc sta %pM deleted\n", addr);
+
+	return 0;
+}
+
+static int
+ath10k_vendor_get_unassoc_sta_stats(struct ath10k *ar, u8 *addr,
+				    struct ath10k_vendor_bss_filter_get_reply *reply)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+	struct ath10k_vendor_unassoc_sta_stats *sta_s;
+
+	if (!tbl->entries) {
+		ath10k_warn(ar, "No sta exist to get statistics\n");
+		return -EINVAL;
+	}
+
+	rcu_read_lock();
+
+	sta = rhashtable_lookup_fast(&tbl->rhead,
+				     addr,
+				     ath10k_vendor_unassoc_sta_rht);
+	if (!sta) {
+		ath10k_warn(ar, "sta %pM not exist\n", addr);
+		rcu_read_unlock();
+		return -ENXIO;
+	}
+
+	reply->n_sta = 1;
+	sta_s = (struct ath10k_vendor_unassoc_sta_stats *)reply->data;
+	memcpy(sta_s, &sta->stats, sizeof(sta->stats));
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Get unassoc stats sta %pM rssi %d ts 0x%llx\n",
+		   sta_s->addr, sta_s->rssi, sta_s->rssi_ts);
+
+	rcu_read_unlock();
+
+	return 0;
+}
+
+static int
+ath10k_vendor_dump_unassoc_sta_stats(struct ath10k *ar,
+				     struct ath10k_vendor_bss_filter_get_reply *reply)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+	struct rhashtable_iter iter;
+	struct ath10k_vendor_unassoc_sta_stats *sta_s;
+	int ret, idx;
+
+	if (!tbl->entries) {
+		ath10k_warn(ar, "No sta exist to get statistics\n");
+		return -EINVAL;
+	}
+
+	ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
+	if (ret) {
+		ath10k_warn(ar, "rhashtbl walk init Failed ret %d\n", ret);
+		return ret;
+	}
+
+	rhashtable_walk_start(&iter);
+
+	idx = 0;
+	sta_s = (struct ath10k_vendor_unassoc_sta_stats *)reply->data;
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Get All Statistics\n");
+
+	while ((sta = rhashtable_walk_next(&iter))) {
+		if (IS_ERR(sta) && PTR_ERR(sta) == -EAGAIN)
+			continue;
+
+		if (IS_ERR(sta)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		if (idx >= reply->n_sta)
+			break;
+
+		memcpy(sta_s, &sta->stats, sizeof(sta->stats));
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "[%d] sta %pM rssi %d ts 0x%llx\n",
+			   idx, sta_s->addr, sta_s->rssi, (u64)(sta_s->rssi_ts));
+		sta_s++;
+		idx++;
+	}
+	reply->n_sta = idx;
+
+	rhashtable_walk_stop(&iter);
+	rhashtable_walk_exit(&iter);
+	return ret;
+}
+
+static int
+ath10k_vendor_unassoc_sta_filter_action(struct ath10k *ar,
+					u8 *addr,
+					enum qca_wlan_vendor_bss_filter_type type,
+					enum qca_wlan_vendor_bss_filter_action action)
+{
+	struct ath10k_vendor_bss_filter_get_reply *reply_msg;
+	struct ath10k_vendor_unassoc_sta_stats *sta;
+	struct sk_buff *reply_skb;
+	struct nlattr *nl_stats, *nl_sta;
+	int msglen, n_sta, ret, i;
+	bool all;
+
+	switch (action) {
+	case QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD:
+		if (!is_valid_ether_addr(addr)) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		ret = ath10k_vendor_unassoc_sta_filter_add(ar, addr);
+		if (ret) {
+			ath10k_warn(ar, "sta add failed ret %d\n", ret);
+			goto out;
+		}
+		break;
+	case QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL:
+		ret = ath10k_vendor_unassoc_sta_filter_delete(ar, addr);
+		if (ret) {
+			ath10k_warn(ar, "sta delete failed ret %d\n", ret);
+			goto out;
+		}
+		break;
+	case QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET:
+		/* If the given MAC is Broadcast address , then we need to get
+		 * the statistics for all the stations
+		 */
+		if (is_broadcast_ether_addr(addr)) {
+			n_sta = ar->vendor.bss_filter.tbl.entries;
+			all = true;
+		} else if (is_valid_ether_addr(addr)) {
+			n_sta = 1;
+			all = false;
+		} else {
+			ath10k_warn(ar, "Invalid addr %pM\n", addr);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		msglen = sizeof(*reply_msg) + (n_sta * sizeof(*sta));
+		reply_msg = kzalloc(msglen, GFP_KERNEL);
+		if (!reply_msg) {
+			ath10k_warn(ar, "Failed to alloc %d bytes\n", msglen);
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		reply_msg->n_sta = n_sta;
+		if (all) {
+			ret = ath10k_vendor_dump_unassoc_sta_stats(ar,
+								   reply_msg);
+		} else {
+			ret = ath10k_vendor_get_unassoc_sta_stats(ar, addr,
+								  reply_msg);
+		}
+
+		if (ret) {
+			ath10k_warn(ar, "Get stats Failed ret %d\n", ret);
+			goto free_reply_msg;
+		}
+
+		/* Send a response to the command */
+		reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(ar->hw->wiphy,
+								msglen);
+		if (!reply_skb) {
+			ret = -ENOMEM;
+			goto free_reply_msg;
+		}
+
+		nl_stats = nla_nest_start(reply_skb,
+					  QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS);
+		if (!nl_stats) {
+			ret = -ENOBUFS;
+			goto nla_put_failure;
+		}
+
+		sta = (struct ath10k_vendor_unassoc_sta_stats *)reply_msg->data;
+		for (i = 0; i < reply_msg->n_sta; i++) {
+			nl_sta = nla_nest_start(reply_skb, i);
+			if (!nl_sta) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			if (nla_put
+			       (reply_skb,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_MAC,
+				ETH_ALEN, sta->addr)) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			if (sta->filled & (1ULL << NL80211_STA_INFO_SIGNAL) &&
+			    nla_put_u8
+			       (reply_skb,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI,
+				sta->rssi)) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			if (sta->filled & (1ULL << NL80211_STA_INFO_SIGNAL) &&
+			    nla_put_u64_64bit
+			       (reply_skb,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI_TS,
+				sta->rssi_ts,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_PAD)) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			nla_nest_end(reply_skb, nl_sta);
+			sta++;
+		}
+
+		nla_nest_end(reply_skb, nl_stats);
+
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "sending vendor cmd reply\n");
+
+		ret = cfg80211_vendor_cmd_reply(reply_skb);
+		if (ret) {
+			ath10k_warn(ar, "failed to send vendor reply %d\n", ret);
+			goto free_reply_msg;
+		}
+
+		kfree(reply_msg);
+		break;
+	default:
+		ath10k_warn(ar, "Invalid action %d\n", action);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	return 0;
+
+nla_put_failure:
+	kfree_skb(reply_skb);
+free_reply_msg:
+	kfree(reply_msg);
+out:
+	return ret;
+}
+
+static void ath10k_vendor_unassoc_sta_cleanup(struct ath10k *ar)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+
+	if (!tbl->entries)
+		return;
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "unassoc sta cleanup\n");
+	rhashtable_free_and_destroy(&tbl->rhead,
+				    ath10k_vendor_unassoc_sta_rht_free, tbl);
+	tbl->entries = 0;
+}
+
+void ath10k_vendor_bss_filter_cleanup(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+	struct ath10k_vendor_bssid_info *bssid;
+	u32 vdev_id;
+	u8 i;
+
+	if (!ar->vendor.bss_filter.max || arvif->vdev_type != WMI_VDEV_TYPE_AP)
+		return;
+
+	if (!ar->vendor.bss_filter.n_bssid)
+		goto sta_cleanup;
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "BSS filter cleanup\n");
+	vdev_id = arvif->vdev_id;
+	i = 0;
+	bssid = ar->vendor.bss_filter.bssid;
+	while (i < ar->vendor.bss_filter.max) {
+		if (is_valid_ether_addr(bssid[i].addr)) {
+			ath10k_vendor_bssid_filter_delete(ar, bssid[i].addr, i,
+							  vdev_id);
+		}
+		i++;
+	}
+
+sta_cleanup:
+	/* Do station cleanup only no other bss filter enabled */
+	if (!ar->vendor.bss_filter.n_bssid)
+		ath10k_vendor_unassoc_sta_cleanup(ar);
+}
+
+static int ath10k_vendor_bss_filter_vendor_handler(struct wiphy *wiphy,
+						   struct wireless_dev *wdev,
+						   const void *data,
+						   int data_len)
+{
+	struct ieee80211_vif *vif;
+	struct ath10k_vif *arvif;
+	struct ath10k *ar;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX + 1];
+	u8 addr[ETH_ALEN];
+	enum qca_wlan_vendor_bss_filter_type type;
+	enum qca_wlan_vendor_bss_filter_action action;
+	int ret;
+
+	if (!wdev)
+		return -EINVAL;
+
+	vif = wdev_to_ieee80211_vif(wdev);
+	if (!vif)
+		return -EINVAL;
+
+	arvif = (void *)vif->drv_priv;
+	if (!arvif)
+		return -EINVAL;
+
+	ar = arvif->ar;
+
+	mutex_lock(&ar->conf_mutex);
+
+	/* Check BSSID filter is supported in the platform and then allow
+	 * filter only for the AP VAP.
+	 */
+	if (!ar->vendor.bss_filter.max || arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+		ath10k_warn(ar, "BSS filter not supported Max %d vdev type %d\n",
+			    ar->vendor.bss_filter.max, arvif->vdev_type);
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Check the given Data is valid */
+	if (!data) {
+		ath10k_warn(ar, "invalid Data\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX, data, data_len,
+			ath10k_vendor_bss_filter_policy, NULL);
+	if (ret) {
+		ath10k_warn(ar, "invalid BSS filter policy ATTR\n");
+		goto out;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION]) {
+		ath10k_warn(ar, "invalid BSS filter ATTR\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ether_addr_copy(addr,
+			nla_data(tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR]));
+	type = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE]);
+	action = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION]);
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Req MAC %pM type %d action %d\n",
+		   addr, type, action);
+
+	if (type == QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID) {
+		ret = ath10k_vendor_bssid_filter_action(arvif->ar, addr, type,
+							action, arvif->vdev_id);
+	} else if (type == QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA) {
+		ret = ath10k_vendor_unassoc_sta_filter_action(arvif->ar, addr,
+							      type, action);
+	} else {
+		ath10k_warn(ar, "invalid BSS filter type %d\n", type);
+		ret = -EINVAL;
+		goto out;
+	}
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+int ath10k_vendor_register(struct ath10k *ar)
+{
+	int ret;
+	int len;
+	u8 count;
+
+	/* Initialize other BSS filter, If platform support */
+	if (test_bit(WMI_SERVICE_VDEV_FILTER_NEIGHBOR, ar->wmi.svc_map)) {
+		count = ATH10K_VENDOR_BSSID_FILTER_COUNT;
+		len = count * sizeof(struct ath10k_vendor_bssid_info);
+
+		ar->vendor.bss_filter.bssid = kzalloc(len, GFP_KERNEL);
+		if (!ar->vendor.bss_filter.bssid) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ar->vendor.bss_filter.max = count;
+		ar->vendor.bss_filter.tbl.entries = 0;
+	}
+
+	ar->hw->wiphy->vendor_commands = ath10k_vendor_commands;
+	ar->hw->wiphy->n_vendor_commands = ARRAY_SIZE(ath10k_vendor_commands);
+
+	return 0;
+
+err:
+	return ret;
+}
+
+void ath10k_vendor_unregister(struct ath10k *ar)
+{
+	if (ar->vendor.bss_filter.bssid) {
+		ar->vendor.bss_filter.max = 0;
+		kfree(ar->vendor.bss_filter.bssid);
+		ar->vendor.bss_filter.bssid = NULL;
+	}
+	return;
+}
diff --git a/drivers/net/wireless/ath/ath10k/vendor.h b/drivers/net/wireless/ath/ath10k/vendor.h
new file mode 100644
index 0000000..fd126b1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/vendor.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _VENDOR_H_
+#define _VENDOR_H_
+
+#include <linux/rhashtable.h>
+#include <net/mac80211.h>
+#include <linux/ktime.h>
+
+#include "htt.h"
+
+#define ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX	0xFF
+#define ATH10K_VENDOR_BSSID_FILTER_COUNT	0x3
+
+/* Vendor id to be used in vendor specific command and events to user space
+ * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
+ * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and
+ * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in
+ * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that
+ */
+#define QCA_NL80211_VENDOR_ID 0x001374
+
+/* enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers */
+enum qca_nl80211_vendor_subcmds {
+	/* This command is used to configure an RX filter to receive frames
+	 * from stations that are active on the operating channel, but not
+	 * associated with the local device (e.g., STAs associated with other
+	 * APs). Filtering is done based on a list of BSSIDs and STA MAC
+	 * addresses added by the user. This command is also used to fetch the
+	 * statistics of unassociated stations. The attributes used with this
+	 * command are defined in enum qca_wlan_vendor_attr_bss_filter.
+	 */
+	QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER = 170,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ * The user can add/delete the filter by specifying the BSSID/STA MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, add/delete action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user can get the
+ * statistics of an unassociated station by specifying the MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user also can get
+ * the statistics of all unassociated stations by specifying the Broadcast MAC
+ * address (ff:ff:ff:ff:ff:ff) in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with
+ * above procedure. In the response, driver shall specify statistics
+ * information nested in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.
+ */
+enum qca_wlan_vendor_attr_bss_filter {
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR = 1,
+
+	/* Other BSS filter type, unsigned 8 bit value. One of the values
+	 * in enum qca_wlan_vendor_bss_filter_type.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE = 2,
+
+	/* Other BSS filter action, unsigned 8 bit value. One of the values
+	 * in enum qca_wlan_vendor_bss_filter_action.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION = 3,
+
+	/* Array of nested attributes where each entry is the statistics
+	 * information of the specified station that belong to another BSS.
+	 * Attributes for each entry are taken from enum
+	 * qca_wlan_vendor_bss_filter_sta_stats.
+	 * Other BSS station configured in
+	 * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER with filter type
+	 * QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA.
+	 * Statistics returned by QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER
+	 * with filter action QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS = 4,
+
+	/* Dummy (NOP) attribute for 64 bit padding */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_PAD = 13,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX
+};
+
+/* enum qca_wlan_vendor_bss_filter_type - Type of
+ * filter used in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ */
+enum qca_wlan_vendor_bss_filter_type {
+	/* BSSID filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID,
+
+	/* Station MAC address filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA
+};
+
+/* enum qca_wlan_vendor_bss_filter_action - Type of
+ * action in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ */
+enum qca_wlan_vendor_bss_filter_action {
+	/* Add filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD,
+
+	/* Delete filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL,
+
+	/* Get the statistics */
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET
+};
+
+/* enum qca_wlan_vendor_bss_filter_sta_stats - Attributes for
+ * the statistics of a specific unassociated station belong to another BSS.
+ * The statistics provides information of the unassociated station
+ * filtered by other BSS operation - such as MAC, signal value.
+ * Used by the vendor command QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ */
+enum qca_wlan_vendor_attr_bss_filter_sta_stats {
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_INVALID,
+
+	/* MAC address of the station */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_MAC,
+
+	/* Last received signal strength of the station.
+	 * Unsigned 8 bit number containing RSSI.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI,
+
+	/* Time stamp of the host driver for the last received RSSI.
+	 * Unsigned 64 bit number containing nanoseconds from the boottime.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI_TS,
+
+	/* Keep last */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_MAX =
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_AFTER_LAST - 1
+};
+
+/* struct ath10k_vendor_bssid_info - BSSID information */
+struct ath10k_vendor_bssid_info {
+	/* vdev map used to indicate which VAPs are own */
+	unsigned long long vdev_map;
+
+	/* BSSID */
+	u8 addr[ETH_ALEN];
+	u16 ref;
+};
+
+/* struct ath10k_vendor_unassoc_sta_stats - Unassociated station statistics
+ * information.
+ */
+struct ath10k_vendor_unassoc_sta_stats {
+	/* bitflag of flags using the bits of &enum nl80211_sta_info to
+	 * indicate the relevant values in this struct for them
+	 */
+	u64 filled;
+
+	/* host driver time stamp for the signal (rssi) */
+	u64 rssi_ts;
+
+	/* signal value of the station */
+	s8 rssi;
+
+	/* MAC address of the station */
+	u8 addr[ETH_ALEN];
+};
+
+/* struct ath10k_vendor_unassoc_sta - Unassociated station information
+ * This structure protected by rcu lock.
+ */
+struct ath10k_vendor_unassoc_sta {
+	struct ath10k_vendor_unassoc_sta_stats stats;
+
+	/* rhashtable list pointer */
+	struct rhash_head rhash;
+
+	/* rcu head for freeing unassociated station */
+	struct rcu_head rcu;
+};
+
+/* struct ath10k_vendor_unassoc_sta_tbl - Unassociated station table info */
+struct ath10k_vendor_unassoc_sta_tbl {
+	/* The rhashtable containing struct ath10k_vendor_unassoc_sta, keyed
+	 * by MAC addr
+	 */
+	struct rhashtable rhead;
+
+	/* Total Number of entries */
+	u16 entries;
+};
+
+/* struct ath10k_vendor_bss_filter - BSS filter information */
+struct ath10k_vendor_bss_filter {
+	/* Array of BSSID information */
+	struct ath10k_vendor_bssid_info *bssid;
+
+	/* Unassociated station table */
+	struct ath10k_vendor_unassoc_sta_tbl tbl;
+
+	/* Maximum other bss filter supported by the platform */
+	u8 max;
+
+	/* number of bssid filter configured by user */
+	u8 n_bssid;
+};
+
+struct ath10k_vendor_bss_filter_get_reply {
+	u32 n_sta;		/* Number of stations */
+	u8 data[0];		/* Array of ath10k_vendor_unassoc_sta_stats */
+};
+
+struct ath10k_vendor {
+	/* BSS filter */
+	struct ath10k_vendor_bss_filter bss_filter;
+};
+
+struct ath10k_vendor_unassoc_sta *
+ath10k_vendor_unassoc_sta_lookup(struct ath10k_vendor_unassoc_sta_tbl *tbl, u8 *addr);
+void ath10k_vendor_bss_filter_cleanup(struct ath10k_vif *arvif);
+int ath10k_vendor_register(struct ath10k *ar);
+void ath10k_vendor_unregister(struct ath10k *ar);
+
+static inline bool
+ath10k_vendor_rx_h_bssid_filter(struct ath10k_vendor *vendor,
+				struct sk_buff_head *amsdu,
+				struct ieee80211_rx_status *rx_status)
+{
+	struct sk_buff *first;
+	struct htt_rx_desc *rxd;
+	struct ath10k_vendor_unassoc_sta_tbl *tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+	struct ieee80211_hdr *hdr;
+
+	/* If BSS filter are not enabled, then
+	 * no need to filter sta so allow all frames
+	 */
+	if (!vendor->bss_filter.n_bssid)
+		return false;
+
+	first = skb_peek(amsdu);
+	rxd = (void *)first->data - sizeof(*rxd);
+
+	if (!rxd)
+		return false;
+
+	/* other bssid frames are with invalid peer idx flags */
+	if (rxd->attention.flags &
+	    __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID)) {
+		tbl = &vendor->bss_filter.tbl;
+
+		/* If unassociacted sta configured, then do lookup
+		 * and maintain the last rssi value.
+		 * Don't allow other bssid frames.
+		 */
+		if (tbl->entries) {
+			hdr = (void *)rxd->rx_hdr_status;
+			rcu_read_lock();
+
+			sta = ath10k_vendor_unassoc_sta_lookup(tbl, hdr->addr2);
+			if (sta) {
+				sta->stats.rssi = rx_status->signal;
+				sta->stats.rssi_ts = ktime_to_ns(ktime_get_boottime());
+				sta->stats.filled |= BIT(NL80211_STA_INFO_SIGNAL);
+			}
+
+			rcu_read_unlock();
+		}
+		return true;
+	}
+
+	return false;
+}
+
+#endif /* _VENDOR_H_ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC 2/2] ath10k: Add QCA vendor command/attr support to filter neighbor BSS frames
@ 2018-07-05 11:51   ` Karthikeyan Periyasamy
  0 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-07-05 11:51 UTC (permalink / raw)
  To: ath10k; +Cc: Karthikeyan Periyasamy, linux-wireless

Add operations to allow an AP to capture frames from stations that
are active on the operating channel, but not associated to the current AP.
Operations include add/delete the filter and get the statistics
information of the unassociated stations.

User can able to add/delete two type of filters,
	1. BSSID
	2. STA MAC address

BSSID filter achieved by HW through vdev_set_neighbor_rx_param WMI command.
Local device able to capture all frames of the specified BSS using the above
WMI command. STA filter achieved by SW through RX addr2 matching with
unassociated station rhash table list keyed by MAC address. rhash table used
for efficient search. rhash table can grow/shrink by the add/delete STA
filter request.

Hardware tested: QCA9984, QCA4019 and QCA9888
Firmware tested: 10.4-3.6-xxxxx

NOTE: Tested with debug firmware

Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>
---
 drivers/net/wireless/ath/ath10k/Makefile |   3 +-
 drivers/net/wireless/ath/ath10k/core.h   |   3 +
 drivers/net/wireless/ath/ath10k/htt_rx.c |   5 +
 drivers/net/wireless/ath/ath10k/mac.c    |  15 +-
 drivers/net/wireless/ath/ath10k/vendor.c | 770 +++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath10k/vendor.h | 289 ++++++++++++
 6 files changed, 1083 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.c
 create mode 100644 drivers/net/wireless/ath/ath10k/vendor.h

diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 44d60a6..65d824d 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -13,7 +13,8 @@ ath10k_core-y += mac.o \
 		 bmi.o \
 		 hw.o \
 		 p2p.o \
-		 swap.o
+		 swap.o \
+		 vendor.o
 
 ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o
 ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 427ee57..a723028 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -38,6 +38,7 @@
 #include "thermal.h"
 #include "wow.h"
 #include "swap.h"
+#include "vendor.h"
 
 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -1132,6 +1133,8 @@ struct ath10k {
 	struct ath10k_radar_found_info last_radar_info;
 	struct work_struct radar_confirmation_work;
 
+	struct ath10k_vendor vendor;
+
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 4d1cd90..e30ffad 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -23,6 +23,7 @@
 #include "debug.h"
 #include "trace.h"
 #include "mac.h"
+#include "vendor.h"
 
 #include <linux/log2.h>
 #include <linux/bitfield.h>
@@ -1773,6 +1774,10 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
 		return false;
 	}
 
+	/* Do the Neighbor BSSID filter if configured */
+	if (ath10k_vendor_rx_h_bssid_filter(&ar->vendor, amsdu, rx_status))
+		return false;
+
 	return true;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 95243b4..05c8c4f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5313,6 +5313,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 
 	mutex_lock(&ar->conf_mutex);
 
+	ath10k_vendor_bss_filter_cleanup(arvif);
+
 	spin_lock_bh(&ar->data_lock);
 	ath10k_mac_vif_beacon_cleanup(arvif);
 	spin_unlock_bh(&ar->data_lock);
@@ -8518,10 +8520,16 @@ int ath10k_mac_register(struct ath10k *ar)
 
 	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
 
+	ret = ath10k_vendor_register(ar);
+	if (ret) {
+		ath10k_err(ar, "failed to register vendor: %d\n", ret);
+		goto err_dfs_detector_exit;
+	}
+
 	ret = ieee80211_register_hw(ar->hw);
 	if (ret) {
 		ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
-		goto err_dfs_detector_exit;
+		goto err_vendor_unregister;
 	}
 
 	if (!ath_is_world_regd(&ar->ath_common.regulatory)) {
@@ -8536,6 +8544,9 @@ int ath10k_mac_register(struct ath10k *ar)
 err_unregister:
 	ieee80211_unregister_hw(ar->hw);
 
+err_vendor_unregister:
+	ath10k_vendor_unregister(ar);
+
 err_dfs_detector_exit:
 	if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
 		ar->dfs_detector->exit(ar->dfs_detector);
@@ -8552,6 +8563,8 @@ void ath10k_mac_unregister(struct ath10k *ar)
 {
 	ieee80211_unregister_hw(ar->hw);
 
+	ath10k_vendor_unregister(ar);
+
 	if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
 		ar->dfs_detector->exit(ar->dfs_detector);
 
diff --git a/drivers/net/wireless/ath/ath10k/vendor.c b/drivers/net/wireless/ath/ath10k/vendor.c
new file mode 100644
index 0000000..a6687d2
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/vendor.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <net/netlink.h>
+#include <net/mac80211.h>
+
+#include "core.h"
+#include "wmi-ops.h"
+#include "debug.h"
+
+static int ath10k_vendor_bss_filter_vendor_handler(struct wiphy *wiphy,
+						   struct wireless_dev *wdev,
+						   const void *data,
+						   int data_len);
+
+static const struct nla_policy
+ath10k_vendor_bss_filter_policy[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR] = { .len = ETH_ALEN },
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION] = { .type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS] = { .type = NLA_NESTED },
+};
+
+static struct wiphy_vendor_command ath10k_vendor_commands[] = {
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = ath10k_vendor_bss_filter_vendor_handler,
+	}
+};
+
+static u32
+ath10k_vendor_unassoc_sta_table_hash(const void *addr, u32 len, u32 seed)
+{
+	/* Use last four bytes of hw addr as hash index */
+	return jhash_1word(*(u32 *)(addr + 2), seed);
+}
+
+static const struct rhashtable_params ath10k_vendor_unassoc_sta_rht = {
+	.nelem_hint = 2,
+	.automatic_shrinking = true,
+	.key_len = ETH_ALEN,
+	.key_offset = offsetof(struct ath10k_vendor_unassoc_sta, stats.addr),
+	.head_offset = offsetof(struct ath10k_vendor_unassoc_sta, rhash),
+	.hashfn = ath10k_vendor_unassoc_sta_table_hash,
+};
+
+struct ath10k_vendor_unassoc_sta *
+ath10k_vendor_unassoc_sta_lookup(struct ath10k_vendor_unassoc_sta_tbl *tbl,
+				 u8 *addr)
+{
+	return rhashtable_lookup_fast(&tbl->rhead,
+				      addr, ath10k_vendor_unassoc_sta_rht);
+}
+
+static u8 ath10k_vendor_bssid_filter_get_free_idx(struct ath10k *ar, u8 *addr)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	u8 idx = ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX, loop = 0;
+
+	while (loop < ar->vendor.bss_filter.max) {
+		bssid = &ar->vendor.bss_filter.bssid[loop];
+
+		/* check given MAC already configured */
+		if (addr && !is_zero_ether_addr(addr)) {
+			if (memcmp(bssid->addr, addr, ETH_ALEN) == 0) {
+				idx = loop;
+				break;
+			}
+		}
+
+		/* Get the least free index */
+		if (idx == ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX &&
+		    is_zero_ether_addr(bssid->addr)) {
+			idx = loop;
+		}
+
+		loop++;
+	}
+	return idx;
+}
+
+static int ath10k_vendor_bssid_filter_add(struct ath10k *ar, u8 *addr,
+					  u32 vdev_id)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	int ret;
+	u8 idx;
+
+	/* If monitor started then no point to enable other bss filter */
+	if (ar->monitor_started) {
+		ath10k_warn(ar, "not able to enable other bss filter if monitor alive\n");
+		return -EBUSY;
+	}
+
+	idx = ath10k_vendor_bssid_filter_get_free_idx(ar, addr);
+	if (idx == ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX) {
+		ath10k_warn(ar, "No Free idx to add BSS filter\n");
+		return -EBUSY;
+	}
+
+	bssid = &ar->vendor.bss_filter.bssid[idx];
+
+	/* If valid MAC already configured in the given index, check both are
+	 * same one or not. If its same, just add the reference count
+	 * otherwise throw error.
+	 */
+	if (!is_zero_ether_addr(bssid->addr)) {
+		if (memcmp(bssid->addr, addr, ETH_ALEN) != 0) {
+			ath10k_warn(ar, "Already used idx %d\n", idx);
+			return -EINVAL;
+		}
+		goto add_ref;
+	}
+
+	/* Send wmi message to receive the given BSSID frames, zeroth
+	 * index is reserved so we cannot use that index.
+	 */
+	ret = ath10k_wmi_set_neighbor_rx_param(ar, vdev_id,
+					       addr, idx + 1,
+					       WMI_NEIGHBOR_RX_ACTION_ADD,
+					       WMI_NEIGHBOR_RX_TYPE_BSSID);
+	if (ret) {
+		ath10k_warn(ar, "BSS Add Filter failed on idx %d addr %pM\n",
+			    idx, addr);
+		return ret;
+	}
+
+	ether_addr_copy(bssid->addr, addr);
+
+	spin_lock_bh(&ar->data_lock);
+	ar->vendor.bss_filter.n_bssid++;
+	spin_unlock_bh(&ar->data_lock);
+
+add_ref:
+	/*If the VAP already configured, then no need to add reference count */
+	if (!(bssid->vdev_map & (1LL << vdev_id))) {
+		bssid->ref++;
+		bssid->vdev_map |= 1LL << vdev_id;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Filter added vdev %d idx %d addr %pM\n",
+		   vdev_id, idx, addr);
+	return 0;
+}
+
+static int ath10k_vendor_bssid_filter_delete(struct ath10k *ar, u8 *addr,
+					     u8 idx, u32 vdev_id)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	int ret;
+
+	if (idx >= ar->vendor.bss_filter.max) {
+		ath10k_warn(ar, "Invalid idx %d\n", idx);
+		return -EINVAL;
+	}
+
+	bssid = ar->vendor.bss_filter.bssid;
+	/* Check this bssid filter configured by the given VAP */
+	if (!(bssid[idx].vdev_map & (1LL << vdev_id))) {
+		ath10k_warn(ar, "BSS Filter addr %pM not configured by vdev %d\n",
+			    addr, vdev_id);
+		return -EINVAL;
+	}
+
+	bssid[idx].ref--;
+	bssid[idx].vdev_map &= ~(1LL << vdev_id);
+
+	/* If no reference count, then Send wmi message to not receive
+	 * the given BSSID frames, zeroth index is reserved so we cannot
+	 * use that index.
+	 */
+	if (!bssid[idx].ref) {
+		ret = ath10k_wmi_set_neighbor_rx_param(ar,
+						       vdev_id,
+						       addr, idx + 1,
+						       WMI_NEIGHBOR_RX_ACTION_DEL,
+						       WMI_NEIGHBOR_RX_TYPE_BSSID);
+		if (ret) {
+			ath10k_warn(ar, "wmi filter delete failed ret %d\n", ret);
+			bssid[idx].ref++;
+			bssid[idx].vdev_map &= ~(1LL << vdev_id);
+			return ret;
+		}
+
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "Filter deleted vdev %d addr %pM\n",
+			   vdev_id, addr);
+
+		memset(bssid[idx].addr, 0, ETH_ALEN);
+
+		spin_lock_bh(&ar->data_lock);
+		ar->vendor.bss_filter.n_bssid--;
+		spin_unlock_bh(&ar->data_lock);
+	}
+
+	return ret;
+}
+
+static int
+ath10k_vendor_bssid_filter_action(struct ath10k *ar,
+				  u8 *addr,
+				  enum qca_wlan_vendor_bss_filter_type type,
+				  enum qca_wlan_vendor_bss_filter_action action,
+				  u32 vdev_id)
+{
+	struct ath10k_vendor_bssid_info *bssid;
+	int ret;
+	u8 loop, idx = ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX;
+
+	if (!is_valid_ether_addr(addr))
+		return -EINVAL;
+
+	if (action == QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD) {
+		ret = ath10k_vendor_bssid_filter_add(ar, addr, vdev_id);
+	} else if (action == QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL) {
+		if (!ar->vendor.bss_filter.n_bssid) {
+			ath10k_warn(ar, "No BSS Filter to delete\n");
+			return -EINVAL;
+		}
+
+		bssid = ar->vendor.bss_filter.bssid;
+		loop = 0;
+		while (loop < ar->vendor.bss_filter.max) {
+			if (memcmp(bssid[loop].addr,
+				   addr, ETH_ALEN) == 0) {
+				idx = loop;
+				break;
+			}
+
+			loop++;
+		}
+
+		if (idx == ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX) {
+			ath10k_warn(ar, "Invalid BSS addr %pM\n", addr);
+			return -EINVAL;
+		}
+
+		ret = ath10k_vendor_bssid_filter_delete(ar, addr, idx, vdev_id);
+	} else {
+		ath10k_warn(ar, "Invalid action %d\n", action);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int ath10k_vendor_unassoc_sta_filter_add(struct ath10k *ar, u8 *addr)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta, *tmp = NULL;
+	int ret;
+
+	if (!ar->vendor.bss_filter.max) {
+		ath10k_warn(ar, "Not supported by platform\n");
+		return -EOPNOTSUPP;
+	}
+
+	sta = kzalloc(sizeof(*sta), GFP_KERNEL);
+	if (!sta)
+		return -ENOMEM;
+
+	if (!tbl->entries)
+		rhashtable_init(&ar->vendor.bss_filter.tbl.rhead,
+				&ath10k_vendor_unassoc_sta_rht);
+
+	ether_addr_copy(sta->stats.addr, addr);
+
+	rcu_read_lock();
+	do {
+		ret = rhashtable_lookup_insert_fast(&tbl->rhead,
+						    &sta->rhash,
+						    ath10k_vendor_unassoc_sta_rht);
+		if (ret == -EEXIST)
+			tmp = rhashtable_lookup_fast(&tbl->rhead,
+						     sta->stats.addr,
+						     ath10k_vendor_unassoc_sta_rht);
+	} while (unlikely(ret == -EEXIST && !tmp));
+
+	if (ret)
+		goto error;
+
+	tbl->entries++;
+	rcu_read_unlock();
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Unassoc sta %pM added\n", addr);
+	return 0;
+
+error:
+	rcu_read_unlock();
+	kfree(sta);
+	return ret;
+}
+
+static void
+ath10k_vendor_unassoc_sta_delete(struct ath10k_vendor_unassoc_sta_tbl *tbl,
+				 struct ath10k_vendor_unassoc_sta *sta)
+{
+	if (!tbl || !sta)
+		return;
+
+	tbl->entries--;
+	kfree_rcu(sta, rcu);
+}
+
+static void ath10k_vendor_unassoc_sta_rht_free(void *ptr, void *tblptr)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = tblptr;
+	struct ath10k_vendor_unassoc_sta *sta = ptr;
+
+	ath10k_vendor_unassoc_sta_delete(tbl, sta);
+}
+
+static int ath10k_vendor_unassoc_sta_filter_delete(struct ath10k *ar, u8 *addr)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+
+	if (!tbl->entries) {
+		ath10k_warn(ar, "No sta to delete\n");
+		return -EINVAL;
+	}
+
+	rcu_read_lock();
+	sta = rhashtable_lookup_fast(&tbl->rhead,
+				     addr,
+				     ath10k_vendor_unassoc_sta_rht);
+	if (!sta) {
+		rcu_read_unlock();
+		ath10k_warn(ar, "Failed: Given addr %pM not in the list\n", addr);
+		return -ENXIO;
+	}
+
+	rhashtable_remove_fast(&tbl->rhead, &sta->rhash,
+			       ath10k_vendor_unassoc_sta_rht);
+	tbl->entries--;
+	kfree_rcu(sta, rcu);
+	rcu_read_unlock();
+
+	if (!tbl->entries)
+		rhashtable_destroy(&tbl->rhead);
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Unassoc sta %pM deleted\n", addr);
+
+	return 0;
+}
+
+static int
+ath10k_vendor_get_unassoc_sta_stats(struct ath10k *ar, u8 *addr,
+				    struct ath10k_vendor_bss_filter_get_reply *reply)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+	struct ath10k_vendor_unassoc_sta_stats *sta_s;
+
+	if (!tbl->entries) {
+		ath10k_warn(ar, "No sta exist to get statistics\n");
+		return -EINVAL;
+	}
+
+	rcu_read_lock();
+
+	sta = rhashtable_lookup_fast(&tbl->rhead,
+				     addr,
+				     ath10k_vendor_unassoc_sta_rht);
+	if (!sta) {
+		ath10k_warn(ar, "sta %pM not exist\n", addr);
+		rcu_read_unlock();
+		return -ENXIO;
+	}
+
+	reply->n_sta = 1;
+	sta_s = (struct ath10k_vendor_unassoc_sta_stats *)reply->data;
+	memcpy(sta_s, &sta->stats, sizeof(sta->stats));
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Get unassoc stats sta %pM rssi %d ts 0x%llx\n",
+		   sta_s->addr, sta_s->rssi, sta_s->rssi_ts);
+
+	rcu_read_unlock();
+
+	return 0;
+}
+
+static int
+ath10k_vendor_dump_unassoc_sta_stats(struct ath10k *ar,
+				     struct ath10k_vendor_bss_filter_get_reply *reply)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+	struct rhashtable_iter iter;
+	struct ath10k_vendor_unassoc_sta_stats *sta_s;
+	int ret, idx;
+
+	if (!tbl->entries) {
+		ath10k_warn(ar, "No sta exist to get statistics\n");
+		return -EINVAL;
+	}
+
+	ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
+	if (ret) {
+		ath10k_warn(ar, "rhashtbl walk init Failed ret %d\n", ret);
+		return ret;
+	}
+
+	rhashtable_walk_start(&iter);
+
+	idx = 0;
+	sta_s = (struct ath10k_vendor_unassoc_sta_stats *)reply->data;
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Get All Statistics\n");
+
+	while ((sta = rhashtable_walk_next(&iter))) {
+		if (IS_ERR(sta) && PTR_ERR(sta) == -EAGAIN)
+			continue;
+
+		if (IS_ERR(sta)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		if (idx >= reply->n_sta)
+			break;
+
+		memcpy(sta_s, &sta->stats, sizeof(sta->stats));
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "[%d] sta %pM rssi %d ts 0x%llx\n",
+			   idx, sta_s->addr, sta_s->rssi, (u64)(sta_s->rssi_ts));
+		sta_s++;
+		idx++;
+	}
+	reply->n_sta = idx;
+
+	rhashtable_walk_stop(&iter);
+	rhashtable_walk_exit(&iter);
+	return ret;
+}
+
+static int
+ath10k_vendor_unassoc_sta_filter_action(struct ath10k *ar,
+					u8 *addr,
+					enum qca_wlan_vendor_bss_filter_type type,
+					enum qca_wlan_vendor_bss_filter_action action)
+{
+	struct ath10k_vendor_bss_filter_get_reply *reply_msg;
+	struct ath10k_vendor_unassoc_sta_stats *sta;
+	struct sk_buff *reply_skb;
+	struct nlattr *nl_stats, *nl_sta;
+	int msglen, n_sta, ret, i;
+	bool all;
+
+	switch (action) {
+	case QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD:
+		if (!is_valid_ether_addr(addr)) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		ret = ath10k_vendor_unassoc_sta_filter_add(ar, addr);
+		if (ret) {
+			ath10k_warn(ar, "sta add failed ret %d\n", ret);
+			goto out;
+		}
+		break;
+	case QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL:
+		ret = ath10k_vendor_unassoc_sta_filter_delete(ar, addr);
+		if (ret) {
+			ath10k_warn(ar, "sta delete failed ret %d\n", ret);
+			goto out;
+		}
+		break;
+	case QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET:
+		/* If the given MAC is Broadcast address , then we need to get
+		 * the statistics for all the stations
+		 */
+		if (is_broadcast_ether_addr(addr)) {
+			n_sta = ar->vendor.bss_filter.tbl.entries;
+			all = true;
+		} else if (is_valid_ether_addr(addr)) {
+			n_sta = 1;
+			all = false;
+		} else {
+			ath10k_warn(ar, "Invalid addr %pM\n", addr);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		msglen = sizeof(*reply_msg) + (n_sta * sizeof(*sta));
+		reply_msg = kzalloc(msglen, GFP_KERNEL);
+		if (!reply_msg) {
+			ath10k_warn(ar, "Failed to alloc %d bytes\n", msglen);
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		reply_msg->n_sta = n_sta;
+		if (all) {
+			ret = ath10k_vendor_dump_unassoc_sta_stats(ar,
+								   reply_msg);
+		} else {
+			ret = ath10k_vendor_get_unassoc_sta_stats(ar, addr,
+								  reply_msg);
+		}
+
+		if (ret) {
+			ath10k_warn(ar, "Get stats Failed ret %d\n", ret);
+			goto free_reply_msg;
+		}
+
+		/* Send a response to the command */
+		reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(ar->hw->wiphy,
+								msglen);
+		if (!reply_skb) {
+			ret = -ENOMEM;
+			goto free_reply_msg;
+		}
+
+		nl_stats = nla_nest_start(reply_skb,
+					  QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS);
+		if (!nl_stats) {
+			ret = -ENOBUFS;
+			goto nla_put_failure;
+		}
+
+		sta = (struct ath10k_vendor_unassoc_sta_stats *)reply_msg->data;
+		for (i = 0; i < reply_msg->n_sta; i++) {
+			nl_sta = nla_nest_start(reply_skb, i);
+			if (!nl_sta) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			if (nla_put
+			       (reply_skb,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_MAC,
+				ETH_ALEN, sta->addr)) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			if (sta->filled & (1ULL << NL80211_STA_INFO_SIGNAL) &&
+			    nla_put_u8
+			       (reply_skb,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI,
+				sta->rssi)) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			if (sta->filled & (1ULL << NL80211_STA_INFO_SIGNAL) &&
+			    nla_put_u64_64bit
+			       (reply_skb,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI_TS,
+				sta->rssi_ts,
+				QCA_WLAN_VENDOR_ATTR_BSS_FILTER_PAD)) {
+				ret = -ENOBUFS;
+				goto nla_put_failure;
+			}
+
+			nla_nest_end(reply_skb, nl_sta);
+			sta++;
+		}
+
+		nla_nest_end(reply_skb, nl_stats);
+
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "sending vendor cmd reply\n");
+
+		ret = cfg80211_vendor_cmd_reply(reply_skb);
+		if (ret) {
+			ath10k_warn(ar, "failed to send vendor reply %d\n", ret);
+			goto free_reply_msg;
+		}
+
+		kfree(reply_msg);
+		break;
+	default:
+		ath10k_warn(ar, "Invalid action %d\n", action);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	return 0;
+
+nla_put_failure:
+	kfree_skb(reply_skb);
+free_reply_msg:
+	kfree(reply_msg);
+out:
+	return ret;
+}
+
+static void ath10k_vendor_unassoc_sta_cleanup(struct ath10k *ar)
+{
+	struct ath10k_vendor_unassoc_sta_tbl *tbl = &ar->vendor.bss_filter.tbl;
+
+	if (!tbl->entries)
+		return;
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "unassoc sta cleanup\n");
+	rhashtable_free_and_destroy(&tbl->rhead,
+				    ath10k_vendor_unassoc_sta_rht_free, tbl);
+	tbl->entries = 0;
+}
+
+void ath10k_vendor_bss_filter_cleanup(struct ath10k_vif *arvif)
+{
+	struct ath10k *ar = arvif->ar;
+	struct ath10k_vendor_bssid_info *bssid;
+	u32 vdev_id;
+	u8 i;
+
+	if (!ar->vendor.bss_filter.max || arvif->vdev_type != WMI_VDEV_TYPE_AP)
+		return;
+
+	if (!ar->vendor.bss_filter.n_bssid)
+		goto sta_cleanup;
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "BSS filter cleanup\n");
+	vdev_id = arvif->vdev_id;
+	i = 0;
+	bssid = ar->vendor.bss_filter.bssid;
+	while (i < ar->vendor.bss_filter.max) {
+		if (is_valid_ether_addr(bssid[i].addr)) {
+			ath10k_vendor_bssid_filter_delete(ar, bssid[i].addr, i,
+							  vdev_id);
+		}
+		i++;
+	}
+
+sta_cleanup:
+	/* Do station cleanup only no other bss filter enabled */
+	if (!ar->vendor.bss_filter.n_bssid)
+		ath10k_vendor_unassoc_sta_cleanup(ar);
+}
+
+static int ath10k_vendor_bss_filter_vendor_handler(struct wiphy *wiphy,
+						   struct wireless_dev *wdev,
+						   const void *data,
+						   int data_len)
+{
+	struct ieee80211_vif *vif;
+	struct ath10k_vif *arvif;
+	struct ath10k *ar;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX + 1];
+	u8 addr[ETH_ALEN];
+	enum qca_wlan_vendor_bss_filter_type type;
+	enum qca_wlan_vendor_bss_filter_action action;
+	int ret;
+
+	if (!wdev)
+		return -EINVAL;
+
+	vif = wdev_to_ieee80211_vif(wdev);
+	if (!vif)
+		return -EINVAL;
+
+	arvif = (void *)vif->drv_priv;
+	if (!arvif)
+		return -EINVAL;
+
+	ar = arvif->ar;
+
+	mutex_lock(&ar->conf_mutex);
+
+	/* Check BSSID filter is supported in the platform and then allow
+	 * filter only for the AP VAP.
+	 */
+	if (!ar->vendor.bss_filter.max || arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+		ath10k_warn(ar, "BSS filter not supported Max %d vdev type %d\n",
+			    ar->vendor.bss_filter.max, arvif->vdev_type);
+		ret = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Check the given Data is valid */
+	if (!data) {
+		ath10k_warn(ar, "invalid Data\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX, data, data_len,
+			ath10k_vendor_bss_filter_policy, NULL);
+	if (ret) {
+		ath10k_warn(ar, "invalid BSS filter policy ATTR\n");
+		goto out;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION]) {
+		ath10k_warn(ar, "invalid BSS filter ATTR\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ether_addr_copy(addr,
+			nla_data(tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR]));
+	type = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE]);
+	action = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION]);
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "Req MAC %pM type %d action %d\n",
+		   addr, type, action);
+
+	if (type == QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID) {
+		ret = ath10k_vendor_bssid_filter_action(arvif->ar, addr, type,
+							action, arvif->vdev_id);
+	} else if (type == QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA) {
+		ret = ath10k_vendor_unassoc_sta_filter_action(arvif->ar, addr,
+							      type, action);
+	} else {
+		ath10k_warn(ar, "invalid BSS filter type %d\n", type);
+		ret = -EINVAL;
+		goto out;
+	}
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+int ath10k_vendor_register(struct ath10k *ar)
+{
+	int ret;
+	int len;
+	u8 count;
+
+	/* Initialize other BSS filter, If platform support */
+	if (test_bit(WMI_SERVICE_VDEV_FILTER_NEIGHBOR, ar->wmi.svc_map)) {
+		count = ATH10K_VENDOR_BSSID_FILTER_COUNT;
+		len = count * sizeof(struct ath10k_vendor_bssid_info);
+
+		ar->vendor.bss_filter.bssid = kzalloc(len, GFP_KERNEL);
+		if (!ar->vendor.bss_filter.bssid) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ar->vendor.bss_filter.max = count;
+		ar->vendor.bss_filter.tbl.entries = 0;
+	}
+
+	ar->hw->wiphy->vendor_commands = ath10k_vendor_commands;
+	ar->hw->wiphy->n_vendor_commands = ARRAY_SIZE(ath10k_vendor_commands);
+
+	return 0;
+
+err:
+	return ret;
+}
+
+void ath10k_vendor_unregister(struct ath10k *ar)
+{
+	if (ar->vendor.bss_filter.bssid) {
+		ar->vendor.bss_filter.max = 0;
+		kfree(ar->vendor.bss_filter.bssid);
+		ar->vendor.bss_filter.bssid = NULL;
+	}
+	return;
+}
diff --git a/drivers/net/wireless/ath/ath10k/vendor.h b/drivers/net/wireless/ath/ath10k/vendor.h
new file mode 100644
index 0000000..fd126b1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/vendor.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _VENDOR_H_
+#define _VENDOR_H_
+
+#include <linux/rhashtable.h>
+#include <net/mac80211.h>
+#include <linux/ktime.h>
+
+#include "htt.h"
+
+#define ATH10K_VENDOR_BSSID_FILTER_INVALID_IDX	0xFF
+#define ATH10K_VENDOR_BSSID_FILTER_COUNT	0x3
+
+/* Vendor id to be used in vendor specific command and events to user space
+ * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
+ * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and
+ * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in
+ * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that
+ */
+#define QCA_NL80211_VENDOR_ID 0x001374
+
+/* enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers */
+enum qca_nl80211_vendor_subcmds {
+	/* This command is used to configure an RX filter to receive frames
+	 * from stations that are active on the operating channel, but not
+	 * associated with the local device (e.g., STAs associated with other
+	 * APs). Filtering is done based on a list of BSSIDs and STA MAC
+	 * addresses added by the user. This command is also used to fetch the
+	 * statistics of unassociated stations. The attributes used with this
+	 * command are defined in enum qca_wlan_vendor_attr_bss_filter.
+	 */
+	QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER = 170,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ * The user can add/delete the filter by specifying the BSSID/STA MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, add/delete action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user can get the
+ * statistics of an unassociated station by specifying the MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user also can get
+ * the statistics of all unassociated stations by specifying the Broadcast MAC
+ * address (ff:ff:ff:ff:ff:ff) in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with
+ * above procedure. In the response, driver shall specify statistics
+ * information nested in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.
+ */
+enum qca_wlan_vendor_attr_bss_filter {
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR = 1,
+
+	/* Other BSS filter type, unsigned 8 bit value. One of the values
+	 * in enum qca_wlan_vendor_bss_filter_type.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE = 2,
+
+	/* Other BSS filter action, unsigned 8 bit value. One of the values
+	 * in enum qca_wlan_vendor_bss_filter_action.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION = 3,
+
+	/* Array of nested attributes where each entry is the statistics
+	 * information of the specified station that belong to another BSS.
+	 * Attributes for each entry are taken from enum
+	 * qca_wlan_vendor_bss_filter_sta_stats.
+	 * Other BSS station configured in
+	 * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER with filter type
+	 * QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA.
+	 * Statistics returned by QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER
+	 * with filter action QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS = 4,
+
+	/* Dummy (NOP) attribute for 64 bit padding */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_PAD = 13,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX
+};
+
+/* enum qca_wlan_vendor_bss_filter_type - Type of
+ * filter used in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ */
+enum qca_wlan_vendor_bss_filter_type {
+	/* BSSID filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID,
+
+	/* Station MAC address filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA
+};
+
+/* enum qca_wlan_vendor_bss_filter_action - Type of
+ * action in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ */
+enum qca_wlan_vendor_bss_filter_action {
+	/* Add filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD,
+
+	/* Delete filter */
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL,
+
+	/* Get the statistics */
+	QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET
+};
+
+/* enum qca_wlan_vendor_bss_filter_sta_stats - Attributes for
+ * the statistics of a specific unassociated station belong to another BSS.
+ * The statistics provides information of the unassociated station
+ * filtered by other BSS operation - such as MAC, signal value.
+ * Used by the vendor command QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ */
+enum qca_wlan_vendor_attr_bss_filter_sta_stats {
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_INVALID,
+
+	/* MAC address of the station */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_MAC,
+
+	/* Last received signal strength of the station.
+	 * Unsigned 8 bit number containing RSSI.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI,
+
+	/* Time stamp of the host driver for the last received RSSI.
+	 * Unsigned 64 bit number containing nanoseconds from the boottime.
+	 */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_RSSI_TS,
+
+	/* Keep last */
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_MAX =
+	QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS_AFTER_LAST - 1
+};
+
+/* struct ath10k_vendor_bssid_info - BSSID information */
+struct ath10k_vendor_bssid_info {
+	/* vdev map used to indicate which VAPs are own */
+	unsigned long long vdev_map;
+
+	/* BSSID */
+	u8 addr[ETH_ALEN];
+	u16 ref;
+};
+
+/* struct ath10k_vendor_unassoc_sta_stats - Unassociated station statistics
+ * information.
+ */
+struct ath10k_vendor_unassoc_sta_stats {
+	/* bitflag of flags using the bits of &enum nl80211_sta_info to
+	 * indicate the relevant values in this struct for them
+	 */
+	u64 filled;
+
+	/* host driver time stamp for the signal (rssi) */
+	u64 rssi_ts;
+
+	/* signal value of the station */
+	s8 rssi;
+
+	/* MAC address of the station */
+	u8 addr[ETH_ALEN];
+};
+
+/* struct ath10k_vendor_unassoc_sta - Unassociated station information
+ * This structure protected by rcu lock.
+ */
+struct ath10k_vendor_unassoc_sta {
+	struct ath10k_vendor_unassoc_sta_stats stats;
+
+	/* rhashtable list pointer */
+	struct rhash_head rhash;
+
+	/* rcu head for freeing unassociated station */
+	struct rcu_head rcu;
+};
+
+/* struct ath10k_vendor_unassoc_sta_tbl - Unassociated station table info */
+struct ath10k_vendor_unassoc_sta_tbl {
+	/* The rhashtable containing struct ath10k_vendor_unassoc_sta, keyed
+	 * by MAC addr
+	 */
+	struct rhashtable rhead;
+
+	/* Total Number of entries */
+	u16 entries;
+};
+
+/* struct ath10k_vendor_bss_filter - BSS filter information */
+struct ath10k_vendor_bss_filter {
+	/* Array of BSSID information */
+	struct ath10k_vendor_bssid_info *bssid;
+
+	/* Unassociated station table */
+	struct ath10k_vendor_unassoc_sta_tbl tbl;
+
+	/* Maximum other bss filter supported by the platform */
+	u8 max;
+
+	/* number of bssid filter configured by user */
+	u8 n_bssid;
+};
+
+struct ath10k_vendor_bss_filter_get_reply {
+	u32 n_sta;		/* Number of stations */
+	u8 data[0];		/* Array of ath10k_vendor_unassoc_sta_stats */
+};
+
+struct ath10k_vendor {
+	/* BSS filter */
+	struct ath10k_vendor_bss_filter bss_filter;
+};
+
+struct ath10k_vendor_unassoc_sta *
+ath10k_vendor_unassoc_sta_lookup(struct ath10k_vendor_unassoc_sta_tbl *tbl, u8 *addr);
+void ath10k_vendor_bss_filter_cleanup(struct ath10k_vif *arvif);
+int ath10k_vendor_register(struct ath10k *ar);
+void ath10k_vendor_unregister(struct ath10k *ar);
+
+static inline bool
+ath10k_vendor_rx_h_bssid_filter(struct ath10k_vendor *vendor,
+				struct sk_buff_head *amsdu,
+				struct ieee80211_rx_status *rx_status)
+{
+	struct sk_buff *first;
+	struct htt_rx_desc *rxd;
+	struct ath10k_vendor_unassoc_sta_tbl *tbl;
+	struct ath10k_vendor_unassoc_sta *sta;
+	struct ieee80211_hdr *hdr;
+
+	/* If BSS filter are not enabled, then
+	 * no need to filter sta so allow all frames
+	 */
+	if (!vendor->bss_filter.n_bssid)
+		return false;
+
+	first = skb_peek(amsdu);
+	rxd = (void *)first->data - sizeof(*rxd);
+
+	if (!rxd)
+		return false;
+
+	/* other bssid frames are with invalid peer idx flags */
+	if (rxd->attention.flags &
+	    __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID)) {
+		tbl = &vendor->bss_filter.tbl;
+
+		/* If unassociacted sta configured, then do lookup
+		 * and maintain the last rssi value.
+		 * Don't allow other bssid frames.
+		 */
+		if (tbl->entries) {
+			hdr = (void *)rxd->rx_hdr_status;
+			rcu_read_lock();
+
+			sta = ath10k_vendor_unassoc_sta_lookup(tbl, hdr->addr2);
+			if (sta) {
+				sta->stats.rssi = rx_status->signal;
+				sta->stats.rssi_ts = ktime_to_ns(ktime_get_boottime());
+				sta->stats.filled |= BIT(NL80211_STA_INFO_SIGNAL);
+			}
+
+			rcu_read_unlock();
+		}
+		return true;
+	}
+
+	return false;
+}
+
+#endif /* _VENDOR_H_ */
-- 
1.9.1


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
  2018-07-05 11:51   ` Karthikeyan Periyasamy
  (?)
@ 2018-10-05  6:00   ` Kalle Valo
  -1 siblings, 0 replies; 18+ messages in thread
From: Kalle Valo @ 2018-10-05  6:00 UTC (permalink / raw)
  To: Karthikeyan Periyasamy
  Cc: ath10k, linux-wireless, Karthikeyan Periyasamy, johannes

Karthikeyan Periyasamy <periyasa@codeaurora.org> wrote:

> Add operations to allow an AP to capture frames from stations that
> are active on the operating channel, but not associated to the current AP.
> Operations include add/delete the filter and get the statistics
> information of the unassociated stations.
> 
> User can able to add/delete two type of filters,
> 	1. BSSID
> 	2. STA MAC address
> 
> BSSID filter achieved by HW through vdev_set_neighbor_rx_param WMI command.
> Local device able to capture all frames of the specified BSS using the above
> WMI command. STA filter achieved by SW through RX addr2 matching with
> unassociated station rhash table list keyed by MAC address. rhash table used
> for efficient search. rhash table can grow/shrink by the add/delete STA
> filter request.
> 
> Hardware tested: QCA9984, QCA4019 and QCA9888
> Firmware tested: 10.4-3.6-xxxxx
> 
> NOTE: Tested with debug firmware
> 
> Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>

So I'm not sure what to do with this. A bpf type of filtering system in
mac80211 would be nice but then again we cannot benefit from HW offloading.
Johannes, what do you think?

Here are the full patches:

https://patchwork.kernel.org/patch/10508821/

https://patchwork.kernel.org/patch/10508823/

-- 
https://patchwork.kernel.org/patch/10508823/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
  2018-07-05 11:51   ` Karthikeyan Periyasamy
  (?)
  (?)
@ 2018-10-05  6:00   ` Kalle Valo
  -1 siblings, 0 replies; 18+ messages in thread
From: Kalle Valo @ 2018-10-05  6:00 UTC (permalink / raw)
  To: Karthikeyan Periyasamy; +Cc: johannes, linux-wireless, ath10k

Karthikeyan Periyasamy <periyasa@codeaurora.org> wrote:

> Add operations to allow an AP to capture frames from stations that
> are active on the operating channel, but not associated to the current AP.
> Operations include add/delete the filter and get the statistics
> information of the unassociated stations.
> 
> User can able to add/delete two type of filters,
> 	1. BSSID
> 	2. STA MAC address
> 
> BSSID filter achieved by HW through vdev_set_neighbor_rx_param WMI command.
> Local device able to capture all frames of the specified BSS using the above
> WMI command. STA filter achieved by SW through RX addr2 matching with
> unassociated station rhash table list keyed by MAC address. rhash table used
> for efficient search. rhash table can grow/shrink by the add/delete STA
> filter request.
> 
> Hardware tested: QCA9984, QCA4019 and QCA9888
> Firmware tested: 10.4-3.6-xxxxx
> 
> NOTE: Tested with debug firmware
> 
> Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>

So I'm not sure what to do with this. A bpf type of filtering system in
mac80211 would be nice but then again we cannot benefit from HW offloading.
Johannes, what do you think?

Here are the full patches:

https://patchwork.kernel.org/patch/10508821/

https://patchwork.kernel.org/patch/10508823/

-- 
https://patchwork.kernel.org/patch/10508823/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
       [not found]   ` <20181005060031.BA1EB60BF4@smtp.codeaurora.org>
@ 2018-10-18  8:29       ` Johannes Berg
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2018-10-18  8:29 UTC (permalink / raw)
  To: Kalle Valo, Karthikeyan Periyasamy; +Cc: ath10k, linux-wireless

On Fri, 2018-10-05 at 06:00 +0000, Kalle Valo wrote:
> 
> So I'm not sure what to do with this. A bpf type of filtering system in
> mac80211 would be nice

Yes, I think we really need to start implementing that sooner rather
than later. I had something, must see if I can find time for it.

> but then again we cannot benefit from HW offloading.

Yes, that's a concern. But how big of a concern is it really?

This patch only talks about "allow an AP" etc. and so while important,
power isn't the _utmost_ concern like on mobile. Given an efficient
filtering solution in software, would that be sufficient?

johannes


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
@ 2018-10-18  8:29       ` Johannes Berg
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2018-10-18  8:29 UTC (permalink / raw)
  To: Kalle Valo, Karthikeyan Periyasamy; +Cc: linux-wireless, ath10k

On Fri, 2018-10-05 at 06:00 +0000, Kalle Valo wrote:
> 
> So I'm not sure what to do with this. A bpf type of filtering system in
> mac80211 would be nice

Yes, I think we really need to start implementing that sooner rather
than later. I had something, must see if I can find time for it.

> but then again we cannot benefit from HW offloading.

Yes, that's a concern. But how big of a concern is it really?

This patch only talks about "allow an AP" etc. and so while important,
power isn't the _utmost_ concern like on mobile. Given an efficient
filtering solution in software, would that be sufficient?

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
  2018-10-18  8:29       ` Johannes Berg
@ 2018-11-20  2:40         ` Karthikeyan Periyasamy
  -1 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-11-20  2:40 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Kalle Valo, ath10k, linux-wireless

On 2018-10-18 13:59, Johannes Berg wrote:

>> So I'm not sure what to do with this. A bpf type of filtering system 
>> in
>> mac80211 would be nice
> 
> Yes, I think we really need to start implementing that sooner rather
> than later. I had something, must see if I can find time for it.
> 
>> but then again we cannot benefit from HW offloading.
> 
> Yes, that's a concern. But how big of a concern is it really?
> 
> This patch only talks about "allow an AP" etc. and so while important,
> power isn't the _utmost_ concern like on mobile. Given an efficient
> filtering solution in software, would that be sufficient?

Assume in a scenario where there are multiple APs (One Center AP and 
Multiple repeater AP) in same operating channel.
Clients present in Neighbor APs causing higher traffic.

when we try to filter desire client packets,
In HW offload case, all Neighbor BSS packets are filtered by HW. so 
there is no impact in CPU load. AP performance not get impacted.
In bpf (enabling monitor mode) case, all Neighbor BSS packets get 
filtered by software. It will consume CPU load which will impact AP 
performance.

Irrespective of how many neighbor APs present in the topology, HW 
offload take care of neighbor BSS filtering. Hence no impact in CPU 
load.
so we decided to use HW offload. To use our HW offload feature, we ended 
up in vendor command approach.

Karthikeyan

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
@ 2018-11-20  2:40         ` Karthikeyan Periyasamy
  0 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2018-11-20  2:40 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, ath10k, Kalle Valo

On 2018-10-18 13:59, Johannes Berg wrote:

>> So I'm not sure what to do with this. A bpf type of filtering system 
>> in
>> mac80211 would be nice
> 
> Yes, I think we really need to start implementing that sooner rather
> than later. I had something, must see if I can find time for it.
> 
>> but then again we cannot benefit from HW offloading.
> 
> Yes, that's a concern. But how big of a concern is it really?
> 
> This patch only talks about "allow an AP" etc. and so while important,
> power isn't the _utmost_ concern like on mobile. Given an efficient
> filtering solution in software, would that be sufficient?

Assume in a scenario where there are multiple APs (One Center AP and 
Multiple repeater AP) in same operating channel.
Clients present in Neighbor APs causing higher traffic.

when we try to filter desire client packets,
In HW offload case, all Neighbor BSS packets are filtered by HW. so 
there is no impact in CPU load. AP performance not get impacted.
In bpf (enabling monitor mode) case, all Neighbor BSS packets get 
filtered by software. It will consume CPU load which will impact AP 
performance.

Irrespective of how many neighbor APs present in the topology, HW 
offload take care of neighbor BSS filtering. Hence no impact in CPU 
load.
so we decided to use HW offload. To use our HW offload feature, we ended 
up in vendor command approach.

Karthikeyan

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
  2018-11-20  2:40         ` Karthikeyan Periyasamy
@ 2019-01-25 20:49           ` Johannes Berg
  -1 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2019-01-25 20:49 UTC (permalink / raw)
  To: Karthikeyan Periyasamy; +Cc: Kalle Valo, ath10k, linux-wireless

On Tue, 2018-11-20 at 08:10 +0530, Karthikeyan Periyasamy wrote:

> > This patch only talks about "allow an AP" etc. and so while important,
> > power isn't the _utmost_ concern like on mobile. Given an efficient
> > filtering solution in software, would that be sufficient?
> 
> Assume in a scenario where there are multiple APs (One Center AP and 
> Multiple repeater AP) in same operating channel.
> Clients present in Neighbor APs causing higher traffic.
> 
> when we try to filter desire client packets,
> In HW offload case, all Neighbor BSS packets are filtered by HW. so 
> there is no impact in CPU load. AP performance not get impacted.
> In bpf (enabling monitor mode) case, all Neighbor BSS packets get 
> filtered by software. It will consume CPU load which will impact AP 
> performance.
> 
> Irrespective of how many neighbor APs present in the topology, HW 
> offload take care of neighbor BSS filtering. Hence no impact in CPU 
> load.
> so we decided to use HW offload. To use our HW offload feature, we ended 
> up in vendor command approach.

Sure. I guess my question was intended more along the lines of "how much
CPU impact would you be able to live with?" :-)

At the same time, what happens today actually? Do all frames from non-
associated clients come up to the host? If so, is this not a problem for
all APs, not just ath10k?

And if they don't come up, what feature requires this? Sorry for the
vague questions, but I'm not really sure what this is all about. If
there's a need for these frames, wouldn't we need a generic way of
enabling receiving them, and perhaps even signalling hostapd with them?

Also, what are the statistics and what do you intend to use them for?

johannes


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
@ 2019-01-25 20:49           ` Johannes Berg
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2019-01-25 20:49 UTC (permalink / raw)
  To: Karthikeyan Periyasamy; +Cc: linux-wireless, ath10k, Kalle Valo

On Tue, 2018-11-20 at 08:10 +0530, Karthikeyan Periyasamy wrote:

> > This patch only talks about "allow an AP" etc. and so while important,
> > power isn't the _utmost_ concern like on mobile. Given an efficient
> > filtering solution in software, would that be sufficient?
> 
> Assume in a scenario where there are multiple APs (One Center AP and 
> Multiple repeater AP) in same operating channel.
> Clients present in Neighbor APs causing higher traffic.
> 
> when we try to filter desire client packets,
> In HW offload case, all Neighbor BSS packets are filtered by HW. so 
> there is no impact in CPU load. AP performance not get impacted.
> In bpf (enabling monitor mode) case, all Neighbor BSS packets get 
> filtered by software. It will consume CPU load which will impact AP 
> performance.
> 
> Irrespective of how many neighbor APs present in the topology, HW 
> offload take care of neighbor BSS filtering. Hence no impact in CPU 
> load.
> so we decided to use HW offload. To use our HW offload feature, we ended 
> up in vendor command approach.

Sure. I guess my question was intended more along the lines of "how much
CPU impact would you be able to live with?" :-)

At the same time, what happens today actually? Do all frames from non-
associated clients come up to the host? If so, is this not a problem for
all APs, not just ath10k?

And if they don't come up, what feature requires this? Sorry for the
vague questions, but I'm not really sure what this is all about. If
there's a need for these frames, wouldn't we need a generic way of
enabling receiving them, and perhaps even signalling hostapd with them?

Also, what are the statistics and what do you intend to use them for?

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
  2019-01-25 20:49           ` Johannes Berg
@ 2019-01-28  4:49             ` Karthikeyan Periyasamy
  -1 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2019-01-28  4:49 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Kalle Valo, ath10k, linux-wireless

On 2019-01-26 02:19, Johannes Berg wrote:
> 
> Sure. I guess my question was intended more along the lines of "how 
> much
> CPU impact would you be able to live with?" :-)

As much as no CPU impact.

> At the same time, what happens today actually? Do all frames from non-
> associated clients come up to the host? If so, is this not a problem 
> for
> all APs, not just ath10k?
> 

Today, without this patch. No frames from non-associated clients come up 
to the host in AP mode.

> And if they don't come up, what feature requires this? Sorry for the
> vague questions, but I'm not really sure what this is all about. If
> there's a need for these frames, wouldn't we need a generic way of
> enabling receiving them, and perhaps even signalling hostapd with them?

Steering application use this feature in their logical part of client 
steering.

This feature allow an application to configure filtering rules to 
capture from
stations that are active on the operating channel but not associated to 
this AP.
It also allow to get the statistics information of the configured non 
associated stations.

Ath10k driver use HW filter to capture other BSS frames and drop these 
packets
after collecting statistics information of configured non associated 
stations.

QCA vendor command/attr details:
https://w1.fi/cgit/hostap/commit/?id=6b21df0bb7a261ef890a02d1fef95ffa5ff54cfc


> Also, what are the statistics and what do you intend to use them for?

In this patch, we are providing the below information as a statistics of 
non associated stations.

- MAC address
- Last received signal strength
- Time stamp of the last received signal strength

Thanks,
Karthikeyan

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
@ 2019-01-28  4:49             ` Karthikeyan Periyasamy
  0 siblings, 0 replies; 18+ messages in thread
From: Karthikeyan Periyasamy @ 2019-01-28  4:49 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, ath10k, Kalle Valo

On 2019-01-26 02:19, Johannes Berg wrote:
> 
> Sure. I guess my question was intended more along the lines of "how 
> much
> CPU impact would you be able to live with?" :-)

As much as no CPU impact.

> At the same time, what happens today actually? Do all frames from non-
> associated clients come up to the host? If so, is this not a problem 
> for
> all APs, not just ath10k?
> 

Today, without this patch. No frames from non-associated clients come up 
to the host in AP mode.

> And if they don't come up, what feature requires this? Sorry for the
> vague questions, but I'm not really sure what this is all about. If
> there's a need for these frames, wouldn't we need a generic way of
> enabling receiving them, and perhaps even signalling hostapd with them?

Steering application use this feature in their logical part of client 
steering.

This feature allow an application to configure filtering rules to 
capture from
stations that are active on the operating channel but not associated to 
this AP.
It also allow to get the statistics information of the configured non 
associated stations.

Ath10k driver use HW filter to capture other BSS frames and drop these 
packets
after collecting statistics information of configured non associated 
stations.

QCA vendor command/attr details:
https://w1.fi/cgit/hostap/commit/?id=6b21df0bb7a261ef890a02d1fef95ffa5ff54cfc


> Also, what are the statistics and what do you intend to use them for?

In this patch, we are providing the below information as a statistics of 
non associated stations.

- MAC address
- Last received signal strength
- Time stamp of the last received signal strength

Thanks,
Karthikeyan

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
  2019-01-28  4:49             ` Karthikeyan Periyasamy
@ 2019-02-15 12:37               ` Johannes Berg
  -1 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2019-02-15 12:37 UTC (permalink / raw)
  To: Karthikeyan Periyasamy; +Cc: Kalle Valo, ath10k, linux-wireless

On Mon, 2019-01-28 at 10:19 +0530, Karthikeyan Periyasamy wrote:

> > At the same time, what happens today actually? Do all frames from non-
> > associated clients come up to the host? If so, is this not a problem 
> > for all APs, not just ath10k?
> 
> Today, without this patch. No frames from non-associated clients come up 
> to the host in AP mode.

So it's not just _filtering_ but also enabling to see them, right?

> > And if they don't come up, what feature requires this? Sorry for the
> > vague questions, but I'm not really sure what this is all about. If
> > there's a need for these frames, wouldn't we need a generic way of
> > enabling receiving them, and perhaps even signalling hostapd with them?
> 
> Steering application use this feature in their logical part of client 
> steering.

But there aren't even any steering applications that are open source or
anything like that, right?

I don't see why we should include this upstream. Clearly you can use
this for whatever you like to do with your driver in non-upstream
builds, and you can open-source this code, but if there are no
applications that could possibly use it upstream why bother?

johannes


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor BSS frames
@ 2019-02-15 12:37               ` Johannes Berg
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2019-02-15 12:37 UTC (permalink / raw)
  To: Karthikeyan Periyasamy; +Cc: linux-wireless, ath10k, Kalle Valo

On Mon, 2019-01-28 at 10:19 +0530, Karthikeyan Periyasamy wrote:

> > At the same time, what happens today actually? Do all frames from non-
> > associated clients come up to the host? If so, is this not a problem 
> > for all APs, not just ath10k?
> 
> Today, without this patch. No frames from non-associated clients come up 
> to the host in AP mode.

So it's not just _filtering_ but also enabling to see them, right?

> > And if they don't come up, what feature requires this? Sorry for the
> > vague questions, but I'm not really sure what this is all about. If
> > there's a need for these frames, wouldn't we need a generic way of
> > enabling receiving them, and perhaps even signalling hostapd with them?
> 
> Steering application use this feature in their logical part of client 
> steering.

But there aren't even any steering applications that are open source or
anything like that, right?

I don't see why we should include this upstream. Clearly you can use
this for whatever you like to do with your driver in non-upstream
builds, and you can open-source this code, but if there are no
applications that could possibly use it upstream why bother?

johannes


_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2019-02-15 12:38 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-05 11:51 [RFC 0/2] ath10k: Add QCA vendor command/attr support to filter neighbor BSS frames Karthikeyan Periyasamy
2018-07-05 11:51 ` Karthikeyan Periyasamy
2018-07-05 11:51 ` [RFC 1/2] ath10k: add wmi interface for vdev_set_neighbor_rx_param Karthikeyan Periyasamy
2018-07-05 11:51   ` Karthikeyan Periyasamy
2018-07-05 11:51 ` [RFC 2/2] ath10k: Add QCA vendor command/attr support to filter neighbor BSS frames Karthikeyan Periyasamy
2018-07-05 11:51   ` Karthikeyan Periyasamy
2018-10-05  6:00   ` [RFC 2/2] ath10k: Add QCA vendor command/attr support to filterneighbor " Kalle Valo
2018-10-05  6:00   ` Kalle Valo
     [not found]   ` <20181005060031.BA1EB60BF4@smtp.codeaurora.org>
2018-10-18  8:29     ` Johannes Berg
2018-10-18  8:29       ` Johannes Berg
2018-11-20  2:40       ` Karthikeyan Periyasamy
2018-11-20  2:40         ` Karthikeyan Periyasamy
2019-01-25 20:49         ` Johannes Berg
2019-01-25 20:49           ` Johannes Berg
2019-01-28  4:49           ` Karthikeyan Periyasamy
2019-01-28  4:49             ` Karthikeyan Periyasamy
2019-02-15 12:37             ` Johannes Berg
2019-02-15 12:37               ` Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.