Browse Source

qcacld-3.0: Dump header info for first data packet after WOW wakeup

Propagation from qcacld-2.0 to qcacld-3.0.

Dump some information such as source MAC address, destination
MAC address, sequence number, packet type, subtype and other
important information for the first data packet after WOW wakeup.

Change-Id: I3c83991f56be34412f3f10adf58bd991ecb536ca
CRs-Fixed: 1019037
Himanshu Agarwal 8 years ago
parent
commit
82de9040dd
2 changed files with 314 additions and 8 deletions
  1. 14 0
      core/wma/inc/wma.h
  2. 300 8
      core/wma/src/wma_features.c

+ 14 - 0
core/wma/inc/wma.h

@@ -166,6 +166,20 @@
 #define WMA_MCAST_IPV4_MAC_ADDR (0x01)
 #define WMA_MCAST_IPV6_MAC_ADDR (0x33)
 
+#define WMA_IS_EAPOL_GET_MIN_LEN          14
+#define WMA_EAPOL_SUBTYPE_GET_MIN_LEN     21
+#define WMA_EAPOL_INFO_GET_MIN_LEN        23
+#define WMA_IS_DHCP_GET_MIN_LEN           38
+#define WMA_DHCP_SUBTYPE_GET_MIN_LEN      0x11D
+#define WMA_DHCP_INFO_GET_MIN_LEN         50
+#define WMA_IS_ARP_GET_MIN_LEN            14
+#define WMA_ARP_SUBTYPE_GET_MIN_LEN       22
+#define WMA_IPV4_PROTO_GET_MIN_LEN        24
+#define WMA_IPV4_PKT_INFO_GET_MIN_LEN     42
+#define WMA_ICMP_SUBTYPE_GET_MIN_LEN      35
+#define WMA_IPV6_PROTO_GET_MIN_LEN        21
+#define WMA_IPV6_PKT_INFO_GET_MIN_LEN     62
+#define WMA_ICMPV6_SUBTYPE_GET_MIN_LEN    55
 
 /* Roaming default values
  * All time and period values are in milliseconds.

+ 300 - 8
core/wma/src/wma_features.c

@@ -2616,6 +2616,287 @@ static bool tlv_check_required(int32_t reason)
 	}
 }
 
+/**
+ * wma_pkt_proto_subtype_to_string() - to convert proto subtype
+ *         of data packet to string.
+ * @proto_subtype: proto subtype for data packet
+ *
+ * This function returns the string for the proto subtype of
+ * data packet.
+ *
+ * Return: string for proto subtype for data packet
+ */
+const char *
+wma_pkt_proto_subtype_to_string(enum qdf_proto_subtype proto_subtype)
+{
+	switch (proto_subtype) {
+	case QDF_PROTO_EAPOL_M1:
+		return "EAPOL M1";
+	case QDF_PROTO_EAPOL_M2:
+		return "EAPOL M2";
+	case QDF_PROTO_EAPOL_M3:
+		return "EAPOL M3";
+	case QDF_PROTO_EAPOL_M4:
+		return "EAPOL M4";
+	case QDF_PROTO_DHCP_DISCOVER:
+		return "DHCP DISCOVER";
+	case QDF_PROTO_DHCP_REQUEST:
+		return "DHCP REQUEST";
+	case QDF_PROTO_DHCP_OFFER:
+		return "DHCP OFFER";
+	case QDF_PROTO_DHCP_ACK:
+		return "DHCP ACK";
+	case QDF_PROTO_DHCP_NACK:
+		return "DHCP NACK";
+	case QDF_PROTO_DHCP_RELEASE:
+		return "DHCP RELEASE";
+	case QDF_PROTO_DHCP_INFORM:
+		return "DHCP INFORM";
+	case QDF_PROTO_DHCP_DECLINE:
+		return "DHCP DECLINE";
+	case QDF_PROTO_ARP_REQ:
+		return "ARP REQUEST";
+	case QDF_PROTO_ARP_RES:
+		return "ARP RESPONSE";
+	case QDF_PROTO_ICMP_REQ:
+		return "ICMP REQUEST";
+	case QDF_PROTO_ICMP_RES:
+		return "ICMP RESPONSE";
+	case QDF_PROTO_ICMPV6_REQ:
+		return "ICMPV6 REQUEST";
+	case QDF_PROTO_ICMPV6_RES:
+		return "ICMPV6 RESPONSE";
+	case QDF_PROTO_IPV4_UDP:
+		return "IPV4 UDP Packet";
+	case QDF_PROTO_IPV4_TCP:
+		return "IPV4 TCP Packet";
+	case QDF_PROTO_IPV6_UDP:
+		return "IPV6 UDP Packet";
+	case QDF_PROTO_IPV6_TCP:
+		return "IPV6 TCP Packet";
+	default:
+		return "Invalid Packet";
+	}
+}
+
+/**
+ * wma_wow_get_pkt_proto_subtype() - get the proto subtype
+ *            of the packet.
+ * @data: Pointer to data buffer
+ * @len: length of the data buffer
+ *
+ * This function gives the proto subtype of the packet.
+ *
+ * Return: proto subtype of the packet.
+ */
+static enum qdf_proto_subtype
+wma_wow_get_pkt_proto_subtype(uint8_t *data,
+			uint32_t len)
+{
+	if (len >= WMA_IS_DHCP_GET_MIN_LEN) {
+		if (qdf_nbuf_data_is_ipv4_dhcp_pkt(data)) {
+			if (len >= WMA_DHCP_SUBTYPE_GET_MIN_LEN)
+				return qdf_nbuf_data_get_dhcp_subtype(data);
+			QDF_TRACE(QDF_MODULE_ID_WMA,
+				QDF_TRACE_LEVEL_ERROR, "DHCP Packet");
+			return QDF_PROTO_INVALID;
+		}
+	}
+	if (len >= WMA_IS_EAPOL_GET_MIN_LEN) {
+		if (qdf_nbuf_data_is_ipv4_eapol_pkt(data)) {
+			if (len >= WMA_EAPOL_SUBTYPE_GET_MIN_LEN)
+				return qdf_nbuf_data_get_eapol_subtype(data);
+			QDF_TRACE(QDF_MODULE_ID_WMA,
+				QDF_TRACE_LEVEL_ERROR, "EAPOL Packet");
+			return QDF_PROTO_INVALID;
+		}
+	}
+	if (len >= WMA_IS_ARP_GET_MIN_LEN) {
+		if (qdf_nbuf_data_is_ipv4_arp_pkt(data)) {
+			if (len >= WMA_ARP_SUBTYPE_GET_MIN_LEN)
+				return qdf_nbuf_data_get_arp_subtype(data);
+			QDF_TRACE(QDF_MODULE_ID_WMA,
+				QDF_TRACE_LEVEL_ERROR, "ARP Packet");
+			return QDF_PROTO_INVALID;
+		}
+	}
+	if (len >= WMA_IPV4_PROTO_GET_MIN_LEN) {
+		if (qdf_nbuf_data_is_icmp_pkt(data)) {
+			if (len >= WMA_ICMP_SUBTYPE_GET_MIN_LEN)
+				return qdf_nbuf_data_get_icmp_subtype(data);
+			QDF_TRACE(QDF_MODULE_ID_WMA,
+				QDF_TRACE_LEVEL_ERROR, "ICMP Packet");
+			return QDF_PROTO_INVALID;
+		} else if (qdf_nbuf_data_is_ipv4_udp_pkt(data)) {
+			return QDF_PROTO_IPV4_UDP;
+		} else if (qdf_nbuf_data_is_ipv4_tcp_pkt(data)) {
+			return QDF_PROTO_IPV4_TCP;
+		}
+	}
+	if (len >= WMA_IPV6_PROTO_GET_MIN_LEN) {
+		if (qdf_nbuf_data_is_icmpv6_pkt(data)) {
+			if (len >= WMA_ICMPV6_SUBTYPE_GET_MIN_LEN)
+				return qdf_nbuf_data_get_icmpv6_subtype(data);
+			QDF_TRACE(QDF_MODULE_ID_WMA,
+				QDF_TRACE_LEVEL_ERROR, "ICMPV6 Packet");
+			return QDF_PROTO_INVALID;
+		} else if (qdf_nbuf_data_is_ipv6_udp_pkt(data)) {
+			return QDF_PROTO_IPV6_UDP;
+		} else if (qdf_nbuf_data_is_ipv6_tcp_pkt(data)) {
+			return QDF_PROTO_IPV6_TCP;
+		}
+	}
+
+	return QDF_PROTO_INVALID;
+}
+
+/**
+ * wma_wow_parse_data_pkt_buffer() - API to parse data buffer for data
+ *    packet that resulted in WOW wakeup.
+ * @data: Pointer to data buffer
+ * @buf_len: data buffer length
+ *
+ * This function parses the data buffer received (first few bytes of
+ * skb->data) to get informaton like src mac addr, dst mac addr, packet
+ * len, seq_num, etc.
+ *
+ * Return: void
+ */
+static void wma_wow_parse_data_pkt_buffer(uint8_t *data,
+			uint32_t buf_len)
+{
+	enum qdf_proto_subtype proto_subtype;
+	uint16_t pkt_len, key_len, seq_num;
+	uint32_t transaction_id, tcp_seq_num;
+
+	WMA_LOGD("wow_buf_pkt_len: %d", buf_len);
+	if (buf_len >= QDF_NBUF_TRAC_ETH_TYPE_OFFSET)
+		WMA_LOGE("Src_mac: " MAC_ADDRESS_STR " Dst_mac: " MAC_ADDRESS_STR,
+			MAC_ADDR_ARRAY(data),
+			MAC_ADDR_ARRAY(data + QDF_NBUF_SRC_MAC_OFFSET));
+	else
+		goto end;
+
+	proto_subtype = wma_wow_get_pkt_proto_subtype(data, buf_len);
+	switch (proto_subtype) {
+	case QDF_PROTO_EAPOL_M1:
+	case QDF_PROTO_EAPOL_M2:
+	case QDF_PROTO_EAPOL_M3:
+	case QDF_PROTO_EAPOL_M4:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		if (buf_len >= WMA_EAPOL_INFO_GET_MIN_LEN) {
+			pkt_len = (uint16_t)(*(uint16_t *)(data +
+				EAPOL_PKT_LEN_OFFSET));
+			key_len = (uint16_t)(*(uint16_t *)(data +
+				EAPOL_KEY_LEN_OFFSET));
+			WMA_LOGE("Pkt_len: %d, Key_len: %d",
+				ani_cpu_to_be16(pkt_len),
+				ani_cpu_to_be16(key_len));
+		}
+		break;
+
+	case QDF_PROTO_DHCP_DISCOVER:
+	case QDF_PROTO_DHCP_REQUEST:
+	case QDF_PROTO_DHCP_OFFER:
+	case QDF_PROTO_DHCP_ACK:
+	case QDF_PROTO_DHCP_NACK:
+	case QDF_PROTO_DHCP_RELEASE:
+	case QDF_PROTO_DHCP_INFORM:
+	case QDF_PROTO_DHCP_DECLINE:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		if (buf_len >= WMA_DHCP_INFO_GET_MIN_LEN) {
+			pkt_len = (uint16_t)(*(uint16_t *)(data +
+				DHCP_PKT_LEN_OFFSET));
+			transaction_id = (uint32_t)(*(uint32_t *)(data +
+				DHCP_TRANSACTION_ID_OFFSET));
+			WMA_LOGE("Pkt_len: %d, Transaction_id: %d",
+				ani_cpu_to_be16(pkt_len),
+				ani_cpu_to_be16(transaction_id));
+		}
+		break;
+
+	case QDF_PROTO_ARP_REQ:
+	case QDF_PROTO_ARP_RES:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		break;
+
+	case QDF_PROTO_ICMP_REQ:
+	case QDF_PROTO_ICMP_RES:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) {
+			pkt_len = (uint16_t)(*(uint16_t *)(data +
+				IPV4_PKT_LEN_OFFSET));
+			seq_num = (uint16_t)(*(uint16_t *)(data +
+				ICMP_SEQ_NUM_OFFSET));
+			WMA_LOGE("Pkt_len: %d, Seq_num: %d",
+				ani_cpu_to_be16(pkt_len),
+				ani_cpu_to_be16(seq_num));
+		}
+		break;
+
+	case QDF_PROTO_ICMPV6_REQ:
+	case QDF_PROTO_ICMPV6_RES:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) {
+			pkt_len = (uint16_t)(*(uint16_t *)(data +
+				IPV6_PKT_LEN_OFFSET));
+			seq_num = (uint16_t)(*(uint16_t *)(data +
+				ICMPV6_SEQ_NUM_OFFSET));
+			WMA_LOGE("Pkt_len: %d, Seq_num: %d",
+				ani_cpu_to_be16(pkt_len),
+				ani_cpu_to_be16(seq_num));
+		}
+		break;
+
+	case QDF_PROTO_IPV4_UDP:
+	case QDF_PROTO_IPV4_TCP:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) {
+			pkt_len = (uint16_t)(*(uint16_t *)(data +
+				IPV4_PKT_LEN_OFFSET));
+			WMA_LOGE("Pkt_len: %d",
+				ani_cpu_to_be16(pkt_len));
+			if (proto_subtype == QDF_PROTO_IPV4_TCP) {
+				tcp_seq_num = (uint32_t)(*(uint32_t *)(data +
+					IPV4_TCP_SEQ_NUM_OFFSET));
+				WMA_LOGE("TCP_seq_num: %d",
+					ani_cpu_to_be16(tcp_seq_num));
+			}
+		}
+		break;
+
+	case QDF_PROTO_IPV6_UDP:
+	case QDF_PROTO_IPV6_TCP:
+		WMA_LOGE("WOW Wakeup: %s rcvd",
+			wma_pkt_proto_subtype_to_string(proto_subtype));
+		if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) {
+			pkt_len = (uint16_t)(*(uint16_t *)(data +
+				IPV6_PKT_LEN_OFFSET));
+			WMA_LOGE("Pkt_len: %d",
+				ani_cpu_to_be16(pkt_len));
+			if (proto_subtype == QDF_PROTO_IPV6_TCP) {
+				tcp_seq_num = (uint32_t)(*(uint32_t *)(data +
+					IPV6_TCP_SEQ_NUM_OFFSET));
+				WMA_LOGE("TCP_seq_num: %d",
+					ani_cpu_to_be16(tcp_seq_num));
+			}
+		}
+		break;
+
+	default:
+end:
+		WMA_LOGE("wow_buf_pkt_len: %d", buf_len);
+		WMA_LOGE("Invalid Packet Type or Smaller WOW packet buffer than expected");
+		break;
+	}
+}
+
 /**
  * wma_wow_wakeup_host_event() - wakeup host event handler
  * @handle: wma handle
@@ -2764,14 +3045,25 @@ int wma_wow_wakeup_host_event(void *handle, uint8_t *event,
 			/* First 4-bytes of wow_packet_buffer is the length */
 			qdf_mem_copy((uint8_t *) &wow_buf_pkt_len,
 				     param_buf->wow_packet_buffer, 4);
