Skip to content
Permalink
Browse files

Added code to support WDS AP for 88W8964.

Signed-off-by: David Lin <dlin@marvell.com>
  • Loading branch information
yuhhaurlin committed Dec 12, 2017
1 parent b04d559 commit c96d1ede017df84fc52fc4d6d4e73e6f2d4d951a
Showing with 113 additions and 25 deletions.
  1. +32 −0 core.c
  2. +4 −0 core.h
  3. +2 −0 debugfs.c
  4. +27 −0 hif/fwcmd.c
  5. +2 −0 hif/fwcmd.h
  6. +1 −0 hif/hostcmd.h
  7. +0 −1 hif/pcie/rx.c
  8. +45 −24 hif/pcie/rx_ndp.c
32 core.c
@@ -593,6 +593,35 @@ static void mwl_account_handle(struct work_struct *work)
mwl_hif_process_account(priv->hw);
}

static void mwl_wds_check_handle(struct work_struct *work)
{
struct mwl_priv *priv =
container_of(work, struct mwl_priv, wds_check_handle);
struct mwl_sta *sta_info;
struct ieee80211_sta *sta;
bool wds_sta = false;

spin_lock_bh(&priv->sta_lock);
list_for_each_entry(sta_info, &priv->sta_list, list) {
if (sta_info->wds)
continue;
sta = container_of((void *)sta_info, struct ieee80211_sta,
drv_priv);
if (ether_addr_equal(sta->addr, priv->wds_check_sta)) {
wds_sta = true;
break;
}
}
spin_unlock_bh(&priv->sta_lock);

if (wds_sta) {
mwl_fwcmd_set_new_stn_wds_sc4(priv->hw, sta->addr);
sta_info->wds = true;
}

priv->wds_check = false;
}

static void mwl_chnl_switch_event(struct work_struct *work)
{
struct mwl_priv *priv =
@@ -682,6 +711,7 @@ static int mwl_wl_init(struct mwl_priv *priv)
priv->radio_short_preamble = false;
priv->wmm_enabled = false;
priv->powinited = 0;
priv->wds_check = false;
priv->csa_active = false;
priv->dfs_chirp_count_min = 5;
priv->dfs_chirp_time_interval = 1000;
@@ -692,6 +722,7 @@ static int mwl_wl_init(struct mwl_priv *priv)
/* Handle watchdog ba events */
INIT_WORK(&priv->watchdog_ba_handle, mwl_watchdog_ba_events);
INIT_WORK(&priv->account_handle, mwl_account_handle);
INIT_WORK(&priv->wds_check_handle, mwl_wds_check_handle);
INIT_WORK(&priv->chnl_switch_handle, mwl_chnl_switch_event);

mutex_init(&priv->fwcmd_mutex);
@@ -818,6 +849,7 @@ static void mwl_wl_deinit(struct mwl_priv *priv)
mwl_thermal_unregister(priv);
cancel_work_sync(&priv->chnl_switch_handle);
cancel_work_sync(&priv->account_handle);
cancel_work_sync(&priv->wds_check_handle);
cancel_work_sync(&priv->watchdog_ba_handle);
mwl_hif_deinit(hw);
}
4 core.h
@@ -251,6 +251,10 @@ struct mwl_priv {

struct work_struct account_handle;

bool wds_check;
struct work_struct wds_check_handle;
u8 wds_check_sta[ETH_ALEN];

bool csa_active;
struct work_struct chnl_switch_handle;
enum nl80211_dfs_regions dfs_region;
@@ -292,6 +292,8 @@ static ssize_t mwl_debugfs_sta_read(struct file *file, char __user *ubuf,
sta_info->is_ampdu_allowed ? "true" : "false");
len += scnprintf(p + len, size - len, "amsdu: %s\n",
sta_info->is_amsdu_allowed ? "true" : "false");
len += scnprintf(p + len, size - len, "wds: %s\n",
sta_info->wds ? "true" : "false");
if (sta_info->is_amsdu_allowed) {
len += scnprintf(p + len, size - len,
"amsdu cap: 0x%02x\n",
@@ -2051,6 +2051,33 @@ int mwl_fwcmd_set_new_stn_add_sc4(struct ieee80211_hw *hw,
return 0;
}

int mwl_fwcmd_set_new_stn_wds_sc4(struct ieee80211_hw *hw, u8 *addr)
{
struct mwl_priv *priv = hw->priv;
struct hostcmd_cmd_set_new_stn_sc4 *pcmd;

pcmd = (struct hostcmd_cmd_set_new_stn_sc4 *)&priv->pcmd_buf[0];

mutex_lock(&priv->fwcmd_mutex);

memset(pcmd, 0x00, sizeof(*pcmd));
pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_NEW_STN);
pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));

pcmd->action = cpu_to_le16(HOSTCMD_ACT_STA_ACTION_MODIFY);
ether_addr_copy(pcmd->mac_addr, addr);
pcmd->wds = cpu_to_le32(WDS_MODE);

if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_SET_NEW_STN)) {
mutex_unlock(&priv->fwcmd_mutex);
return -EIO;
}

mutex_unlock(&priv->fwcmd_mutex);

return 0;
}

