Add debugfs entries to corrupt specified frame types by invering fcs field upon transmissionm with given probability. Select frames to be corrupted. <ath9k_debugs>/corrupt_fcs_fram_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 Select corruption probability: <ath9k_debugs>/corrupt_fcs_prob: 0(0%) to 255(100%) Signed-off-by: Wojciech Dubowik <Wojciech.Dubowik@xxxxxxxxxxx> --- drivers/net/wireless/ath/ath9k/Kconfig | 15 +++++ drivers/net/wireless/ath/ath9k/ath9k.h | 7 ++ drivers/net/wireless/ath/ath9k/debug.c | 51 ++++++++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 117 +++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+) 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 -- 2.7.4