qca-wifi: Componentize QWRAP code

Remove dependency of qwrap on VAP layer and radio(ic) layer data
structures and move QWRAP DP code from OSIF to Component DEV.

Change-Id: I0fc975ef4cbac52e1e7fd8a87db3de8f97056ac0

CRs-Fixed: 2832334
This commit is contained in:
Rathees kumar Chinannan
2020-12-30 13:49:59 +05:30
parent 0179c38036
commit 8d8c8e710a
4 changed files with 1906 additions and 0 deletions

392
dp_wrap/inc/dp_wrap.h Normal file
View File

@@ -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

View File

@@ -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
dp_wrap/src/dp_wrap.c Normal file
View File

@@ -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
dp_wrap/src/dp_wrap_mat.c Normal file
View File

@@ -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