int mwl_fwcmd_set_new_stn_add_self(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -153,6 +153,8 @@ int mwl_fwcmd_set_new_stn_add_sc4(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u32 wds);

int mwl_fwcmd_set_new_stn_wds_sc4(struct ieee80211_hw *hw, u8 *addr);

int mwl_fwcmd_set_new_stn_add_self(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);

@@ -115,6 +115,7 @@

/* Define station related constants */
#define HOSTCMD_ACT_STA_ACTION_ADD 0
#define HOSTCMD_ACT_STA_ACTION_MODIFY 1
#define HOSTCMD_ACT_STA_ACTION_REMOVE 2

/* Define key related constants */
@@ -377,7 +377,6 @@ void pcie_rx_recv(unsigned long data)
if ((mwl_vif && mwl_vif->is_hw_crypto_enabled) ||
is_multicast_ether_addr(wh->addr1) ||
(ieee80211_is_mgmt(wh->frame_control) &&
ieee80211_has_protected(wh->frame_control) &&
!is_multicast_ether_addr(wh->addr1))) {
/* When MMIC ERROR is encountered
* by the firmware, payload is
@@ -248,24 +248,23 @@ static inline void pcie_rx_process_fast_data(struct mwl_priv *priv,
memset(&hdr, 0, sizeof(hdr));
switch (mwl_vif->type) {
case NL80211_IFTYPE_AP:
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
ether_addr_copy(hdr.addr1, mwl_vif->bssid);
ether_addr_copy(hdr.addr2, skb->data + ETH_ALEN);
ether_addr_copy(hdr.addr3, skb->data);
hdrlen = 24;
break;
case NL80211_IFTYPE_AP_VLAN:
if (!sta_info->wds)
goto drop_packet;
fc |= (cpu_to_le16(IEEE80211_FCTL_TODS) |
cpu_to_le16(IEEE80211_FCTL_FROMDS));
/* RA TA DA SA */
ether_addr_copy(hdr.addr1, mwl_vif->bssid);
ether_addr_copy(hdr.addr2, sta->addr);
ether_addr_copy(hdr.addr3, skb->data);
ether_addr_copy(hdr.addr4, skb->data + ETH_ALEN);
hdrlen = 30;
if (sta_info->wds) {
fc |= (cpu_to_le16(IEEE80211_FCTL_TODS) |
cpu_to_le16(IEEE80211_FCTL_FROMDS));
/* RA TA DA SA */
ether_addr_copy(hdr.addr1, mwl_vif->bssid);
ether_addr_copy(hdr.addr2, sta->addr);
ether_addr_copy(hdr.addr3, skb->data);
ether_addr_copy(hdr.addr4, skb->data + ETH_ALEN);
hdrlen = 30;
} else {
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
ether_addr_copy(hdr.addr1, mwl_vif->bssid);
ether_addr_copy(hdr.addr2, skb->data + ETH_ALEN);
ether_addr_copy(hdr.addr3, skb->data);
hdrlen = 24;
}
break;
case NL80211_IFTYPE_STATION:
if (sta_info->wds) {
@@ -338,6 +337,7 @@ static inline void pcie_rx_process_slow_data(struct mwl_priv *priv,
{
struct ieee80211_rx_status *status;
struct ieee80211_hdr *wh;
struct mwl_vif *mwl_vif = NULL;

pcie_rx_remove_dma_header(skb, 0);
status = IEEE80211_SKB_RXCB(skb);
@@ -351,12 +351,33 @@ static inline void pcie_rx_process_slow_data(struct mwl_priv *priv,
else {
wh = (struct ieee80211_hdr *)skb->data;

if (ieee80211_is_mgmt(wh->frame_control) &&
ieee80211_has_protected(wh->frame_control) &&
!is_multicast_ether_addr(wh->addr1)) {
status->flag |= RX_FLAG_IV_STRIPPED |
RX_FLAG_DECRYPTED |
RX_FLAG_MMIC_STRIPPED;
if (ieee80211_has_protected(wh->frame_control)) {
if (ieee80211_has_tods(wh->frame_control)) {
mwl_vif = utils_find_vif_bss(priv, wh->addr1);
if (!mwl_vif &&
ieee80211_has_a4(wh->frame_control))
mwl_vif =
utils_find_vif_bss(priv,
wh->addr2);
} else {
mwl_vif = utils_find_vif_bss(priv, wh->addr2);
}

if ((mwl_vif && mwl_vif->is_hw_crypto_enabled) ||
is_multicast_ether_addr(wh->addr1) ||
(ieee80211_is_mgmt(wh->frame_control) &&
!is_multicast_ether_addr(wh->addr1))) {
if (!ieee80211_is_auth(wh->frame_control))
status->flag |= RX_FLAG_IV_STRIPPED |
RX_FLAG_DECRYPTED |
RX_FLAG_MMIC_STRIPPED;
}
}

if (ieee80211_has_a4(wh->frame_control) && !priv->wds_check) {
ether_addr_copy(priv->wds_check_sta, wh->addr2);
ieee80211_queue_work(priv->hw, &priv->wds_check_handle);
priv->wds_check = true;
}
}

0 comments on commit c96d1ed

Please sign in to comment.
You can’t perform that action at this time.