mac80211: add debug file for mic failure

The mic failure count provides the number of mic failures that
have happened on a given key (without a countermeasure being
started, since that would remove the key).

Signed-off-by: Saravana <saravanad@posedge.com>
[fix NULL pointer issues]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 2d42354..c3a3082 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -199,6 +199,22 @@
 }
 KEY_OPS(icverrors);
 
+static ssize_t key_mic_failures_read(struct file *file, char __user *userbuf,
+				     size_t count, loff_t *ppos)
+{
+	struct ieee80211_key *key = file->private_data;
+	char buf[20];
+	int len;
+
+	if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP)
+		return -EINVAL;
+
+	len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(mic_failures);
+
 static ssize_t key_key_read(struct file *file, char __user *userbuf,
 			    size_t count, loff_t *ppos)
 {
@@ -260,6 +276,7 @@
 	DEBUGFS_ADD(rx_spec);
 	DEBUGFS_ADD(replays);
 	DEBUGFS_ADD(icverrors);
+	DEBUGFS_ADD(mic_failures);
 	DEBUGFS_ADD(key);
 	DEBUGFS_ADD(ifindex);
 };
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 7cff0d3..382dc44 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -81,6 +81,9 @@
 
 			/* last received RSC */
 			struct tkip_ctx rx[IEEE80211_NUM_TIDS];
+
+			/* number of mic failures */
+			u32 mic_failures;
 		} tkip;
 		struct {
 			atomic64_t tx_pn;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 8bd2f5c..c175ee8 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -104,7 +104,7 @@
 	 */
 	if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
 		if (status->flag & RX_FLAG_MMIC_ERROR)
-			goto mic_fail;
+			goto mic_fail_no_key;
 
 		if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key &&
 		    rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
@@ -161,6 +161,9 @@
 	return RX_CONTINUE;
 
 mic_fail:
+	rx->key->u.tkip.mic_failures++;
+
+mic_fail_no_key:
 	/*
 	 * In some cases the key can be unset - e.g. a multicast packet, in
 	 * a driver that supports HW encryption. Send up the key idx only if