2013-04-16 10:52:19

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/2] ath: update hardware mac address with bssid mask

Preparation for updating common->macaddr along with virtual interface
MAC address changes.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 7 +++----
drivers/net/wireless/ath/ath9k/reg.h | 3 ---
drivers/net/wireless/ath/hw.c | 6 ++++++
drivers/net/wireless/ath/reg.h | 4 ++++
4 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8a980a4..10eb6ba 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1698,12 +1698,11 @@ static void ath9k_hw_reset_opmode(struct ath_hw *ah,

ENABLE_REGWRITE_BUFFER(ah);

- REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
- REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
- | macStaId1
+ REG_RMW(ah, AR_STA_ID1, macStaId1
| AR_STA_ID1_RTS_USE_DEF
| (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
- | ah->sta_id1_defaults);
+ | ah->sta_id1_defaults,
+ ~AR_STA_ID1_SADH_MASK);
ath_hw_setbssidmask(common);
REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
ath9k_hw_write_associd(ah);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 5929850..5c4ab50 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1493,9 +1493,6 @@ enum {
#define AR9271_RADIO_RF_RST 0x20
#define AR9271_GATE_MAC_CTL 0x4000

-#define AR_STA_ID0 0x8000
-#define AR_STA_ID1 0x8004
-#define AR_STA_ID1_SADH_MASK 0x0000FFFF
#define AR_STA_ID1_STA_AP 0x00010000
#define AR_STA_ID1_ADHOC 0x00020000
#define AR_STA_ID1_PWR_SAV 0x00040000
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
index 39e8a59..eae9abf 100644
--- a/drivers/net/wireless/ath/hw.c
+++ b/drivers/net/wireless/ath/hw.c
@@ -118,6 +118,12 @@
void ath_hw_setbssidmask(struct ath_common *common)
{
void *ah = common->ah;
+ u32 id1;
+
+ REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
+ id1 = REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_SADH_MASK;
+ id1 |= get_unaligned_le16(common->macaddr + 4);
+ REG_WRITE(ah, AR_STA_ID1, id1);

REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask));
REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4));
diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h
index 298e53f..3ad4c77 100644
--- a/drivers/net/wireless/ath/reg.h
+++ b/drivers/net/wireless/ath/reg.h
@@ -23,6 +23,10 @@
#define AR_MIBC_CMC 0x00000004
#define AR_MIBC_MCS 0x00000008

+#define AR_STA_ID0 0x8000
+#define AR_STA_ID1 0x8004
+#define AR_STA_ID1_SADH_MASK 0x0000ffff
+
/*
* BSSID mask registers. See ath_hw_set_bssid_mask()
* for detailed documentation about these registers.
--
1.8.0.2



2013-04-17 16:39:32

by Simon Wunderlich

[permalink] [raw]
Subject: Re: [PATCH 2/2] ath9k: always set common->macaddr to the MAC adress of a virtual interface

On Tue, Apr 16, 2013 at 12:51:57PM +0200, Felix Fietkau wrote:
> In some cases it can be useful to change the MAC address of a virtual
> interface to something that's completely different from the EEPROM
> stored MAC address. In this case it is a bad idea to use the EEPROM MAC
> address for calculating the BSSID mask, as that would make it too wide.
>
> In one case a few devices have been observed to send ACKs for many
> packets on the channel not directed at them, which results in a neat
> Denial of Service attack on the channel.

This was really giving me a hard time. Thanks a lot for finding the cause
and fixing that. :)

Cheers,
Simon
>
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
> drivers/net/wireless/ath/ath9k/ath9k.h | 7 +++----
> drivers/net/wireless/ath/ath9k/main.c | 9 +++++++--
> 2 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 86d3572..1915f12 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -658,11 +658,10 @@ enum sc_op_flags {
> struct ath_rate_table;
>
> struct ath9k_vif_iter_data {
> - const u8 *hw_macaddr; /* phy's hardware address, set
> - * before starting iteration for
> - * valid bssid mask.
> - */
> + u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
> u8 mask[ETH_ALEN]; /* bssid mask */
> + bool has_hw_macaddr;
> +
> int naps; /* number of AP vifs */
> int nmeshes; /* number of mesh vifs */
> int nstations; /* number of station vifs */
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index a383483..6963862 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -839,10 +839,14 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
> struct ath9k_vif_iter_data *iter_data = data;
> int i;
>
> - if (iter_data->hw_macaddr)
> + if (iter_data->has_hw_macaddr) {
> for (i = 0; i < ETH_ALEN; i++)
> iter_data->mask[i] &=
> ~(iter_data->hw_macaddr[i] ^ mac[i]);
> + } else {
> + memcpy(iter_data->hw_macaddr, mac, ETH_ALEN);
> + iter_data->has_hw_macaddr = true;
> + }
>
> switch (vif->type) {
> case NL80211_IFTYPE_AP:
> @@ -891,7 +895,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
> * together with the BSSID mask when matching addresses.
> */
> memset(iter_data, 0, sizeof(*iter_data));
> - iter_data->hw_macaddr = common->macaddr;
> memset(&iter_data->mask, 0xff, ETH_ALEN);
>
> if (vif)
> @@ -901,6 +904,8 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
> ieee80211_iterate_active_interfaces_atomic(
> sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
> ath9k_vif_iter, iter_data);
> +
> + memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN);
> }
>
> /* Called with sc->mutex held. */
> --
> 1.8.0.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


Attachments:
(No filename) (3.11 kB)
signature.asc (198.00 B)
Digital signature
Download all attachments

2013-04-16 10:52:20

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/2] ath9k: always set common->macaddr to the MAC adress of a virtual interface

In some cases it can be useful to change the MAC address of a virtual
interface to something that's completely different from the EEPROM
stored MAC address. In this case it is a bad idea to use the EEPROM MAC
address for calculating the BSSID mask, as that would make it too wide.

In one case a few devices have been observed to send ACKs for many
packets on the channel not directed at them, which results in a neat
Denial of Service attack on the channel.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 7 +++----
drivers/net/wireless/ath/ath9k/main.c | 9 +++++++--
2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 86d3572..1915f12 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -658,11 +658,10 @@ enum sc_op_flags {
struct ath_rate_table;

struct ath9k_vif_iter_data {
- const u8 *hw_macaddr; /* phy's hardware address, set
- * before starting iteration for
- * valid bssid mask.
- */
+ u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
u8 mask[ETH_ALEN]; /* bssid mask */
+ bool has_hw_macaddr;
+
int naps; /* number of AP vifs */
int nmeshes; /* number of mesh vifs */
int nstations; /* number of station vifs */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index a383483..6963862 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -839,10 +839,14 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct ath9k_vif_iter_data *iter_data = data;
int i;

- if (iter_data->hw_macaddr)
+ if (iter_data->has_hw_macaddr) {
for (i = 0; i < ETH_ALEN; i++)
iter_data->mask[i] &=
~(iter_data->hw_macaddr[i] ^ mac[i]);
+ } else {
+ memcpy(iter_data->hw_macaddr, mac, ETH_ALEN);
+ iter_data->has_hw_macaddr = true;
+ }

switch (vif->type) {
case NL80211_IFTYPE_AP:
@@ -891,7 +895,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
* together with the BSSID mask when matching addresses.
*/
memset(iter_data, 0, sizeof(*iter_data));
- iter_data->hw_macaddr = common->macaddr;
memset(&iter_data->mask, 0xff, ETH_ALEN);

if (vif)
@@ -901,6 +904,8 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_vif_iter, iter_data);
+
+ memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN);
}

/* Called with sc->mutex held. */
--
1.8.0.2