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:
392
dp_wrap/inc/dp_wrap.h
Normal file
392
dp_wrap/inc/dp_wrap.h
Normal 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
|
87
dp_wrap/inc/dp_wrap_struct.h
Normal file
87
dp_wrap/inc/dp_wrap_struct.h
Normal 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
837
dp_wrap/src/dp_wrap.c
Normal 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
590
dp_wrap/src/dp_wrap_mat.c
Normal 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
|
Reference in New Issue
Block a user