Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8479580b authored by Ping-Ke Shih's avatar Ping-Ke Shih Committed by Kalle Valo
Browse files

rtlwifi: Add TX report and disable key to force wait until report acked.



When using EAPOL to do a PTK rekey, there is a possible race condition.
When msg 3/4 is received, the supplicant will send msg 4/4 and install
the new key immediately; however, the driver must make sure that msg 4/4
is sent before installing the new key. We use TX report to ensure it is
sent.

Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: Yan-Hsuan Chuang <yhchuang@realtek.com>
Cc: Birming Chiu <birming@realtek.com>
Cc: Shaofu <shaofu@realtek.com>
Cc: Steven Ting <steventing@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 79b64ed7
Loading
Loading
Loading
Loading
+116 −12
Original line number Diff line number Diff line
@@ -1114,6 +1114,9 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
	if (txrate)
		tcb_desc->hw_rate = txrate->hw_value;

	if (rtl_is_tx_report_skb(hw, skb))
		tcb_desc->use_spe_rpt = 1;

	if (ieee80211_is_data(fc)) {
		/*
		 *we set data rate INX 0
@@ -1322,21 +1325,13 @@ static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc)
	ppsc->last_delaylps_stamp_jiffies = jiffies;
}

/*should call before software enc*/
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
		       bool is_enc)
static const u8 *rtl_skb_ether_type_ptr(struct ieee80211_hw *hw,
					struct sk_buff *skb, bool is_enc)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	__le16 fc = rtl_get_fc(skb);
	u16 ether_type;
	u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
	u8 encrypt_header_len = 0;
	u8 offset;
	const struct iphdr *ip;

	if (!ieee80211_is_data(fc))
		goto end;

	switch (rtlpriv->sec.pairwise_enc_algorithm) {
	case WEP40_ENCRYPTION:
@@ -1356,10 +1351,29 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
	offset = mac_hdr_len + SNAP_SIZE;
	if (is_enc)
		offset += encrypt_header_len;
	ether_type = be16_to_cpup((__be16 *)(skb->data + offset));

	return skb->data + offset;
}

/*should call before software enc*/
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
		       bool is_enc)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	__le16 fc = rtl_get_fc(skb);
	u16 ether_type;
	const u8 *ether_type_ptr;
	const struct iphdr *ip;

	if (!ieee80211_is_data(fc))
		goto end;

	ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, is_enc);
	ether_type = be16_to_cpup((__be16 *)ether_type_ptr);

	if (ETH_P_IP == ether_type) {
		ip = (struct iphdr *)((u8 *)skb->data + offset +
		ip = (struct iphdr *)((u8 *)ether_type_ptr +
		     PROTOC_TYPE_SIZE);
		if (IPPROTO_UDP == ip->protocol) {
			struct udphdr *udp = (struct udphdr *)((u8 *)ip +
@@ -1409,6 +1423,96 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
}
EXPORT_SYMBOL_GPL(rtl_is_special_data);

bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb)
{
	u16 ether_type;
	const u8 *ether_type_ptr;

	ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, true);
	ether_type = be16_to_cpup((__be16 *)ether_type_ptr);

	/* EAPOL */
	if (ether_type == ETH_P_PAE)
		return true;

	return false;
}

static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
	u16 sn;

	sn = atomic_inc_return(&tx_report->sn) & 0x0FFF;

	tx_report->last_sent_sn = sn;
	tx_report->last_sent_time = jiffies;

	RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG,
		 "Send TX-Report sn=0x%X\n", sn);

	return sn;
}

void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc,
		       struct ieee80211_hw *hw)
{
	if (ptcb_desc->use_spe_rpt) {
		u16 sn = rtl_get_tx_report_sn(hw);

		SET_TX_DESC_SPE_RPT(pdesc, 1);
		SET_TX_DESC_SW_DEFINE(pdesc, sn);
	}
}
EXPORT_SYMBOL_GPL(rtl_get_tx_report);

void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
	u16 sn;

	sn = ((tmp_buf[7] & 0x0F) << 8) | tmp_buf[6];

	tx_report->last_recv_sn = sn;

	RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG,
		 "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n",
		 tmp_buf[0], sn, tmp_buf[2]);
}
EXPORT_SYMBOL_GPL(rtl_tx_report_handler);

bool rtl_check_tx_report_acked(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_tx_report *tx_report = &rtlpriv->tx_report;

	if (tx_report->last_sent_sn == tx_report->last_recv_sn)
		return true;

	if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) {
		RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_WARNING,
			 "Check TX-Report timeout!!\n");
		return true;	/* 3 sec. (timeout) seen as acked */
	}

	return false;
}

void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	int i;

	for (i = 0; i < wait_ms; i++) {
		if (rtl_check_tx_report_acked(hw))
			break;
		usleep_range(1000, 2000);
		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
			 "Wait 1ms (%d/%d) to disable key.\n", i, wait_ms);
	}
}
/*********************************************************
 *
 * functions called by core.c
+13 −0
Original line number Diff line number Diff line
@@ -107,6 +107,11 @@ enum ap_peer {
	SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \
	(GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val))))

#define SET_TX_DESC_SPE_RPT(__pdesc, __val)			\
	SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val)
#define SET_TX_DESC_SW_DEFINE(__pdesc, __val)	\
	SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val)

int rtl_init_core(struct ieee80211_hw *hw);
void rtl_deinit_core(struct ieee80211_hw *hw);
void rtl_init_rx_config(struct ieee80211_hw *hw);
@@ -123,6 +128,14 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
		       bool is_enc);

bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb);
void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc,
		       struct ieee80211_hw *hw);
void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf,
			   u8 c2h_cmd_len);
bool rtl_check_tx_report_acked(struct ieee80211_hw *hw);
void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms);

void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
	struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+2 −0
Original line number Diff line number Diff line
@@ -1671,6 +1671,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		 *so don't use rtl_cam_reset_all_entry
		 *or clear all entry here.
		 */
		rtl_wait_tx_report_acked(hw, 500); /* wait 500ms for TX ack */

		rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
		break;
	default:
+1 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@
#define COMP_EASY_CONCURRENT	COMP_USB /* reuse of this bit is OK */
#define COMP_BT_COEXIST			BIT(30)
#define COMP_IQK			BIT(31)
#define COMP_TX_REPORT			BIT_ULL(32)

/*--------------------------------------------------------------
		Define the rt_print components
+1 −1
Original line number Diff line number Diff line
@@ -270,7 +270,7 @@ static struct rtl_hal_ops rtl8188ee_hal_ops = {

static struct rtl_mod_params rtl88ee_mod_params = {
	.sw_crypto = false,
	.inactiveps = false,
	.inactiveps = true,
	.swctrl_lps = false,
	.fwctrl_lps = false,
	.msi_support = true,
Loading