diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 8f231c6..ca50f0f 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -95,6 +95,21 @@ config ATH9K_TX99
 	  be evaluated to meet the RF exposure limits set forth in the
 	  governmental SAR regulations.
 
+config ATH9K_FRAME_LOSS_SIMULATOR
+	bool "Atheros ath9k frame loss simulator"
+	depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS
+	default n
+	---help---
+	  Say N. This option should be used only to test fail paths
+          and timeouts by inverting fcs field of selected frames to
+	  be transmitted.
+	  Which frames are corrupted is marked by bitfield in
+	  corrupt_fcs_frame_mask debug entry and probability of
+	  of corruption in corrupt_fcs_prob (0-255). Zero means
+	  disabled and writing 255 makes all selected frames fail.
+	  Management, EAPOL, and Null function frames are
+	  supported.
+
 config ATH9K_DFS_CERTIFIED
 	bool "Atheros DFS support for certified platforms"
 	depends on ATH9K && CFG80211_CERTIFICATION_ONUS
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 331947b..e5ae8f2 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -183,6 +183,9 @@ struct ath_frame_info {
 	u8 baw_tracked : 1;
 	u8 tx_power;
 	enum ath9k_key_type keytype:2;
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+	u8 corrupt_fcs : 1;
+#endif
 };
 
 struct ath_rxbuf {
@@ -1087,6 +1090,10 @@ struct ath_softc {
 	u32 rng_last;
 	struct task_struct *rng_task;
 #endif
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+	u16 corrupt_fcs_prob;
+	u32 corrupt_fcs_frame_mask;
+#endif
 };
 
 /********/
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 43930c3..15ccf52 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1315,6 +1315,50 @@ void ath9k_deinit_debug(struct ath_softc *sc)
 	ath9k_cmn_spectral_deinit_debug(&sc->spec_priv);
 }
 
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+static ssize_t read_file_corrupt_fcs_frame_mask(struct file *file,
+						char __user *user_buf,
+						size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[4];
+	unsigned int len;
+
+	len = sprintf(buf, "0x%08x\n", sc->corrupt_fcs_frame_mask);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_corrupt_fcs_frame_mask(struct file *file,
+						 const char __user *user_buf,
+						 size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	unsigned long corrupt_fcs_frame_mask;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &corrupt_fcs_frame_mask))
+		return -EINVAL;
+
+	sc->corrupt_fcs_frame_mask = corrupt_fcs_frame_mask;
+
+	return count;
+}
+
+static const struct file_operations fops_corrupt_fcs_frame_mask = {
+	.read = read_file_corrupt_fcs_frame_mask,
+	.write = write_file_corrupt_fcs_frame_mask,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+#endif
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1402,5 +1446,12 @@ int ath9k_init_debug(struct ath_hw *ah)
 	debugfs_create_u16("airtime_flags", S_IRUSR | S_IWUSR,
 			   sc->debug.debugfs_phy, &sc->airtime_flags);
 
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+	debugfs_create_u16("corrupt_fcs_prob", S_IRUSR | S_IWUSR,
+			   sc->debug.debugfs_phy, &sc->corrupt_fcs_prob);
+	debugfs_create_file("corrupt_fcs_frame_mask", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc,
+			    &fops_corrupt_fcs_frame_mask);
+#endif
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index c35a192..86a7e31 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1443,6 +1443,10 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
 			if (bf->bf_state.bfs_paprd)
 				info.flags |= (u32) bf->bf_state.bfs_paprd <<
 					      ATH9K_TXDESC_PAPRD_S;
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+			if (fi->corrupt_fcs)
+				info.flags |= ATH9K_TXDESC_CORRUPT_FCS;
+#endif
 
 			/*
 			 * mac80211 doesn't handle RTS threshold for HT because
@@ -2345,6 +2349,112 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
 	return 0;
 }
 
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+static bool corrupt_frame_fcs(struct ath_softc *sc, struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	/* Frame loss enable mask */
+	/* Bit 16 - Null function*/
+	/* Bit 15 - QoS Null function*/
+	/* Bit 14 - EAPOL */
+	/* Bit 13 - Action */
+	/* Bit 12 - Deauthentication */
+	/* Bit 11 - Authentication */
+	/* Bit 10 - Disassociation */
+	/* Bit 9  - ATIM */
+	/* Bit 8  - Beacon */
+	/* Bit 5  - Probe response */
+	/* Bit 4  - Probe request */
+	/* Bit 3  - Reassociation response */
+	/* Bit 2  - Reassociation request */
+	/* Bit 1  - Association response */
+	/* Bit 0  - Association request */
+
+	/* Frame loss probability is 0(0%) to 255(100%) */
+	if (sc->corrupt_fcs_prob &&
+	    get_random_int() % 256 <= sc->corrupt_fcs_prob) {
+		u16 fctl_stype =
+			le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
+
+		if (((1 << 16) & sc->corrupt_fcs_frame_mask) &&
+		    ieee80211_is_nullfunc(hdr->frame_control)) {
+			ath_info(common, "Null function frame corrupted\n");
+			return true;
+		}
+		if (((1 << 15) & sc->corrupt_fcs_frame_mask) &&
+		    ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+			ath_info(common, "QOS Null function frame corrupted\n");
+			return true;
+		}
+		if (((1 << 14) & sc->corrupt_fcs_frame_mask) &&
+		    (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
+			ath_info(common, "EAPOL frame corrupted\n");
+			return true;
+		}
+		if (ieee80211_is_mgmt(hdr->frame_control) &&
+		    ((1 << (fctl_stype >> 4)) & sc->corrupt_fcs_frame_mask)) {
+			switch (fctl_stype) {
+			case IEEE80211_STYPE_ASSOC_REQ:
+				ath_info(common,
+					 "Association request corrupted\n");
+				break;
+			case IEEE80211_STYPE_ASSOC_RESP:
+				ath_info(common,
+					 "Association response corrupted\n");
+				break;
+			case IEEE80211_STYPE_REASSOC_REQ:
+				ath_info(common,
+					 "Re-association request corrupted\n");
+				break;
+			case IEEE80211_STYPE_REASSOC_RESP:
+				ath_info(common,
+					 "Re-association response corrupted\n");
+				break;
+			case IEEE80211_STYPE_PROBE_REQ:
+				ath_info(common,
+					 "Probe request corrupted\n");
+				break;
+			case IEEE80211_STYPE_PROBE_RESP:
+				ath_info(common,
+					 "Probe response corrupted\n");
+				break;
+			case IEEE80211_STYPE_BEACON:
+				ath_info(common,
+					 "Beacon corrupted\n");
+				break;
+			case IEEE80211_STYPE_ATIM:
+				ath_info(common,
+					 "ATIM frame corrupted\n");
+				break;
+			case IEEE80211_STYPE_DISASSOC:
+				ath_info(common,
+					 "Disassociation frame corrupted\n");
+				break;
+			case IEEE80211_STYPE_AUTH:
+				ath_info(common,
+					 "Authentication frame corrupted\n");
+				break;
+			case IEEE80211_STYPE_DEAUTH:
+				ath_info(common,
+					 "Deauthentication frame corrupted\n");
+				break;
+			case IEEE80211_STYPE_ACTION:
+				ath_info(common,
+					 "Action frame corrupted\n");
+				break;
+
+			default:
+				return false;
+			}
+			return true;
+		}
+	}
+	return false;
+}
+#endif
 
 /* Upon failure caller should free skb */
 int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -2363,6 +2473,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 	struct ath_buf *bf;
 	bool ps_resp;
 	int q, ret;
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+	bool corrupt_fcs = corrupt_frame_fcs(sc, skb);
+#endif
 
 	if (vif)
 		avp = (void *)vif->drv_priv;
@@ -2373,6 +2486,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 	if (ret)
 	    return ret;
 
+#ifdef CONFIG_ATH9K_FRAME_LOSS_SIMULATOR
+	fi->corrupt_fcs = corrupt_fcs;
+#endif
+
 	hdr = (struct ieee80211_hdr *) skb->data;
 	/*
 	 * At this point, the vif, hw_key and sta pointers in the tx control