-			wma_wow_wake_up_stats(wma,
-				param_buf->wow_packet_buffer + 4,
-				wow_buf_pkt_len,
-				WOW_REASON_PATTERN_MATCH_FOUND);
-			qdf_trace_hex_dump(QDF_MODULE_ID_WMA,
-					   QDF_TRACE_LEVEL_DEBUG,
-					   param_buf->wow_packet_buffer + 4,
-					   wow_buf_pkt_len);
+			if (wow_buf_pkt_len) {
+				uint8_t *data;
+
+				wma_wow_wake_up_stats(wma,
+					param_buf->wow_packet_buffer + 4,
+					wow_buf_pkt_len,
+					WOW_REASON_PATTERN_MATCH_FOUND);
+				qdf_trace_hex_dump(QDF_MODULE_ID_WMA,
+					QDF_TRACE_LEVEL_DEBUG,
+					param_buf->wow_packet_buffer + 4,
+					wow_buf_pkt_len);
+
+				data = (uint8_t *)
+					(param_buf->wow_packet_buffer + 4);
+				wma_wow_parse_data_pkt_buffer(data,
+					wow_buf_pkt_len);
+			} else {
+				WMA_LOGE("wow packet buffer is empty");
+			}
 		} else {
 			WMA_LOGE("No wow packet buffer present");
 		}