Browse Source

Merge "qca-wifi: Componentize QWRAP code"

Linux Build Service Account 4 năm trước cách đây
mục cha
commit
aa6969e1bd
4 tập tin đã thay đổi với 1906 bổ sung0 xóa
  1. 392 0
      dp_wrap/inc/dp_wrap.h
  2. 87 0
      dp_wrap/inc/dp_wrap_struct.h
  3. 837 0
      dp_wrap/src/dp_wrap.c
  4. 590 0
      dp_wrap/src/dp_wrap_mat.c

+ 392 - 0
dp_wrap/inc/dp_wrap.h

@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2020-2021 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 _DP_WRAP_H_
+#define _DP_WRAP_H__
+
+#if ATH_SUPPORT_WRAP
+#if !WLAN_QWRAP_LEGACY
+
+#include "dp_wrap_struct.h"
+#include <dp_txrx.h>
+#include <cdp_txrx_cmn.h>
+#include <wlan_osif_priv.h>
+
+/**
+ * dp_wrap_get_pdev_handle() - get wrap handle from pdev handle
+ *
+ * @pdev: handle to the objmgr pdev
+ * Return: handle to wrap_pdev
+ */
+static inline
+dp_pdev_wrap_t *dp_wrap_get_pdev_handle(struct wlan_objmgr_pdev *pdev)
+{
+	ol_txrx_soc_handle soc;
+	dp_txrx_pdev_handle_t *dp_hdl;
+
+	soc = wlan_psoc_get_dp_handle(wlan_pdev_get_psoc(pdev));
+
+	if (qdf_unlikely(!soc)) {
+		qwrap_err(" soc handle is NULL");
+		return NULL;
+	}
+	dp_hdl = (dp_txrx_pdev_handle_t *)cdp_pdev_get_dp_txrx_handle(soc,
+		wlan_objmgr_pdev_get_pdev_id(pdev));
+
+	if (qdf_unlikely(!dp_hdl)) {
+		qwrap_err(" dp txrx handle is NULL");
+		return NULL;
+	}
+	return &dp_hdl->wrap_pdev_hdl;
+}
+
+/**
+ * dp_wrap_get_vdev_handle() - get wrap handle from vdev handle
+ *
+ * @vdev: handle to the objmgr vdev
+ * Return: handle to wrap_vdev
+ */
+static inline
+dp_vdev_wrap_t *dp_wrap_get_vdev_handle(struct wlan_objmgr_vdev *vdev)
+{
+	ol_txrx_soc_handle soc;
+	dp_vdev_txrx_handle_t *dp_hdl;
+
+	soc = wlan_psoc_get_dp_handle(
+		wlan_pdev_get_psoc(wlan_vdev_get_pdev(vdev)));
+
+	if (qdf_unlikely(!soc)) {
+		qwrap_err(" soc handle is NULL");
+		return NULL;
+	}
+
+	dp_hdl = (dp_vdev_txrx_handle_t *)cdp_vdev_get_dp_ext_txrx_handle(soc,
+			wlan_vdev_get_id(vdev));
+
+	if (qdf_unlikely(!dp_hdl)) {
+		qwrap_err(" dp txrx handle is NULL");
+		return NULL;
+	}
+
+	return &dp_hdl->wrap_vdev_hdl;
+}
+
+/**
+ * dp_wrap_get_mpsta_vdev() - get mpsta vdev
+ *
+ * @pdev: handle to pdev obj mgr
+ * Return: mpsta vdev object
+ */
+
+static
+struct wlan_objmgr_vdev *dp_wrap_get_mpsta_vdev(struct wlan_objmgr_pdev *pdev)
+{
+	struct dp_wrap_pdev *wrap_pdev;
+
+	if (!pdev)
+		return NULL;
+
+	wrap_pdev = dp_wrap_get_pdev_handle(pdev);
+	if (!wrap_pdev)
+		return NULL;
+	return wrap_pdev->mpsta_vdev;
+}
+
+/**
+ * dp_wrap_get_vdev() - get mpsta vdev
+ *
+ * @pdev: handle to pdev obj mgr
+ * Return: wrap vdev object
+ */
+
+static
+struct wlan_objmgr_vdev *dp_wrap_get_vdev(struct wlan_objmgr_pdev *pdev)
+{
+	struct dp_wrap_pdev *wrap_pdev;
+
+	if (!pdev)
+		return NULL;
+
+	wrap_pdev = dp_wrap_get_pdev_handle(pdev);
+	if (!wrap_pdev)
+		return NULL;
+	return wrap_pdev->wrap_vdev;
+}
+
+/**
+ * dp_wrap_vdev_is_mat_set() - Indicates whether mat translation is set
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: true if mat is set, false otherwise
+ */
+static inline bool dp_wrap_vdev_is_mat_set(struct wlan_objmgr_vdev *vdev)
+{
+	if (vdev && wlan_vdev_mlme_feat_ext_cap_get(vdev, WLAN_VDEV_FEXT_MAT))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dp_wrap_vdev_is_wired_psta() - Indicates whether vdev is wired psta.
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: true if wired psta, false otherwise.
+ */
+static inline bool dp_wrap_vdev_is_wired_psta(struct wlan_objmgr_vdev *vdev)
+{
+	if (vdev && wlan_vdev_mlme_feat_ext_cap_get(
+		vdev, WLAN_VDEV_FEXT_WIRED_PSTA))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dp_wrap_vdev_is_psta() - Indicates whether vdev is of type PSTA.
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: True if psta, false otherwise
+ */
+static inline bool dp_wrap_vdev_is_psta(struct wlan_objmgr_vdev *vdev)
+{
+	if (vdev && wlan_vdev_mlme_feat_ext_cap_get(vdev, WLAN_VDEV_FEXT_PSTA))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dp_wrap_vdev_is_mpsta() - Indicates whether vdev is of type MPSTA.
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: True if mpsta, false otherwise.
+ */
+static inline bool dp_wrap_vdev_is_mpsta(struct wlan_objmgr_vdev *vdev)
+{
+	if (vdev && wlan_vdev_mlme_feat_ext_cap_get(
+		vdev, WLAN_VDEV_FEXT_MPSTA))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dp_wrap_vdev_is_wrap() - Indicates whether vdev is of type WRAP.
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: True if wrap, false otherwise.
+ */
+static bool dp_wrap_vdev_is_wrap(struct wlan_objmgr_vdev *vdev)
+{
+	if (vdev && wlan_vdev_mlme_feat_ext_cap_get(vdev, WLAN_VDEV_FEXT_WRAP))
+		return true;
+	else
+		return false;
+}
+
+/**
+ * dp_wrap_vdev_get_nwrapvaps() - Get number of wrap vaps
+ *
+ * @pdev: handle to the objmgr pdev.
+ * Return: wrap vaps count
+ */
+static int dp_wrap_vdev_get_nwrapvaps(struct wlan_objmgr_pdev *pdev)
+{
+	struct dp_wrap_pdev *wpdev;
+
+	if (pdev) {
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wpdev is NULL");
+			return 0;
+		}
+		return wpdev->nwrapvaps;
+	}
+	return 0;
+}
+
+/**
+ * dp_wrap_vdev_get_npstavaps() - Get number of psta vaps
+ *
+ * @pdev: handle to the objmgr pdev.
+ * Return: psta vaps count
+ */
+static int dp_wrap_vdev_get_npstavaps(struct wlan_objmgr_pdev *pdev)
+{
+	struct dp_wrap_pdev *wpdev;
+
+	if (pdev) {
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wpdev is NULL");
+			return 0;
+		}
+		return wpdev->npstavaps;
+	}
+	return 0;
+}
+
+/**
+ * dp_wrap_pdev_set_isolation() - set isolation
+ *
+ * @pdev: handle to the objmgr pdev.
+ * @isolation: handle to set isolation param
+ * Return: void
+ */
+static void
+dp_wrap_pdev_set_isolation(struct wlan_objmgr_pdev *pdev, int isolation)
+{
+	struct dp_wrap_pdev *wpdev;
+
+	if (pdev) {
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wpdev is NULL");
+			return;
+		}
+		wpdev->wp_isolation = isolation;
+	}
+}
+
+/**
+ * dp_wrap_pdev_get_isolation() - Indicates whether isolation is set
+ *
+ * @pdev: handle to the objmgr pdev.
+ * Return: isolation value
+ */
+static int dp_wrap_pdev_get_isolation(struct wlan_objmgr_pdev *pdev)
+{
+	struct dp_wrap_pdev *wpdev;
+
+	if (pdev) {
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wpdev is NULL");
+			return 0;
+		}
+		return wpdev->wp_isolation;
+	}
+	return 0;
+}
+
+/**
+ * dp_wrap_vdev_get_oma() - Get OMA address of PSTA
+ *
+ * @pdev: handle to the objmgr vdev.
+ * Return: PSTA OMA address
+ */
+static u_int8_t *dp_wrap_vdev_get_oma(struct wlan_objmgr_vdev *vdev)
+{
+	struct dp_wrap_vdev *wvdev;
+
+	if (vdev) {
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err(" wvdev is NULL");
+			return NULL;
+		}
+		return &wvdev->wrap_dev_oma[0];
+	}
+	return NULL;
+}
+
+/**
+ * dp_wrap_vdev_get_vma() - Get VMA address of PSTA
+ *
+ * @pdev: handle to the objmgr vdev.
+ * Return: PSTA VMA address
+ */
+static u_int8_t *dp_wrap_vdev_get_vma(struct wlan_objmgr_vdev *vdev)
+{
+	struct dp_wrap_vdev *wvdev;
+
+	if (vdev) {
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err(" wvdev is NULL");
+			return NULL;
+		}
+		return &wvdev->wrap_dev_vma[0];
+	}
+	return NULL;
+}
+
+/**
+ * @brief Find vdev object based on MAC address.
+ *
+ * @param pdev Ptr to pdev obj mgr.
+ * @param mac MAC address to look up.
+ *
+ * @return vdev objmgr on success
+ * @return NULL on failure
+ */
+
+static inline struct wlan_objmgr_vdev *dp_wrap_vdev_vma_find(
+	struct wlan_objmgr_pdev *pdev, unsigned char *mac)
+{
+	dp_vdev_wrap_t *wrap_vdev;
+	int hash;
+	rwlock_state_t lock_state;
+	struct dp_wrap_pdev *wrap_pdev;
+	struct dp_wrap_devt *wdt;
+
+	if (!pdev)
+		return NULL;
+	wrap_pdev = dp_wrap_get_pdev_handle(pdev);
+	if (!wrap_pdev)
+		return NULL;
+	wdt = &wrap_pdev->wp_devt;
+	hash = WRAP_DEV_HASH(mac);
+	OS_RWLOCK_READ_LOCK(&wdt->wdt_lock, &lock_state);
+	LIST_FOREACH(wrap_vdev, &wdt->wdt_hash_vma[hash], wrap_dev_hash_vma) {
+		if (qdf_is_macaddr_equal((struct qdf_mac_addr *)
+		    wrap_vdev->wrap_dev_vma, (struct qdf_mac_addr *)mac)) {
+			OS_RWLOCK_READ_UNLOCK(&wdt->wdt_lock, &lock_state);
+			return wrap_vdev->vdev;
+		}
+	}
+	OS_RWLOCK_READ_UNLOCK(&wdt->wdt_lock, &lock_state);
+
+	return NULL;
+}
+
+int dp_wrap_attach(struct wlan_objmgr_pdev *pdev);
+int dp_wrap_detach(struct wlan_objmgr_pdev *pdev);
+void dp_wrap_vdev_attach(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_vdev_detach(struct wlan_objmgr_vdev *vdev);
+int dp_wrap_dev_add(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_vdev_set_psta(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_vdev_set_mpsta(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_vdev_clear_psta(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_vdev_set_wrap(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_vdev_clear_wrap(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_dev_remove(struct wlan_objmgr_vdev *vdev);
+void dp_wrap_dev_remove_vma(struct wlan_objmgr_vdev *vdev);
+int dp_wrap_rx_process(struct net_device **dev, struct wlan_objmgr_vdev *vdev,
+		       struct sk_buff *skb, int *nwifi);
+int dp_wrap_tx_process(struct net_device **dev, struct wlan_objmgr_vdev *vdev,
+		       struct sk_buff **skb);
+int dp_wrap_mat_tx(struct dp_wrap_vdev *wvdev, wbuf_t buf);
+int dp_wrap_mat_rx(struct dp_wrap_vdev *wvdev, wbuf_t buf);
+void dp_wrap_vdev_set_netdev(struct wlan_objmgr_vdev *vdev,
+			  struct net_device *dev);
+void dp_wrap_register_xmit_handler(struct wlan_objmgr_vdev *vdev,
+				    void (*wlan_vdev_xmit_queue)
+				    (struct net_device *dev, wbuf_t wbuf));
+#endif
+#endif
+#endif

+ 87 - 0
dp_wrap/inc/dp_wrap_struct.h

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020-2021 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 _DP_WRAP_STRUCT_H_
+#define _DP_WRAP_STRUCT_H_
+
+#if ATH_SUPPORT_WRAP
+#if !WLAN_QWRAP_LEGACY
+
+#include <wbuf.h>
+
+#define	WRAP_DEV_HASHSIZE	32	/*dev hash table size*/
+
+/*device table simple hash function*/
+#define	WRAP_DEV_HASH(addr)   \
+	(((const u_int8_t *)(addr))[QDF_MAC_ADDR_SIZE - 1] % WRAP_DEV_HASHSIZE)
+
+#define qwrap_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_WRAP, ## params)
+#define qwrap_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_WRAP, ## params)
+#define qwrap_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_WRAP, ## params)
+#define qwrap_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_WRAP, ## params)
+#define qwrap_trace(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_WRAP, ## params)
+
+#define WRAP_ISOLATION_DEFVAL 0
+
+typedef rwlock_t wrap_devt_lock_t;
+
+/*wrap device table*/
+typedef struct dp_wrap_devt {
+	struct dp_wrap_pdev		*wrap_pdev;
+					/*back ptr to wrap pdev*/
+	wrap_devt_lock_t		wdt_lock;
+					/*lock for dev table*/
+	TAILQ_HEAD(, dp_wrap_vdev)	wdt_dev;	/*head for device list*/
+	ATH_LIST_HEAD(, dp_wrap_vdev)	wdt_hash[WRAP_DEV_HASHSIZE];
+					/*head for device hash*/
+	TAILQ_HEAD(, dp_wrap_vdev)	wdt_dev_vma;	/*head for device list*/
+	ATH_LIST_HEAD(, dp_wrap_vdev)	wdt_hash_vma[WRAP_DEV_HASHSIZE];
+					/*head for device hash*/
+} dp_wrap_devt_t;
+
+/*wrap pdev struct*/
+typedef struct dp_wrap_pdev {
+	struct dp_wrap_devt	wp_devt;        /*wrap device table*/
+	u_int8_t                wp_isolation;
+	int                     wp_use_cnt;     /*wrap pdev use cnt*/
+	struct wlan_objmgr_vdev       *mpsta_vdev;
+	struct wlan_objmgr_vdev        *wrap_vdev;
+	struct net_device       *mpsta_dev;
+	u_int8_t                nwrapvaps;     /* Number of active WRAP APs */
+	u_int8_t                npstavaps;
+} dp_pdev_wrap_t;
+
+/*wrap vdev struct*/
+typedef struct dp_wrap_vdev {
+	struct dp_wrap_pdev	*wrap_pdev;        /*back ptr to wrap pdev*/
+	struct net_device       *dev;
+	struct wlan_objmgr_vdev *vdev;
+	bool                    is_wrap;
+	bool                    is_mpsta;
+	bool                    is_psta;
+	bool                    is_wired_psta;
+	bool                    mat_enabled;
+	unsigned char       wrap_dev_oma[ETH_ALEN]; /* dev oma mac address */
+	unsigned char       wrap_dev_vma[ETH_ALEN]; /* dev vma mac address */
+	TAILQ_ENTRY(dp_wrap_vdev)  wrap_dev_list;	/*wrap oma dev list entry*/
+	LIST_ENTRY(dp_wrap_vdev)   wrap_dev_hash;	/*wrap oma hash list entry*/
+	TAILQ_ENTRY(dp_wrap_vdev)  wrap_dev_list_vma;  /*wrap vma dev list*/
+	LIST_ENTRY(dp_wrap_vdev)   wrap_dev_hash_vma;  /*wrap vma hash list */
+	void (*wlan_vdev_xmit_queue)(struct net_device *dev, wbuf_t wbuf);
+} dp_vdev_wrap_t;
+#endif
+#endif
+#endif

+ 837 - 0
dp_wrap/src/dp_wrap.c

@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 2020-2021 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.
+ */
+
+#if ATH_SUPPORT_WRAP
+#if !WLAN_QWRAP_LEGACY
+#include <qdf_nbuf.h>
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+
+#include "dp_wrap.h"
+
+#include <wlan_utility.h>
+#ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT
+#include "osif_nss_wifiol_if.h"
+#include "osif_nss_wifiol_vdev_if.h"
+#endif
+extern void transcap_nwifi_to_8023(qdf_nbuf_t msdu);
+
+/**
+ * @brief Find wrap vdev object based on MAC address.
+ *
+ * @param wdt Ptr to the wrap device table.
+ * @param mac MAC address to look up.
+ *
+ * @return wrap_vdev on success
+ * @return NULL on failure
+ */
+dp_vdev_wrap_t *dp_wrap_wdev_find(struct dp_wrap_devt *wdt, unsigned char *mac)
+{
+	dp_vdev_wrap_t *wrap_vdev;
+	int hash;
+	rwlock_state_t lock_state;
+
+	hash = WRAP_DEV_HASH(mac);
+	OS_RWLOCK_READ_LOCK(&wdt->wdt_lock, &lock_state);
+	LIST_FOREACH(wrap_vdev, &wdt->wdt_hash[hash], wrap_dev_hash) {
+		if (qdf_is_macaddr_equal((struct qdf_mac_addr *)
+			wrap_vdev->wrap_dev_oma, (struct qdf_mac_addr *)mac)) {
+			OS_RWLOCK_READ_UNLOCK(&wdt->wdt_lock, &lock_state);
+			return wrap_vdev;
+		}
+	}
+	OS_RWLOCK_READ_UNLOCK(&wdt->wdt_lock, &lock_state);
+	return NULL;
+}
+
+/**
+ * @brief Find wrap vdev object based on MAC address.
+ *
+ * @param wdt Ptr to the wrap device table.
+ * @param mac MAC address to look up.
+ *
+ * @return wrap_vdev on success
+ * @return NULL on failure
+ */
+
+dp_vdev_wrap_t *dp_wrap_wdev_vma_find(struct dp_wrap_devt *wdt, unsigned char *mac)
+{
+	dp_vdev_wrap_t *wrap_vdev;
+	int hash;
+	rwlock_state_t lock_state;
+
+	hash = WRAP_DEV_HASH(mac);
+	OS_RWLOCK_READ_LOCK(&wdt->wdt_lock, &lock_state);
+	LIST_FOREACH(wrap_vdev, &wdt->wdt_hash_vma[hash], wrap_dev_hash_vma) {
+		if (qdf_is_macaddr_equal((struct qdf_mac_addr *)
+			wrap_vdev->wrap_dev_vma, (struct qdf_mac_addr *)mac)) {
+			OS_RWLOCK_READ_UNLOCK(&wdt->wdt_lock, &lock_state);
+			return wrap_vdev;
+		}
+	}
+	OS_RWLOCK_READ_UNLOCK(&wdt->wdt_lock, &lock_state);
+	return NULL;
+}
+
+/**
+ * @brief Add wrap vdev object to the device table, also
+ * registers bridge hooks if this the first object.
+ *
+ * @param vdev objmgr Pointer to wrap_vdev to add.
+ *
+ * @return 0 on success
+ * @return -ve on failure
+ */
+int dp_wrap_dev_add(struct wlan_objmgr_vdev *vdev)
+{
+	int hash, hash_vma;
+	struct dp_wrap_pdev *wrap_pdev;
+	struct dp_wrap_vdev *wrap_vdev;
+	struct dp_wrap_devt *wdt;
+	rwlock_state_t lock_state;
+
+	wrap_pdev = dp_wrap_get_pdev_handle(wlan_vdev_get_pdev(vdev));
+	if (!wrap_pdev) {
+		qwrap_err(" wrap_pdev is NULL");
+		return -EINVAL;
+	}
+	wrap_vdev = dp_wrap_get_vdev_handle(vdev);
+	if (!wrap_vdev) {
+		qwrap_err(" wrap_vdev is NULL");
+		return -EINVAL;
+	}
+	wdt = &wrap_pdev->wp_devt;
+	hash = WRAP_DEV_HASH(wrap_vdev->wrap_dev_oma);
+	hash_vma = WRAP_DEV_HASH(wrap_vdev->wrap_dev_vma);
+	OS_RWLOCK_WRITE_LOCK_BH(&wdt->wdt_lock, &lock_state);
+	LIST_INSERT_HEAD(&wdt->wdt_hash[hash], wrap_vdev, wrap_dev_hash);
+	TAILQ_INSERT_TAIL(&wdt->wdt_dev, wrap_vdev, wrap_dev_list);
+	LIST_INSERT_HEAD(&wdt->wdt_hash_vma[hash_vma], wrap_vdev,
+			 wrap_dev_hash_vma);
+	TAILQ_INSERT_TAIL(&wdt->wdt_dev_vma, wrap_vdev, wrap_dev_list_vma);
+	OS_RWLOCK_WRITE_UNLOCK_BH(&wdt->wdt_lock, &lock_state);
+	qwrap_info("Added vdev:%d to the list mat. pdev_id:%d",
+		   vdev->vdev_objmgr.vdev_id,
+		   wlan_objmgr_pdev_get_pdev_id(
+		   wlan_vdev_get_pdev(vdev)));
+	return 0;
+}
+
+/**
+ * @brief Delete wrap dev object from the device table,
+ * based on OMA address.
+ *
+ * @param vdev objmgr Pointer to wrap_vdev to delete.
+ *
+ * @return void
+ */
+void dp_wrap_dev_remove(struct wlan_objmgr_vdev *vdev)
+{
+	int hash;
+	struct dp_wrap_vdev *wrap_vdev, *wvdev, *temp;
+	struct dp_wrap_pdev *wrap_pdev;
+	struct dp_wrap_devt *wdt;
+	rwlock_state_t lock_state;
+
+	wrap_pdev = dp_wrap_get_pdev_handle(wlan_vdev_get_pdev(vdev));
+	if (!wrap_pdev) {
+		qwrap_err(" wrap_pdev is NULL");
+		return;
+	}
+	wrap_vdev = dp_wrap_get_vdev_handle(vdev);
+	if (!wrap_vdev) {
+		qwrap_err(" wrap_vdev is NULL");
+		return;
+	}
+	wdt = &wrap_pdev->wp_devt;
+	hash = WRAP_DEV_HASH(wrap_vdev->wrap_dev_oma);
+	OS_RWLOCK_WRITE_LOCK_BH(&wdt->wdt_lock, &lock_state);
+	LIST_FOREACH_SAFE(wvdev, &wdt->wdt_hash[hash], wrap_dev_hash, temp) {
+		if ((wvdev == wrap_vdev) &&
+		    qdf_is_macaddr_equal((struct qdf_mac_addr *)
+			wvdev->wrap_dev_oma,
+			(struct qdf_mac_addr *)wrap_vdev->wrap_dev_oma)) {
+			LIST_REMOVE(wvdev, wrap_dev_hash);
+			TAILQ_REMOVE(&wdt->wdt_dev, wvdev, wrap_dev_list);
+			OS_RWLOCK_WRITE_UNLOCK_BH(&wdt->wdt_lock, &lock_state);
+			qwrap_info("Removed vdev:%d from OMA list. pdev_id:%d",
+				   vdev->vdev_objmgr.vdev_id,
+				   wlan_objmgr_pdev_get_pdev_id(
+				   wlan_vdev_get_pdev(vdev)));
+			return;
+		}
+	}
+	OS_RWLOCK_WRITE_UNLOCK_BH(&wdt->wdt_lock, &lock_state);
+}
+
+/**
+ * @brief Delete wrap dev object from the device table,
+ * based on VMA address.
+ *
+ * @param vdev objmgr Pointer to wrap_vdev to delete.
+ *
+ * @return void
+ */
+void dp_wrap_dev_remove_vma(struct wlan_objmgr_vdev *vdev)
+{
+	int hash;
+	struct dp_wrap_vdev *wrap_vdev, *wvdev, *temp;
+	struct dp_wrap_pdev *wrap_pdev;
+	struct dp_wrap_devt *wdt;
+	rwlock_state_t lock_state;
+
+	wrap_pdev = dp_wrap_get_pdev_handle(wlan_vdev_get_pdev(vdev));
+	if (!wrap_pdev) {
+		qwrap_err(" wrap_pdev is NULL");
+		return;
+	}
+	wrap_vdev = dp_wrap_get_vdev_handle(vdev);
+	if (!wrap_vdev) {
+		qwrap_err(" wrap_vdev is NULL");
+		return;
+	}
+	wdt = &wrap_pdev->wp_devt;
+	hash = WRAP_DEV_HASH(wrap_vdev->wrap_dev_vma);
+	OS_RWLOCK_WRITE_LOCK_BH(&wdt->wdt_lock, &lock_state);
+	LIST_FOREACH_SAFE(wvdev, &wdt->wdt_hash_vma[hash],
+			  wrap_dev_hash_vma, temp) {
+		if ((wvdev == wrap_vdev) &&
+		    qdf_is_macaddr_equal((struct qdf_mac_addr *)
+			wvdev->wrap_dev_vma,
+			(struct qdf_mac_addr *)wrap_vdev->wrap_dev_vma)) {
+			LIST_REMOVE(wvdev, wrap_dev_hash_vma);
+			TAILQ_REMOVE(&wdt->wdt_dev_vma, wvdev,
+				     wrap_dev_list_vma);
+			OS_RWLOCK_WRITE_UNLOCK_BH(&wdt->wdt_lock, &lock_state);
+			qwrap_info("Removed vdev:%d from vma list. pdev_id:%d",
+				   vdev->vdev_objmgr.vdev_id,
+				   wlan_objmgr_pdev_get_pdev_id(
+				   wlan_vdev_get_pdev(vdev)));
+			return;
+		}
+	}
+	OS_RWLOCK_WRITE_UNLOCK_BH(&wdt->wdt_lock, &lock_state);
+}
+
+/**
+ * @brief WRAP device table attach
+ *
+ * @param pdev objmgr Pointer.
+ * @param wdt Ptr to wrap device table.
+ *
+ * @return void
+ */
+static void dp_wrap_devt_init(struct dp_wrap_pdev *wpdev, struct dp_wrap_devt *wdt)
+{
+	int i;
+
+	OS_RWLOCK_INIT(&wdt->wdt_lock);
+	TAILQ_INIT(&wdt->wdt_dev);
+	TAILQ_INIT(&wdt->wdt_dev_vma);
+	for (i = 0; i < WRAP_DEV_HASHSIZE; i++) {
+		LIST_INIT(&wdt->wdt_hash[i]);
+		LIST_INIT(&wdt->wdt_hash_vma[i]);
+	}
+	wdt->wrap_pdev = wpdev;
+}
+
+/**
+ * @brief wrap device table detach
+ *
+ * @param pdev objmgr Pointer.
+ *
+ * @return
+ */
+static void dp_wrap_devt_detach(struct dp_wrap_pdev *wpdev)
+{
+	struct dp_wrap_devt *wdt = &wpdev->wp_devt;
+
+	OS_RWLOCK_DESTROY(&wdt->wdt_lock);
+	wdt->wrap_pdev = NULL;
+}
+
+/**
+ * @brief wrap attach
+ *
+ * @param pdev objmgr Pointer.
+ *
+ * @return 0 on success
+ * @return -ve on failure
+ */
+int dp_wrap_attach(struct wlan_objmgr_pdev *pdev)
+{
+	int ret = 0;
+	struct dp_wrap_pdev *wrap_pdev = dp_wrap_get_pdev_handle(pdev);
+
+	if (!wrap_pdev) {
+		qwrap_err(" wrap_pdev is NULL");
+		return -EINVAL;
+	}
+
+	OS_MEMZERO(wrap_pdev, sizeof(struct dp_wrap_pdev));
+	wrap_pdev->wp_use_cnt++;
+	dp_wrap_devt_init(wrap_pdev, &wrap_pdev->wp_devt);
+	wrap_pdev->wp_isolation = WRAP_ISOLATION_DEFVAL;
+	qwrap_info("Wrap Attached: Wrap_pdev =%pK &wrap_pdev->wp_devt=%pK",
+		   wrap_pdev, &wrap_pdev->wp_devt);
+	return ret;
+}
+qdf_export_symbol(dp_wrap_attach);
+
+/**
+ * @brief wrap vdev attach
+ *
+ * @param vdev objmgr Pointer.
+ *
+ * @return void
+ */
+void dp_wrap_vdev_attach(struct wlan_objmgr_vdev *vdev)
+{
+	if (dp_wrap_vdev_is_psta(vdev)) {
+		dp_wrap_vdev_set_psta(vdev);
+		if (dp_wrap_vdev_is_mpsta(vdev))
+			dp_wrap_vdev_set_mpsta(vdev);
+	}
+	if (dp_wrap_vdev_is_wrap(vdev))
+		dp_wrap_vdev_set_wrap(vdev);
+}
+
+/**
+ * @brief wrap vdev detach
+ *
+ * @param vdev objmgr Pointer.
+ *
+ * @return void
+ */
+void dp_wrap_vdev_detach(struct wlan_objmgr_vdev *vdev)
+{
+	if (dp_wrap_vdev_is_psta(vdev))
+		dp_wrap_vdev_clear_psta(vdev);
+	if (dp_wrap_vdev_is_wrap(vdev))
+		dp_wrap_vdev_clear_wrap(vdev);
+}
+
+/**
+ * @brief wrap detach
+ *
+ * @param pdev objmgr Pointer.
+ *
+ * @return 0 on success
+ * @return -ve on failure
+ */
+int dp_wrap_detach(struct wlan_objmgr_pdev *pdev)
+{
+	int ret = 0;
+	struct dp_wrap_pdev *wrap_pdev = dp_wrap_get_pdev_handle(pdev);
+
+	if (!wrap_pdev) {
+		qwrap_err(" wrap_pdev is NULL");
+		return -EINVAL;
+	}
+	wrap_pdev->wp_use_cnt--;
+	if (wrap_pdev->wp_use_cnt == 0) {
+		dp_wrap_devt_detach(wrap_pdev);
+		qwrap_info("qca wrap detached\n");
+	}
+	return ret;
+}
+qdf_export_symbol(dp_wrap_detach);
+
+/**
+ * dp_wrap_vdev_set_psta() - Set psta flag
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: void
+ */
+void dp_wrap_vdev_set_psta(struct wlan_objmgr_vdev *vdev)
+{
+	struct dp_wrap_vdev *wvdev;
+	struct dp_wrap_pdev *wpdev;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (vdev) {
+		pdev = vdev->vdev_objmgr.wlan_pdev;
+		if (!pdev) {
+			qwrap_err(" pdev is NULL");
+			return;
+		}
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wrap_pdev is NULL");
+			return;
+		}
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err(" wrap_vdev is NULL");
+			return;
+		}
+		OS_MEMZERO(wvdev, sizeof(struct dp_wrap_vdev));
+		wvdev->wrap_pdev = wpdev;
+		wvdev->is_psta = 1;
+		wvdev->vdev = vdev;
+		wpdev->npstavaps++;
+		if (dp_wrap_vdev_is_wired_psta(vdev))
+			wvdev->is_wired_psta = 1;
+		if (dp_wrap_vdev_is_mat_set(vdev)) {
+			wvdev->mat_enabled = 1;
+			WLAN_ADDR_COPY(wvdev->wrap_dev_oma,
+				       vdev->vdev_mlme.mataddr);
+		} else {
+			WLAN_ADDR_COPY(wvdev->wrap_dev_oma,
+				       vdev->vdev_mlme.macaddr);
+		}
+		WLAN_ADDR_COPY(wvdev->wrap_dev_vma, vdev->vdev_mlme.macaddr);
+		qwrap_info("set PSTA flags for vdev_id:%d pdev_id:%d OMA addr:"
+				QDF_MAC_ADDR_FMT "Vma addr:" QDF_MAC_ADDR_FMT,
+				vdev->vdev_objmgr.vdev_id,
+				wlan_objmgr_pdev_get_pdev_id(pdev),
+				QDF_MAC_ADDR_REF(wvdev->wrap_dev_oma),
+				QDF_MAC_ADDR_REF(wvdev->wrap_dev_vma));
+	}
+}
+
+/**
+ * dp_wrap_vdev_clear_psta() - clear psta flag
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: void
+ */
+void dp_wrap_vdev_clear_psta(struct wlan_objmgr_vdev *vdev)
+{
+	struct dp_wrap_pdev *wpdev;
+	struct dp_wrap_vdev *wvdev;
+
+	if (vdev) {
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err(" wrap_vdev is NULL");
+			return;
+		}
+		wpdev = wvdev->wrap_pdev;
+		if (!wpdev) {
+			qwrap_err(" wrap_pdev is NULL");
+			return;
+		}
+		wpdev->npstavaps--;
+		if (wvdev->is_mpsta) {
+			wpdev->mpsta_vdev = NULL;
+			wpdev->mpsta_dev = NULL;
+		}
+		qwrap_info("clear PSTA flag vdev_id:%d pdev_id:%d mpsta:%d",
+			   vdev->vdev_objmgr.vdev_id,
+			   wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev
+			   (vdev)), wvdev->is_mpsta);
+	}
+}
+
+/**
+ * dp_wrap_vdev_set_mpsta() - Set mpsta flag
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: void
+ */
+void dp_wrap_vdev_set_mpsta(struct wlan_objmgr_vdev *vdev)
+{
+	struct dp_wrap_vdev *wvdev;
+	struct dp_wrap_pdev *wpdev;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (vdev) {
+		pdev = vdev->vdev_objmgr.wlan_pdev;
+		if (!pdev) {
+			qwrap_err(" pdev is NULL");
+			return;
+		}
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wrap_pdev is NULL");
+			return;
+		}
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err(" wrap_vdev is NULL");
+			return;
+		}
+		wvdev->is_mpsta = 1;
+		wpdev->mpsta_vdev = vdev;
+		qwrap_info("set MPSTA flags vdev_id:%d pdev_id:%d OMA addr:"
+				QDF_MAC_ADDR_FMT "Vma addr:" QDF_MAC_ADDR_FMT,
+				vdev->vdev_objmgr.vdev_id,
+				wlan_objmgr_pdev_get_pdev_id(pdev),
+				QDF_MAC_ADDR_REF(wvdev->wrap_dev_oma),
+				QDF_MAC_ADDR_REF(wvdev->wrap_dev_vma));
+	}
+}
+
+/**
+ * dp_wrap_vdev_set_wrap() - set wrap flag
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: void
+ */
+void dp_wrap_vdev_set_wrap(struct wlan_objmgr_vdev *vdev)
+{
+	struct dp_wrap_vdev *wvdev;
+	struct dp_wrap_pdev *wpdev;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (vdev) {
+		pdev = vdev->vdev_objmgr.wlan_pdev;
+		if (!pdev) {
+			qwrap_err(" pdev is NULL");
+			return;
+		}
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wrap_pdev is NULL");
+			return;
+		}
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err(" wrap_vdev is NULL");
+			return;
+		}
+		OS_MEMZERO(wvdev, sizeof(struct dp_wrap_vdev));
+		wvdev->wrap_pdev = wpdev;
+		wvdev->is_wrap = 1;
+		wvdev->vdev = vdev;
+		wpdev->wrap_vdev = vdev;
+		wpdev->nwrapvaps++;
+		qwrap_info("set WRAP flags for vdev_id:%d pdev_id:%d OMA addr:"
+				QDF_MAC_ADDR_FMT "Vma addr:" QDF_MAC_ADDR_FMT,
+				vdev->vdev_objmgr.vdev_id,
+				wlan_objmgr_pdev_get_pdev_id(pdev),
+				QDF_MAC_ADDR_REF(wvdev->wrap_dev_oma),
+				QDF_MAC_ADDR_REF(wvdev->wrap_dev_vma));
+	}
+}
+
+/**
+ * dp_wrap_vdev_clear_wrap() - clear wrap flag
+ *
+ * @vdev: handle to the objmgr vdev.
+ * Return: void
+ */
+void dp_wrap_vdev_clear_wrap(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_pdev *pdev;
+	struct dp_wrap_pdev *wpdev;
+
+	if (vdev) {
+		pdev = vdev->vdev_objmgr.wlan_pdev;
+		if (!pdev) {
+			qwrap_err(" pdev is NULL");
+			return;
+		}
+		wpdev = dp_wrap_get_pdev_handle(pdev);
+		if (!wpdev) {
+			qwrap_err(" wpdev is NULL");
+			return;
+		}
+		wpdev->wrap_vdev = NULL;
+		wpdev->nwrapvaps--;
+		qwrap_info("clear WRAP flags for vdev_id:%d pdev_id:%d",
+			   vdev->vdev_objmgr.vdev_id,
+			   wlan_objmgr_pdev_get_pdev_id(pdev));
+	}
+}
+
+static inline int
+dp_wrap_tx_bridge(struct wlan_objmgr_vdev *vdev, struct dp_wrap_vdev **wvdev,
+		  struct sk_buff **skb) {
+	/* Assuming native wifi or raw mode is not
+	 * enabled in beeliner, to be revisted later
+	 */
+	struct ether_header *eh = (struct ether_header *)((*skb)->data);
+	struct dp_wrap_pdev *wpdev;
+	struct dp_wrap_vdev *wrap_vdev;
+
+	/* Mpsta vap here, find the correct tx vap from the wrap
+	 * common based on src address
+	 */
+	wpdev = dp_wrap_get_pdev_handle(wlan_vdev_get_pdev(vdev));
+	if (qdf_unlikely(!wpdev))
+		return 1;
+	wrap_vdev = dp_wrap_wdev_find(&wpdev->wp_devt, eh->ether_shost);
+	if (qdf_unlikely(!wrap_vdev))
+		return 1;
+	*wvdev = wrap_vdev;
+	if (wrap_vdev) {
+		if (qdf_unlikely((IEEE80211_IS_MULTICAST(eh->ether_dhost) ||
+				  IEEE80211_IS_BROADCAST(eh->ether_dhost)))) {
+			*skb = qdf_nbuf_unshare(*skb);
+		}
+		return 0;
+	} else {
+		/* When proxysta is not created, drop the packet. Donot send
+		 * packet on mainproxysta. Return 1 here to drop the packet
+		 * when psta is not yet created.
+		 */
+		qwrap_err("Drop pkt, PSTA is not created src mac:"
+			  QDF_MAC_ADDR_FMT "vdev_id:%d", QDF_MAC_ADDR_REF
+			  (eh->ether_shost), vdev->vdev_objmgr.vdev_id);
+		return 1;
+	}
+}
+
+int dp_wrap_tx_process(struct net_device **dev, struct wlan_objmgr_vdev *vdev,
+		       struct sk_buff **skb)
+{
+	struct dp_wrap_vdev *wvdev = NULL;
+	struct ether_header *eh;
+
+	if (qdf_unlikely(dp_wrap_vdev_is_mpsta(vdev))) {
+		if (dp_wrap_tx_bridge(vdev, &wvdev, skb))
+			return 1;
+		if (*(skb) == NULL) {
+			qwrap_err("Drop pkt, SKB is null dev_id:%d",
+				  vdev->vdev_objmgr.vdev_id);
+			return 1;
+		}
+		eh = (struct ether_header *)((*skb)->data);
+		if (qdf_likely(dp_wrap_vdev_is_psta(wvdev->vdev))) {
+			if (dp_wrap_mat_tx(wvdev, (wbuf_t)*skb)) {
+				qwrap_err("Drop pkt,MAT error:"QDF_MAC_ADDR_FMT
+					   "vdev_id:%d", QDF_MAC_ADDR_REF(
+					   eh->ether_shost),
+					   vdev->vdev_objmgr.vdev_id);
+				return 1;
+			}
+		}
+		*dev = wvdev->dev;
+		vdev = wvdev->vdev;
+	}
+	if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) {
+		qwrap_err("Drop pkt, vdev is not up:"QDF_MAC_ADDR_FMT
+			  "vdevid:%d", QDF_MAC_ADDR_REF(eh->ether_shost),
+			  vdev->vdev_objmgr.vdev_id);
+		return 1;
+	}
+	return 0;
+}
+qdf_export_symbol(dp_wrap_tx_process);
+
+static inline
+int dp_wrap_rx_bridge(struct wlan_objmgr_vdev *vdev, struct net_device **dev,
+		      struct dp_wrap_vdev *wvdev, struct sk_buff *skb)
+{
+	/* Assuming native wifi or raw mode is not
+	 * enabled in beeliner, to be revisted later
+	 */
+	struct ether_header *eh = (struct ether_header *)skb->data;
+	struct dp_wrap_pdev *wpdev = wvdev->wrap_pdev;
+	int isolation = wpdev->wp_isolation;
+	int ret = 0;
+	struct dp_wrap_vdev *mpsta_wvdev, *wrap_wvdev, *t_wvdev;
+	struct wlan_objmgr_vdev *mpsta_vdev, *wrap_vdev;
+
+	mpsta_vdev = wpdev->mpsta_vdev;
+	wrap_vdev = wpdev->wrap_vdev;
+	if (isolation == 0) {
+		/* Isolatio mode,Wired and wireless clients connected
+		 * to Qwrap Ap can talk through Qwrap bridge
+		 */
+		if ((wvdev->is_mpsta == 0) && (wvdev->is_psta) &&
+		    (mpsta_vdev)) {
+			if (qdf_likely(
+				!(eh->ether_type == htons(ETHERTYPE_PAE)))) {
+				/*get mpsta vap , for qwrap bridge learning
+				 * is always through main proxy sta
+				 */
+				skb->dev = wpdev->mpsta_dev;
+				*dev = skb->dev;
+			}
+			ret = 0;
+		}
+	} else {
+		/* isolation mode enabled. Wired and wireless client
+		 * connected to Qwrap AP can talk through root AP
+		 */
+		if (wvdev->is_psta && !wvdev->is_mpsta &&
+		    wvdev->is_wired_psta) {
+			/* Packets recevied through wired psta vap */
+			if (qdf_likely(!(eh->ether_type == htons(ETHERTYPE_PAE)
+					)) && (mpsta_vdev)) {
+				/* rx packets from wired psta should go through
+				 * bridge.Here qwrap bridge learning for wired
+				 * proxy clients is always through mpsta
+				 */
+				skb->dev = wpdev->mpsta_dev;
+				*dev = skb->dev;
+				ret = 0;
+			}
+		} else if (wvdev->is_psta && !wvdev->is_mpsta &&
+			  !wvdev->is_wired_psta &&
+			  !(eh->ether_type == htons(ETHERTYPE_PAE)) &&
+			  (wrap_vdev)) {
+			/* rx unicast from wireless proxy, client
+			 * should always xmit through wrap AP vap
+			 */
+			wrap_wvdev = dp_wrap_get_vdev_handle(wrap_vdev);
+			wrap_wvdev->wlan_vdev_xmit_queue(wrap_wvdev->dev, skb);
+			ret = 1;
+		} else if ((wvdev->is_wrap &&
+			   !(eh->ether_type == htons(ETHERTYPE_PAE))) &&
+			   (mpsta_vdev)) {
+			/* rx from wrap AP , since wrap not connected to
+			 * in isolation , should always xmit through
+			 * main proxy vap
+			 */
+			mpsta_wvdev = dp_wrap_get_vdev_handle(mpsta_vdev);
+			mpsta_wvdev->wlan_vdev_xmit_queue(
+							mpsta_wvdev->dev, skb);
+			ret = 1;
+		} else if (wvdev->is_mpsta &&
+			   IEEE80211_IS_MULTICAST(eh->ether_dhost) &&
+			   (mpsta_vdev) && (wrap_vdev)) {
+			/*check oma or vma, for MPSTA both are same*/
+			mpsta_wvdev = dp_wrap_get_vdev_handle(mpsta_vdev);
+			if ((OS_MEMCMP(mpsta_wvdev->wrap_dev_oma,
+				       eh->ether_shost, 6) == 0))  {
+				/* Multicast orginated from mpsta/bridge
+				 * should always xmit through wrap AP vap
+				 */
+				wrap_wvdev = dp_wrap_get_vdev_handle(
+						wrap_vdev);
+				wrap_wvdev->wlan_vdev_xmit_queue(
+						wrap_wvdev->dev, skb);
+				ret = 1;
+			} else {
+				t_wvdev = dp_wrap_wdev_vma_find(
+						&wpdev->wp_devt,
+						eh->ether_shost);
+				if (t_wvdev) {
+					if (t_wvdev->is_wired_psta) {
+						/*Multicast received from wired
+						 *clients , forward to wrap AP
+						 */
+						wrap_wvdev =
+						dp_wrap_get_vdev_handle(
+								wrap_vdev);
+						wrap_wvdev->
+							wlan_vdev_xmit_queue
+							(wrap_wvdev->dev, skb);
+						ret = 1;
+					} else {
+						/*Multicast received from
+						 *wireless client,fwd to bridge
+						 */
+						skb->dev = wpdev->mpsta_dev;
+						*dev = skb->dev;
+						ret = 0;
+					}
+				} else  {
+					qdf_nbuf_t copy;
+
+					copy = qdf_nbuf_copy(skb);
+					/*Multicast received from client behind
+					 *root side forward to both wrap and
+					 *bridge side
+					 */
+					if (copy) {
+						wrap_wvdev =
+						dp_wrap_get_vdev_handle(
+								wrap_vdev);
+						wrap_wvdev->
+						wlan_vdev_xmit_queue(
+							wrap_wvdev->dev, copy);
+					} else {
+						qdf_err("Wrap buf cpy fail");
+					}
+					skb->dev = wpdev->mpsta_dev;
+					*dev = skb->dev;
+					ret = 0;
+				}
+			}
+		}
+	}
+	return ret;
+}
+
+int dp_wrap_rx_process(struct net_device **dev, struct wlan_objmgr_vdev *vdev,
+		       struct sk_buff *skb, int *nwifi)
+{
+	struct dp_wrap_vdev *wvdev;
+	int rv = 0;
+
+	wvdev = dp_wrap_get_vdev_handle(vdev);
+
+	if (qdf_unlikely(dp_wrap_vdev_is_psta(vdev) || dp_wrap_vdev_is_wrap(vdev))) {
+		if (*nwifi) {
+			transcap_nwifi_to_8023(skb);
+			*nwifi = 0;
+		}
+		dp_wrap_mat_rx(wvdev, (wbuf_t)skb);
+		rv = dp_wrap_rx_bridge(vdev, dev, wvdev, skb);
+	}
+	return rv;
+}
+qdf_export_symbol(dp_wrap_rx_process);
+
+void
+dp_wrap_vdev_set_netdev(struct wlan_objmgr_vdev *vdev, struct net_device *dev)
+{
+	struct dp_wrap_vdev *wvdev;
+	struct dp_wrap_pdev *wpdev;
+	struct wlan_objmgr_pdev *pdev;
+
+	if (vdev) {
+		wvdev = dp_wrap_get_vdev_handle(vdev);
+		if (!wvdev) {
+			qwrap_err("wrap_vdev is NULL");
+			return;
+		}
+		wvdev->dev = dev;
+		if (dp_wrap_vdev_is_mpsta(vdev)) {
+			pdev = vdev->vdev_objmgr.wlan_pdev;
+			if (!pdev) {
+				qwrap_err("pdev is NULL");
+				return;
+			}
+			wpdev = dp_wrap_get_pdev_handle(pdev);
+			if (!wpdev) {
+				qwrap_err(" wpdev is NULL");
+				return;
+			}
+			wpdev->mpsta_dev = dev;
+		}
+	}
+}
+
+/**
+ * dp_wrap_register_xmit_handler() - Register xmit handler in wrap_vdev object
+ *
+ * @vdev: handle to the objmgr vdev
+ * @func: xmit handler function to register
+ * Return: void
+ */
+void dp_wrap_register_xmit_handler(struct wlan_objmgr_vdev *vdev,
+				    void (*wlan_vdev_xmit_queue)
+				    (struct net_device *dev, wbuf_t wbuf))
+{
+	struct dp_wrap_vdev *wrap_vdev;
+
+	wrap_vdev = dp_wrap_get_vdev_handle(vdev);
+
+	if (wrap_vdev)
+		wrap_vdev->wlan_vdev_xmit_queue = wlan_vdev_xmit_queue;
+	else
+		qwrap_err("Error in registering xmit queue");
+}
+#endif
+#endif

