Browse Source

qcacmn: Fix failing to distinguish between EAPOL M2 and M4

Currently we distinguish EAPOL frames by taking the secure bit in key
information field into account. This is sometimes error because for WPA
handshake M3/M4 secure bit is 0 (GTK is not included in M3) whereas for
WPA2 handshake M3/M4 secure bit is 1 for WPA2 handshake. This change uses
the ack bit in key information field to differentiate M1/M3 from M2/M4,
then uses the key data length as well as Key Mic and Encrypted Key Data
in key information field together to identify EAPOL M2 and M4 frames.

Change-Id: Iac88bc5b942415edee08dc4a98dbd4e811cb8604
CRs-Fixed: 3327876
jinbaoliu 2 năm trước cách đây
mục cha
commit
161650dffa
2 tập tin đã thay đổi với 39 bổ sung27 xóa
  1. 1 0
      qdf/inc/qdf_nbuf.h
  2. 38 27
      qdf/linux/src/qdf_nbuf.c

+ 1 - 0
qdf/inc/qdf_nbuf.h

@@ -104,6 +104,7 @@
 #define EAPOL_KEY_INFO_OFFSET			19
 #define EAPOL_PKT_LEN_OFFSET			16
 #define EAPOL_KEY_LEN_OFFSET			21
+#define EAPOL_KEY_DATA_LENGTH_OFFSET		111
 
 #define EAPOL_PACKET_TYPE_EAP                   0
 #define EAPOL_PACKET_TYPE_START                 1

+ 38 - 27
qdf/linux/src/qdf_nbuf.c

@@ -44,6 +44,7 @@
 #include <qdf_types.h>
 #include <net/ieee80211_radiotap.h>
 #include <pld_common.h>
+#include <qdf_crypto.h>
 
 #if defined(FEATURE_TSO)
 #include <net/ipv6.h>
@@ -1486,46 +1487,56 @@ __qdf_nbuf_data_get_dhcp_subtype(uint8_t *data)
 	return subtype;
 }
 
-#define EAPOL_MASK				0x8002
-#define EAPOL_M1_BIT_MASK			0x8000
-#define EAPOL_M2_BIT_MASK			0x0000
-#define EAPOL_M3_BIT_MASK			0x8002
-#define EAPOL_M4_BIT_MASK			0x0002
+#define EAPOL_WPA_KEY_INFO_ACK BIT(7)
+#define EAPOL_WPA_KEY_INFO_MIC BIT(8)
+#define EAPOL_WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
+
 /**
- * __qdf_nbuf_data_get_eapol_subtype() - get the subtype
- *            of EAPOL packet.
+ * __qdf_nbuf_data_get_eapol_subtype() - get the subtype of EAPOL packet.
  * @data: Pointer to EAPOL packet data buffer
  *
  * This func. returns the subtype of EAPOL packet.
  *
+ * We can distinguish M1/M3 from M2/M4 by the ack bit in the keyinfo field
+ * The ralationship between the ack bit and EAPOL type is as follows:
+ *
+ *  EAPOL type  |   M1    M2   M3  M4
+ * --------------------------------------
+ *     Ack      |   1     0    1   0
+ * --------------------------------------
+ *
+ * Then, we can differentiate M1 from M3, M2 from M4 by below methods:
+ * M2/M4: by keyDataLength being AES_BLOCK_SIZE for FILS and 0 otherwise.
+ * M1/M3: by the mic/encrKeyData bit in the keyinfo field.
+ *
  * Return: subtype of the EAPOL packet.
  */
 enum qdf_proto_subtype
 __qdf_nbuf_data_get_eapol_subtype(uint8_t *data)
 {
-	uint16_t eapol_key_info;
-	enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
-	uint16_t mask;
+	uint16_t key_info, key_data_length;
+	enum qdf_proto_subtype subtype;
 
-	eapol_key_info = (uint16_t)(*(uint16_t *)
-			(data + EAPOL_KEY_INFO_OFFSET));
+	key_info = qdf_ntohs((uint16_t)(*(uint16_t *)
+			(data + EAPOL_KEY_INFO_OFFSET)));
 
-	mask = eapol_key_info & EAPOL_MASK;
+	key_data_length = qdf_ntohs((uint16_t)(*(uint16_t *)
+				(data + EAPOL_KEY_DATA_LENGTH_OFFSET)));
 
-	switch (mask) {
-	case EAPOL_M1_BIT_MASK:
-		subtype = QDF_PROTO_EAPOL_M1;
-		break;
-	case EAPOL_M2_BIT_MASK:
-		subtype = QDF_PROTO_EAPOL_M2;
-		break;
-	case EAPOL_M3_BIT_MASK:
-		subtype = QDF_PROTO_EAPOL_M3;
-		break;
-	case EAPOL_M4_BIT_MASK:
-		subtype = QDF_PROTO_EAPOL_M4;
-		break;
-	}
+	if (key_info & EAPOL_WPA_KEY_INFO_ACK)
+		if (key_info &
+		    (EAPOL_WPA_KEY_INFO_MIC | EAPOL_WPA_KEY_INFO_ENCR_KEY_DATA))
+			subtype = QDF_PROTO_EAPOL_M3;
+		else
+			subtype = QDF_PROTO_EAPOL_M1;
+	else
+		if (key_data_length == 0 ||
+		    (!(key_info & EAPOL_WPA_KEY_INFO_MIC) &&
+		     (key_info & EAPOL_WPA_KEY_INFO_ENCR_KEY_DATA) &&
+		     key_data_length == AES_BLOCK_SIZE))
+			subtype = QDF_PROTO_EAPOL_M4;
+		else
+			subtype = QDF_PROTO_EAPOL_M2;
 
 	return subtype;
 }