mirror of https://gitee.com/openkylin/linux.git
mwifiex: parse TDLS action frames during RX
This patch adds support for parsing TDLS action frames during station receive handler. Peer station capabilities are stored into station node. Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
b23bce2965
commit
5f2caaf32b
|
@ -93,6 +93,14 @@ enum mwifiex_bss_role {
|
||||||
MWIFIEX_BSS_ROLE_ANY = 0xff,
|
MWIFIEX_BSS_ROLE_ANY = 0xff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mwifiex_tdls_status {
|
||||||
|
TDLS_NOT_SETUP = 0,
|
||||||
|
TDLS_SETUP_INPROGRESS,
|
||||||
|
TDLS_SETUP_COMPLETE,
|
||||||
|
TDLS_SETUP_FAILURE,
|
||||||
|
TDLS_LINK_TEARDOWN,
|
||||||
|
};
|
||||||
|
|
||||||
#define BSS_ROLE_BIT_MASK BIT(0)
|
#define BSS_ROLE_BIT_MASK BIT(0)
|
||||||
|
|
||||||
#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
|
#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
|
||||||
|
|
|
@ -594,8 +594,20 @@ struct mwifiex_bss_priv {
|
||||||
u64 fw_tsf;
|
u64 fw_tsf;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is AP specific structure which stores information
|
struct mwifiex_tdls_capab {
|
||||||
* about associated STA
|
__le16 capab;
|
||||||
|
u8 rates[32];
|
||||||
|
u8 rates_len;
|
||||||
|
u8 qos_info;
|
||||||
|
u8 coex_2040;
|
||||||
|
struct ieee80211_ht_cap ht_capb;
|
||||||
|
struct ieee80211_ht_operation ht_oper;
|
||||||
|
struct ieee_types_extcap extcap;
|
||||||
|
struct ieee_types_generic rsn_ie;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is AP/TDLS specific structure which stores information
|
||||||
|
* about associated/peer STA
|
||||||
*/
|
*/
|
||||||
struct mwifiex_sta_node {
|
struct mwifiex_sta_node {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
@ -605,6 +617,7 @@ struct mwifiex_sta_node {
|
||||||
u8 ampdu_sta[MAX_NUM_TID];
|
u8 ampdu_sta[MAX_NUM_TID];
|
||||||
u16 rx_seq[MAX_NUM_TID];
|
u16 rx_seq[MAX_NUM_TID];
|
||||||
u16 max_amsdu;
|
u16 max_amsdu;
|
||||||
|
struct mwifiex_tdls_capab tdls_cap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mwifiex_if_ops {
|
struct mwifiex_if_ops {
|
||||||
|
@ -1194,6 +1207,8 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
|
||||||
u8 *peer, u8 action_code, u8 dialog_token,
|
u8 *peer, u8 action_code, u8 dialog_token,
|
||||||
u16 status_code, const u8 *extra_ies,
|
u16 status_code, const u8 *extra_ies,
|
||||||
size_t extra_ies_len);
|
size_t extra_ies_len);
|
||||||
|
void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
|
||||||
|
u8 *buf, int len);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
void mwifiex_debugfs_init(void);
|
void mwifiex_debugfs_init(void);
|
||||||
|
|
|
@ -88,11 +88,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
|
||||||
struct rxpd *local_rx_pd;
|
struct rxpd *local_rx_pd;
|
||||||
int hdr_chop;
|
int hdr_chop;
|
||||||
struct ethhdr *eth;
|
struct ethhdr *eth;
|
||||||
|
u16 rx_pkt_off, rx_pkt_len;
|
||||||
|
u8 *offset;
|
||||||
|
|
||||||
local_rx_pd = (struct rxpd *) (skb->data);
|
local_rx_pd = (struct rxpd *) (skb->data);
|
||||||
|
|
||||||
rx_pkt_hdr = (void *)local_rx_pd +
|
rx_pkt_off = le16_to_cpu(local_rx_pd->rx_pkt_offset);
|
||||||
le16_to_cpu(local_rx_pd->rx_pkt_offset);
|
rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length);
|
||||||
|
rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off;
|
||||||
|
|
||||||
if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
|
if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
|
||||||
sizeof(bridge_tunnel_header))) ||
|
sizeof(bridge_tunnel_header))) ||
|
||||||
|
@ -142,6 +145,12 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
|
||||||
|
ntohs(rx_pkt_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
|
||||||
|
offset = (u8 *)local_rx_pd + rx_pkt_off;
|
||||||
|
mwifiex_process_tdls_action_frame(priv, offset, rx_pkt_len);
|
||||||
|
}
|
||||||
|
|
||||||
priv->rxpd_rate = local_rx_pd->rx_rate;
|
priv->rxpd_rate = local_rx_pd->rx_rate;
|
||||||
|
|
||||||
priv->rxpd_htinfo = local_rx_pd->ht_info;
|
priv->rxpd_htinfo = local_rx_pd->ht_info;
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "wmm.h"
|
||||||
|
|
||||||
|
#define TDLS_REQ_FIX_LEN 6
|
||||||
|
#define TDLS_RESP_FIX_LEN 8
|
||||||
|
#define TDLS_CONFIRM_FIX_LEN 6
|
||||||
|
|
||||||
/* This function appends rate TLV to scan config command. */
|
/* This function appends rate TLV to scan config command. */
|
||||||
static int
|
static int
|
||||||
|
@ -421,3 +426,117 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function process tdls action frame from peer.
|
||||||
|
* Peer capabilities are stored into station node structure.
|
||||||
|
*/
|
||||||
|
void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
|
||||||
|
u8 *buf, int len)
|
||||||
|
{
|
||||||
|
struct mwifiex_sta_node *sta_ptr;
|
||||||
|
u8 *peer, *pos, *end;
|
||||||
|
u8 i, action, basic;
|
||||||
|
int ie_len = 0;
|
||||||
|
|
||||||
|
if (len < (sizeof(struct ethhdr) + 3))
|
||||||
|
return;
|
||||||
|
if (*(u8 *)(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
|
||||||
|
return;
|
||||||
|
if (*(u8 *)(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
peer = buf + ETH_ALEN;
|
||||||
|
action = *(u8 *)(buf + sizeof(struct ethhdr) + 2);
|
||||||
|
|
||||||
|
/* just handle TDLS setup request/response/confirm */
|
||||||
|
if (action > WLAN_TDLS_SETUP_CONFIRM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_dbg(priv->adapter->dev,
|
||||||
|
"rx:tdls action: peer=%pM, action=%d\n", peer, action);
|
||||||
|
|
||||||
|
sta_ptr = mwifiex_add_sta_entry(priv, peer);
|
||||||
|
if (!sta_ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case WLAN_TDLS_SETUP_REQUEST:
|
||||||
|
if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = buf + sizeof(struct ethhdr) + 4;
|
||||||
|
/* payload 1+ category 1 + action 1 + dialog 1 */
|
||||||
|
sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
|
||||||
|
ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
|
||||||
|
pos += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_SETUP_RESPONSE:
|
||||||
|
if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))
|
||||||
|
return;
|
||||||
|
/* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
|
||||||
|
pos = buf + sizeof(struct ethhdr) + 6;
|
||||||
|
sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
|
||||||
|
ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
|
||||||
|
pos += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_TDLS_SETUP_CONFIRM:
|
||||||
|
if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))
|
||||||
|
return;
|
||||||
|
pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;
|
||||||
|
ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_warn(priv->adapter->dev, "Unknown TDLS frame type.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
|
||||||
|
if (pos + 2 + pos[1] > end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (*pos) {
|
||||||
|
case WLAN_EID_SUPP_RATES:
|
||||||
|
sta_ptr->tdls_cap.rates_len = pos[1];
|
||||||
|
for (i = 0; i < pos[1]; i++)
|
||||||
|
sta_ptr->tdls_cap.rates[i] = pos[i + 2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLAN_EID_EXT_SUPP_RATES:
|
||||||
|
basic = sta_ptr->tdls_cap.rates_len;
|
||||||
|
for (i = 0; i < pos[1]; i++)
|
||||||
|
sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
|
||||||
|
sta_ptr->tdls_cap.rates_len += pos[1];
|
||||||
|
break;
|
||||||
|
case WLAN_EID_HT_CAPABILITY:
|
||||||
|
memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
|
||||||
|
sizeof(struct ieee80211_ht_cap));
|
||||||
|
sta_ptr->is_11n_enabled = 1;
|
||||||
|
break;
|
||||||
|
case WLAN_EID_HT_OPERATION:
|
||||||
|
memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
|
||||||
|
sizeof(struct ieee80211_ht_operation));
|
||||||
|
break;
|
||||||
|
case WLAN_EID_BSS_COEX_2040:
|
||||||
|
sta_ptr->tdls_cap.coex_2040 = pos[2];
|
||||||
|
break;
|
||||||
|
case WLAN_EID_EXT_CAPABILITY:
|
||||||
|
memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
|
||||||
|
sizeof(struct ieee_types_header) +
|
||||||
|
min_t(u8, pos[1], 8));
|
||||||
|
break;
|
||||||
|
case WLAN_EID_RSN:
|
||||||
|
memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
|
||||||
|
sizeof(struct ieee_types_header) + pos[1]);
|
||||||
|
break;
|
||||||
|
case WLAN_EID_QOS_CAPA:
|
||||||
|
sta_ptr->tdls_cap.qos_info = pos[2];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -374,8 +374,7 @@ mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
|
||||||
* AP is disabled (due to call admission control (ACM bit). Mapping
|
* AP is disabled (due to call admission control (ACM bit). Mapping
|
||||||
* of TID to AC is taken care of internally.
|
* of TID to AC is taken care of internally.
|
||||||
*/
|
*/
|
||||||
static u8
|
u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
|
||||||
mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
|
|
||||||
{
|
{
|
||||||
enum mwifiex_wmm_ac_e ac, ac_down;
|
enum mwifiex_wmm_ac_e ac, ac_down;
|
||||||
u8 new_tid;
|
u8 new_tid;
|
||||||
|
@ -578,7 +577,7 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
|
||||||
* If no such node is found, a new node is added first and then
|
* If no such node is found, a new node is added first and then
|
||||||
* retrieved.
|
* retrieved.
|
||||||
*/
|
*/
|
||||||
static struct mwifiex_ra_list_tbl *
|
struct mwifiex_ra_list_tbl *
|
||||||
mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
|
mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
|
||||||
{
|
{
|
||||||
struct mwifiex_ra_list_tbl *ra_list;
|
struct mwifiex_ra_list_tbl *ra_list;
|
||||||
|
|
|
@ -122,5 +122,8 @@ void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
|
||||||
void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
|
void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
|
||||||
int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
|
int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
|
||||||
const struct host_cmd_ds_command *resp);
|
const struct host_cmd_ds_command *resp);
|
||||||
|
struct mwifiex_ra_list_tbl *
|
||||||
|
mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr);
|
||||||
|
u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid);
|
||||||
|
|
||||||
#endif /* !_MWIFIEX_WMM_H_ */
|
#endif /* !_MWIFIEX_WMM_H_ */
|
||||||
|
|
Loading…
Reference in New Issue