+ 590 - 0
dp_wrap/src/dp_wrap_mat.c

@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2020-2021 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.
+ */
+
+#if ATH_SUPPORT_WRAP
+#if !WLAN_QWRAP_LEGACY
+/*WRAP includes for MAT*/
+#include <linux/udp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ndisc.h>
+#include <net/arp.h>
+#include "asf_print.h"    /* asf_print_setup */
+#include "qdf_mem.h"   /* qdf_mem_malloc,free */
+#include "qdf_lock.h"  /* qdf_spinlock_* */
+#include "qdf_types.h" /* qdf_vprint */
+#include "dp_wrap.h"
+#include "ol_if_athvar.h"
+
+extern char *arps[];
+
+extern void
+compute_udp_checksum(qdf_net_iphdr_t *p_iph, unsigned short  *ip_payload);
+
+static u16
+checksum(u16 protocol, u16 len, u8 src_addr[], u8 dest_addr[],
+	 u16 addrleninbytes, u8 *buff)
+{
+	u16 pad = 0;
+	u16 word16;
+	u32 sum = 0;
+	int i;
+
+	/* Find out if the length of data is even or odd number. If odd,
+	 * add a padding byte = 0 at the end of packet
+	 */
+	if (len & 1) {
+		/* Take care of the last byte by itself. */
+		len -= 1;
+		pad = 1;
+	}
+
+	/* make 16 bit words out of every two adjacent 8 bit words and
+	 * calculate the sum of all 16 bit words
+	 */
+	for (i = 0; i < len; i = i + 2) {
+		word16 = buff[i];
+		word16 = (word16 << 8) + buff[i + 1];
+		sum = sum + (u32)word16;
+	}
+
+	if (pad) {
+		/* Get the last byte */
+		word16 = buff[len];
+		word16 <<= 8;
+		sum = sum + (u32)word16;
+	}
+
+	/* add the UDP pseudo header which contains the IP source and
+	 * destination addresses.
+	 */
+	for (i = 0; i < addrleninbytes; i = i + 2) {
+		word16 = src_addr[i];
+		word16 = (word16 << 8) + src_addr[i + 1];
+		sum = sum + (u32)word16;
+	}
+
+	for (i = 0; i < addrleninbytes; i = i + 2) {
+		word16 = dest_addr[i];
+		word16 = (word16 << 8) + dest_addr[i + 1];
+		sum = sum + (u32)word16;
+	}
+
+	/* the protocol number and the length of the s packet */
+	sum = sum + (u32)protocol + (u32)(len + pad);
+
+	/* keep only the last 16 bits of the 32 bit calculated sum and
+	 *  add back the carries
+	 */
+	while (sum >> 16) {
+		sum = (sum & 0xFFFF) + (sum >> 16);
+	}
+
+	/* Take the one's complement of sum */
+	sum = ~sum;
+
+	return (u16)sum;
+}
+
+struct eth_arphdr {
+	unsigned short	ar_hrd,	/* format of hardware address */
+			ar_pro;	/* format of protocol address */
+	unsigned char	ar_hln,	/* length of hardware address */
+			ar_pln;	/* length of protocol address */
+	unsigned short	ar_op;	/* ARP opcode (command) */
+	unsigned char	ar_sha[ETH_ALEN],	/* sender hardware address */
+			ar_sip[4],		/* sender IP address */
+			ar_tha[ETH_ALEN],	/* target hardware address */
+			ar_tip[4];		/* target IP address */
+} __attribute__((__packed__));
+
+struct dhcp_option {
+	u_char type;
+	u_char len;
+	u_char value[0];	/* option value*/
+} __attribute__((__packed__));
+
+struct dhcp_packet {
+	u_char              op;          /* packet opcode type */
+	u_char              htype;       /* hardware addr type */
+	u_char              hlen;        /* hardware addr length */
+	u_char              hops;        /* gateway hops */
+	u32           xid;         /* transaction ID */
+	u16           secs;        /* seconds since boot began */
+	u16           flags;       /* flags */
+	struct in_addr      ciaddr;      /* client IP address */
+	struct in_addr      yiaddr;      /* 'your' IP address */
+	struct in_addr      siaddr;      /* server IP address */
+	struct in_addr      giaddr;      /* gateway IP address */
+	u_char              chaddr[16];  /* client hardware address */
+	u_char              sname[64];   /* server host name */
+	u_char              file[128];   /* boot file name */
+	u_char              magic_cookie[4];   /* magic cookie */
+	u_char              options[0];  /* variable-length options field */
+} __attribute__((__packed__));
+
+struct eth_icmp6_lladdr {
+	unsigned char type;
+	unsigned char len;
+	unsigned char addr[6];	/* hardware address */
+} __attribute__((__packed__));
+
+typedef struct eth_icmp6_lladdr eth_icmp6_lladdr_t;
+/* Option: (53) DHCP Message Type  */
+#define OPTION_DHCP_MSG_TYPE   0x35
+ /* DHCP: Discover (1) */
+#define DHCP_DISOVER    1
+/*Option: (50) Requested IP Address */
+#define OPTION_DHCP_REQUESTED_IP_ADDR   0x32
+
+/**
+ * @brief WRAP MAT function for transmit.
+ *
+ * @param wrap_vdev handle.
+ * @param buf
+ *
+ * @return 0 On success.
+ * @return -ve On failure.
+ */
+int dp_wrap_mat_tx(struct dp_wrap_vdev *wvdev, wbuf_t buf)
+{
+	struct ether_header *eh;
+	u16 ether_type;
+	int contig_len = sizeof(struct ether_header);
+	int pktlen = wbuf_get_pktlen(buf);
+	u8 *src_mac, *des_mac, *p, ismcast;
+	u8 *arp_smac = NULL;
+	u8 *arp_dmac = NULL;
+	struct eth_arphdr *parp = NULL;
+
+	if (!wvdev->mat_enabled)
+		return 0;
+
+	if (pktlen < contig_len)
+		return -EINVAL;
+
+	eh = (struct ether_header *)(wbuf_header(buf));
+	p = (u8 *)(eh + 1);
+
+	ether_type = eh->ether_type;
+	src_mac = eh->ether_shost;
+	des_mac = eh->ether_dhost;
+	ismcast = IEEE80211_IS_MULTICAST(des_mac);
+
+	qwrap_trace("src mac:" QDF_MAC_ADDR_FMT " dst mac: "
+		    " "QDF_MAC_ADDR_FMT " "
+		    "ether type: %d", QDF_MAC_ADDR_REF(src_mac),
+		    QDF_MAC_ADDR_REF(des_mac), ether_type);
+
+	if (ether_type == htons(ETH_P_PAE))
+		return 0;
+
+	if (ether_type == htons(ETHERTYPE_ARP)) {
+		parp = (struct eth_arphdr *)p;
+		contig_len += sizeof(struct eth_arphdr);
+
+		if (pktlen < contig_len)
+			return -EINVAL;
+
+		if (parp->ar_hln == ETH_ALEN &&
+		    parp->ar_pro == htons(ETH_P_IP)) {
+			arp_smac = parp->ar_sha;
+			arp_dmac = parp->ar_tha;
+		} else {
+			parp = NULL;
+		}
+	}
+
+	if (parp) {
+		if (parp->ar_op == htons(ARPOP_REQUEST) ||
+		    parp->ar_op == htons(ARPOP_REPLY)) {
+			IEEE80211_ADDR_COPY(arp_smac, wvdev->wrap_dev_vma);
+			qwrap_debug("ARP %s\t" QDF_IPV4_ADDR_STR "\t"
+				    " " QDF_MAC_ADDR_FMT "\t"
+				    " " QDF_IPV4_ADDR_STR "\t"
+				    " " QDF_MAC_ADDR_FMT "\n",
+				    arps[qdf_ntohs(parp->ar_op)],
+				    QDF_IPV4_ADDR_ARRAY(parp->ar_sip),
+				    QDF_MAC_ADDR_REF(parp->ar_sha),
+				    QDF_IPV4_ADDR_ARRAY(parp->ar_tip),
+				    QDF_MAC_ADDR_REF(parp->ar_tha));
+		}
+	} else if (ether_type == htons(ETHERTYPE_IP)) {
+		struct iphdr *p_ip = (struct iphdr *)(p);
+		qdf_net_udphdr_t *p_udp;
+		s16 ip_hlen = 0;
+		u16 udplen = 0;
+
+		contig_len += sizeof(struct iphdr);
+		if (pktlen < contig_len)
+			return -EINVAL;
+
+		ip_hlen = p_ip->ihl * 4;
+		p_udp = (qdf_net_udphdr_t *)(((u8 *)p_ip) + ip_hlen);
+
+		/* If Proto is UDP */
+		if (p_ip->protocol == IPPROTO_UDP) {
+			contig_len += sizeof(struct udphdr);
+			if (pktlen < contig_len)
+				return -EINVAL;
+			udplen = p_ip->tot_len - (p_ip->ihl * 4);
+		}
+		/*
+		 * DHCP request UDP Client SP = 68 (bootpc), DP = 67 (bootps).
+		 */
+		if ((p_ip->protocol == IPPROTO_UDP) &&
+		    (p_udp->dst_port == htons(67))) {
+			struct dhcp_packet *p_dhcp;
+			struct dhcp_option *option;
+			u8 *value;
+			u8 dhcpDicover = 0;
+
+			p_dhcp = (struct dhcp_packet *)(((u8 *)p_udp) +
+					sizeof(struct udphdr));
+			option = (struct dhcp_option *)p_dhcp->options;
+
+			contig_len += sizeof(struct dhcp_packet);
+			if (pktlen < contig_len)
+				return -EINVAL;
+
+			qwrap_debug("src mac:" QDF_MAC_ADDR_FMT " "
+				    "dst mac:" QDF_MAC_ADDR_FMT " "
+				    "ether type: %d",
+				    QDF_MAC_ADDR_REF(src_mac),
+				    QDF_MAC_ADDR_REF(des_mac),
+				    ether_type);
+			qwrap_debug("DHCP: sport %d dport %d len %d"
+				    "chaddr:" QDF_MAC_ADDR_FMT " "
+				    "opcode: %d",
+				    p_udp->src_port, p_udp->dst_port,
+				    udplen,
+				    QDF_MAC_ADDR_REF(p_dhcp->chaddr),
+				    p_dhcp->op);
+
+			if (p_dhcp->magic_cookie[0] == 0x63 &&
+			    p_dhcp->magic_cookie[1] == 0x82 &&
+			    p_dhcp->magic_cookie[2] == 0x53 &&
+			    p_dhcp->magic_cookie[3] == 0x63) {
+				if (p_dhcp->op == 1) {
+					/* dhcp REQ or DISCOVER*/
+#ifdef BIG_ENDIAN_HOST
+					if ((p_dhcp->flags & 0x8000) == 0) {
+						p_dhcp->flags |= 0x8000;
+#else
+					if ((p_dhcp->flags & 0x0080) == 0) {
+						p_dhcp->flags |= 0x0080;
+#endif
+
+						compute_udp_checksum((qdf_net_iphdr_t *)p_ip, (unsigned short *)p_udp);
+					}
+				}
+			} /* Magic cookie for DHCP*/
+
+			while (option->type != 0xFF) {
+				/*Not an end option*/
+
+				contig_len += (option->len + 2);
+				if (pktlen < contig_len)
+					return -EINVAL;
+
+				value = option->value;
+				if (option->type == OPTION_DHCP_MSG_TYPE) {
+					if (value[0] == DHCP_DISOVER) {
+						dhcpDicover = 1;
+					}
+					option = (struct dhcp_option *)(value +
+						  option->len);
+
+				} else if (option->type ==
+					   OPTION_DHCP_REQUESTED_IP_ADDR &&
+					   dhcpDicover == 1) {
+					u32    *addr = (u32 *)value;
+
+					if (*addr != 0) {
+						memset(value, 0, option->len);
+						compute_udp_checksum((qdf_net_iphdr_t *)p_ip, (unsigned short *)p_udp);
+					}
+					qwrap_debug("DHCP Disover with"
+						    "IP Addr:"
+						    " " QDF_IPV4_ADDR_STR " "
+						    "from caddr: "
+						    " " QDF_MAC_ADDR_FMT " ",
+						    QDF_IPV4_ADDR_ARRAY(value),
+						    QDF_MAC_ADDR_REF(p_dhcp->chaddr));
+
+					break;
+				} else {
+					option = (struct dhcp_option *)(value +
+						  option->len);
+				}
+			}
+		}
+	} else if (ether_type == htons(ETHERTYPE_IPV6)) {
+		struct ipv6hdr *p_ip6 = (struct ipv6hdr *)(p);
+		eth_icmp6_lladdr_t  *phwaddr;
+		int change_packet = 1;
+
+		contig_len += sizeof(struct ipv6hdr);
+		if (pktlen < contig_len)
+			return -EINVAL;
+
+		if (p_ip6->nexthdr == IPPROTO_ICMPV6) {
+			struct icmp6hdr *p_icmp6;
+			u16 icmp6len = ntohs(p_ip6->payload_len);
+			p_icmp6 = (struct icmp6hdr *)(p_ip6 + 1);
+
+			contig_len += sizeof(struct icmp6hdr);
+			if (pktlen < contig_len)
+				return -EINVAL;
+			/*
+			 * It seems that we only have to modify IPv6 packets
+			 * sent by a Proxy STA. Both the solicitation and
+			 * adevertisement packets have the STA's OMA.
+			 * Flip that to the VMA.
+			 */
+			switch (p_icmp6->icmp6_type) {
+			case NDISC_NEIGHBOUR_SOLICITATION:
+			case NDISC_NEIGHBOUR_ADVERTISEMENT:
+			{
+				contig_len += 16 + sizeof(eth_icmp6_lladdr_t);
+				if (pktlen < contig_len)
+					return -EINVAL;
+
+				phwaddr = (eth_icmp6_lladdr_t *)
+						((u8 *)(p_icmp6 + 1) + 16);
+				IEEE80211_ADDR_COPY(phwaddr->addr,
+						    wvdev->wrap_dev_vma);
+				p_icmp6->icmp6_cksum = 0;
+				p_icmp6->icmp6_cksum = htons(checksum(
+							     (u16)IPPROTO_ICMPV6,
+							     icmp6len,
+							     p_ip6->saddr.s6_addr,
+							     p_ip6->daddr.s6_addr,
+							     16 /* IPv6 has 32 byte addresses */,
+							     (u8 *)p_icmp6));
+				break;
+			}
+			case NDISC_ROUTER_SOLICITATION:
+			{
+				contig_len += sizeof(eth_icmp6_lladdr_t);
+				if (pktlen < contig_len)
+					return -EINVAL;
+
+					/*replace the HW address with the VMA*/
+					phwaddr = (eth_icmp6_lladdr_t *)
+							((u8 *)(p_icmp6 + 1));
+					break;
+				}
+			default:
+				change_packet = 0;
+				break;
+			}
+
+			if (change_packet) {
+				IEEE80211_ADDR_COPY(phwaddr->addr,
+						    wvdev->wrap_dev_vma);
+				p_icmp6->icmp6_cksum = 0;
+				p_icmp6->icmp6_cksum = htons(checksum((u16)IPPROTO_ICMPV6,
+							     icmp6len,
+							     p_ip6->saddr.s6_addr,
+							     p_ip6->daddr.s6_addr,
+							     /* IPv6 has 32 byte addresses */
+							     16,
+							     (u8 *)p_icmp6));
+				qwrap_debug("IPV6 type %d\t sip:"
+					    QDF_IPV6_ADDR_STR " \t hwaddr:"
+					    QDF_MAC_ADDR_FMT "\t dip:"
+					    QDF_IPV6_ADDR_STR "\t\n",
+					    p_icmp6->icmp6_type,
+					    QDF_IPV6_ADDR_ARRAY(p_ip6->saddr.s6_addr),
+					    QDF_MAC_ADDR_REF(phwaddr->addr),
+					    QDF_IPV6_ADDR_ARRAY(p_ip6->daddr.s6_addr));
+			}
+		}
+	}
+	IEEE80211_ADDR_COPY(src_mac, wvdev->wrap_dev_vma);
+	return 0;
+}
+
+/**
+ * @brief WRAP MAT on receive path.
+ *
+ * @param wrap_vdev handle.
+ * @param buf
+ *
+ * @return 0 On success.
+ * @return -ve On failure.
+ */
+int dp_wrap_mat_rx(struct dp_wrap_vdev *wvdev, wbuf_t buf)
+{
+	struct ether_header *eh;
+	u16 ether_type;
+	int contig_len = sizeof(struct ether_header);
+	int pktlen = wbuf_get_pktlen(buf);
+	u8 *src_mac, *des_mac, *p, ismcast;
+	u8 *arp_smac = NULL;
+	u8 *arp_dmac = NULL;
+	struct eth_arphdr *parp = NULL;
+
+	eh = (struct ether_header *)(wbuf_header(buf));
+	p = (u8 *)(eh + 1);
+
+	if (!wvdev->is_wrap && !wvdev->is_psta)
+		return 0;
+
+	if (pktlen < contig_len)
+		return -EINVAL;
+
+	ether_type = eh->ether_type;
+	src_mac = eh->ether_shost;
+	des_mac = eh->ether_dhost;
+	ismcast = IEEE80211_IS_MULTICAST(des_mac);
+
+	if (ether_type == htons(ETH_P_PAE)) {
+		/* mark the pkt to allow local delivery on the device */
+		buf->mark |= WRAP_MARK_ROUTE;
+		return 0;
+	}
+
+	qwrap_trace("src mac:" QDF_MAC_ADDR_FMT " dst mac: "
+		    " " QDF_MAC_ADDR_FMT " "
+		    "ether type:%d", QDF_MAC_ADDR_REF(src_mac),
+		    QDF_MAC_ADDR_REF(des_mac), ether_type);
+
+	if (ether_type == htons(ETHERTYPE_ARP)) {
+		parp = (struct eth_arphdr *)p;
+		contig_len += sizeof(struct eth_arphdr);
+
+		if (pktlen < contig_len)
+			return -EINVAL;
+
+		if (parp->ar_hln == ETH_ALEN &&
+		    parp->ar_pro == htons(ETH_P_IP)) {
+			arp_smac = parp->ar_sha;
+			arp_dmac = parp->ar_tha;
+		} else {
+			parp = NULL;
+		}
+	}
+
+	if (ismcast && wvdev->is_mpsta) {
+		struct wlan_objmgr_pdev *pdev;
+		struct wlan_objmgr_vdev *vdev = NULL;
+		struct wlan_objmgr_vdev *vdev_next = NULL;
+		struct wlan_objmgr_pdev_objmgr *objmgr;
+		qdf_list_t *vdev_list;
+
+		pdev = wvdev->vdev->vdev_objmgr.wlan_pdev;
+		wlan_pdev_obj_lock(pdev);
+
+		objmgr = &pdev->pdev_objmgr;
+		vdev_list = &objmgr->wlan_vdev_list;
+		/* Get first vdev */
+		vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
+
+		while (vdev != NULL) {
+			if (qdf_is_macaddr_equal((struct qdf_mac_addr *)src_mac,
+			    (struct qdf_mac_addr *)vdev->vdev_mlme.macaddr)) {
+				buf->mark |= WRAP_MARK_REFLECT;
+				if (dp_wrap_vdev_is_mat_set(vdev))
+					IEEE80211_ADDR_COPY(src_mac,
+							    vdev->vdev_mlme.mataddr);
+				wlan_pdev_obj_unlock(pdev);
+				return 0;
+			}
+			/* get next vdev */
+			vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list,
+								    vdev);
+			vdev = vdev_next;
+		}
+
+		wlan_pdev_obj_unlock(pdev);
+	}
+
+	if (parp) {
+		qwrap_debug("ARP %s\t" QDF_IPV4_ADDR_STR "\t"
+			    " " QDF_MAC_ADDR_FMT " "
+			    "\t" QDF_IPV4_ADDR_STR "\t" QDF_MAC_ADDR_FMT "\n",
+			    arps[qdf_ntohs(parp->ar_op)],
+			    QDF_IPV4_ADDR_ARRAY(parp->ar_sip),
+			    QDF_MAC_ADDR_REF(parp->ar_sha),
+			    QDF_IPV4_ADDR_ARRAY(parp->ar_tip),
+			    QDF_MAC_ADDR_REF(parp->ar_tha));
+		if (!ismcast) {
+			if (parp->ar_op == htons(ARPOP_REQUEST) ||
+			    parp->ar_op == htons(ARPOP_REPLY)) {
+				if (wvdev->mat_enabled) {
+					IEEE80211_ADDR_COPY(arp_dmac,
+							    wvdev->wrap_dev_oma);
+				}
+			}
+		} else{
+			struct wlan_objmgr_pdev *pdev;
+			struct wlan_objmgr_vdev *vdev = NULL, *n_vdev = NULL;
+			struct wlan_objmgr_vdev *vdev_next = NULL;
+			struct wlan_objmgr_pdev_objmgr *objmgr;
+			qdf_list_t *vdev_list;
+
+			pdev = wvdev->vdev->vdev_objmgr.wlan_pdev;
+
+			if (!qdf_is_macaddr_equal((struct qdf_mac_addr *)arp_dmac,
+			    (struct qdf_mac_addr *)wvdev->wrap_dev_oma)) {
+				wlan_pdev_obj_lock(pdev);
+
+				objmgr = &pdev->pdev_objmgr;
+				vdev_list = &objmgr->wlan_vdev_list;
+				/* Get first vdev */
+				vdev = wlan_pdev_vdev_list_peek_head(vdev_list);
+
+				while (vdev != NULL) {
+					if (dp_wrap_vdev_is_mat_set(vdev) &&
+					    qdf_is_macaddr_equal((struct qdf_mac_addr *)arp_dmac,
+					    (struct qdf_mac_addr *)vdev->vdev_mlme.macaddr)) {
+						n_vdev = vdev;
+						break;
+					}
+					/* get next vdev */
+					vdev_next = wlan_vdev_get_next_vdev_of_pdev(vdev_list, vdev);
+					vdev = vdev_next;
+				}
+
+				wlan_pdev_obj_unlock(pdev);
+				if (n_vdev) {
+					wvdev = dp_wrap_get_vdev_handle(n_vdev);
+				} else {
+					return 0;
+				}
+			}
+
+			if (wvdev->mat_enabled == 0)
+				return 0;
+
+			IEEE80211_ADDR_COPY(arp_dmac, wvdev->wrap_dev_oma);
+			return 0;
+		}
+	}
+
+	else if (ether_type == htons(ETHERTYPE_IPV6)) {
+		/* Add support later if needed */
+	}
+
+	if (!(ismcast) && !(wvdev->is_mpsta) && (wvdev->mat_enabled))
+		IEEE80211_ADDR_COPY(des_mac, wvdev->wrap_dev_oma);
+
+	return 0;
+}
+#endif
+#endif