Arthur's blog

Hacking ath9k wifi device adventures

So here is where it all started. I have this apple branded atheros AR5BXB92, with an ar9280 chipset, which is supported by the ath9k Linux drivers. This chipset is supposed to support both 5GHz and 2.4GHz frequencies, but using the wavemon tool 5GHz SSID never show up even when I'm next to a device that emits one.

iw list shows the following:

Band 2:
    Capabilities: 0x11ce
        HT20/HT40
        SM Power Save disabled
        RX HT40 SGI
        TX STBC
        RX STBC 1-stream
        Max AMSDU length: 3839 bytes
        DSSS/CCK HT40
    Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
    Minimum RX AMPDU time spacing: 8 usec (0x06)
    HT TX/RX MCS rate indexes supported: 0-15
    Bitrates (non-HT):
        * 6.0 Mbps
        * 9.0 Mbps
        * 12.0 Mbps
        * 18.0 Mbps
        * 24.0 Mbps
        * 36.0 Mbps
        * 48.0 Mbps
        * 54.0 Mbps
    Frequencies:
        * 5180 MHz [36] (16.0 dBm) (no IR)
        * 5200 MHz [40] (16.0 dBm) (no IR)
        * 5220 MHz [44] (16.0 dBm) (no IR)
        * 5240 MHz [48] (16.0 dBm) (no IR)
        * 5260 MHz [52] (17.0 dBm) (no IR, radar detection)
        * 5280 MHz [56] (16.0 dBm) (no IR, radar detection)
        * 5300 MHz [60] (16.0 dBm) (no IR, radar detection)
        * 5320 MHz [64] (16.0 dBm) (no IR, radar detection)
        * 5500 MHz [100] (disabled)
        * 5520 MHz [104] (disabled)
        * 5540 MHz [108] (disabled)
        * 5560 MHz [112] (disabled)
        * 5580 MHz [116] (disabled)
        * 5600 MHz [120] (disabled)
        * 5620 MHz [124] (disabled)
        * 5640 MHz [128] (disabled)
        * 5660 MHz [132] (disabled)
        * 5680 MHz [136] (disabled)
        * 5700 MHz [140] (disabled)
        * 5745 MHz [149] (disabled)
        * 5765 MHz [153] (disabled)
        * 5785 MHz [157] (disabled)
        * 5805 MHz [161] (disabled)
        * 5825 MHz [165] (disabled)

So most of the 5GHz channels which are avaible in my country were disabled. Changing the reg domain iw reg set BE did not change this On the web I found some articles about modifying the reg domain in the eeprom that is present on that wifi card. One of these is the following guide. The link to the iwleeprom code is dead but can be found on the following github repo. Doing so I found out that my region code is 0x65. I tried to modify that eeprom content but that didn't seem to work properly for some reason. I knew that almost everything is done by the kernel driver so I looked for the possibilty to override this regional setting an I found it! By changing the reg_rules for my 0x65 domain device and recompiling the ath9k module I got those 5GHz appearing in wavemon and listed as supported in iw list!

diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index e25bfdf78c2e..e4cbf366b4e3 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -74,12 +74,12 @@ static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
 /* Can be used by 0x63 and 0x65 */
 static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
-   .n_reg_rules = 4,
+   .n_reg_rules = 5,
    .alpha2 =  "99",
    .reg_rules = {
-       ATH9K_2GHZ_CH01_11,
-       ATH9K_2GHZ_CH12_13,
-       ATH9K_5GHZ_NO_MIDBAND,
+       ATH9K_2GHZ_ALL,
+       ATH9K_5GHZ_ALL,
+
    }
 };

Not wanting to recompile this module each time I get a kernel update, I looked into modifying the eeprom again to change it to a value where those channel were permanently enabled (0x60 for instance). So I looked at the the dump iweeprom provided me

./iwleeprom -o mydump.bin

The dump looked like this:

00000000: 5AA5 0000 0300 0060 8C16 2900 0860 0100  Z......`..)..`..
00000010: 8002 2C60 6B10 8F00 0050 8C16 2A00 0850  ..,`k....P..*..P
00000020: 0100 8002 2C50 6B10 8F00 6450 C00C 0405  ....,Pk...dP....
00000030: 6C50 1138 0300 0440 3B07 4000 7440 0300  lP.8...@;.@.t@..
00000040: 0000 0040 0150 C2FF 1440 0004 003A 3460  ...@.P...@...:4`
00000050: 4400 0000 FFFF FFFF FFFF FFFF FFFF FFFF  D...............
00000060: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000070: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000080: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000090: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000000a0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000000b0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000000c0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000000d0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000000e0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000000f0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000100: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000110: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000120: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000130: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000140: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000150: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000160: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000170: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000180: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000190: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000001a0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000001b0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000001c0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000001d0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000001e0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
000001f0: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF  ................
00000200: B80C AB15 16E0 0302 6500 1F00 D49A 2060  ........e..... `
00000210: 06C6 0303 0000 0000 0000 0004 0900 0501  ................
00000220: 01FF 0200 0001 0000 00FB 0000 0000 0000  ................
00000230: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000240: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000250: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000260: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000270: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000280: 4001 0000 4001 0000 0000 0000 1002 0000  @...@...........
00000290: 0000 002C 2020 0B00 000B E200 0E0E 0E00  ...,  ..........
000002a0: 020E 1CCA CACA 0301 0000 0000 0000 0604  ................
000002b0: 0400 0000 0E0E 0215 1500 1F1F 002C 0000  .............,..
000002c0: 0000 0000 0404 1D09 0000 0000 0000 8E8C  ................
000002d0: 888E 8C88 0080 0000 0000 0000 0000 0000  ................
000002e0: 0000 0000 0000 0000 1000 0000 1000 0000  ................
000002f0: 0000 0000 1002 0000 0000 002D 2020 0B00  ...........-  ..
00000300: 0010 E200 0D0D 0D00 020E 1CFF FFFF 0301  ................

etc…

From the previously linked blogpost it looks like the country code resides at offset 520 or 0x208 and indeed that one contains 0x65. So one needs to change that to 0x60. (one still needs to change the checksum but later more about that) When trying to write this back to the eeprom, it does not seem to do anything. A first clue comes for the iwleeprom output.

ath9k short eeprom base: 0  size: 512

The things I changed reside at addresses larger than byte 512. So I changed the iwleeprom to do just that.

diff --git a/iwleeprom/ath9kio.c b/iwleeprom/ath9kio.c
index c57062d..83187e3 100644
--- a/iwleeprom/ath9kio.c
+++ b/iwleeprom/ath9kio.c
@@ -799,8 +799,8 @@ static bool ath9k_eeprom_check(struct pcidev *dev)
        goto ssize_ok;
    }
    if (dev->ops->eeprom_read16(dev, 512, &data) && (3256 == data)) {
-       short_eeprom_base =  0;
-       short_eeprom_size = 512;
+       short_eeprom_base =  512;
+       short_eeprom_size = 1024 * 4;
        goto ssize_ok;
    }
    if (dev->ops->eeprom_read16(dev, 256, &data) && (727 == data)) {

Using this I was able to write back my changes to the eeprom. But Linux won't be happy about this since the eeprom's checksum still needs to be fixes. Looking at the linux source it looks like the checksum is computed by XORing each word of the eeprom and expects the result to be 0xffff. The bytes to fix this checksum result are bytes 514-515. After some trial and error I found that the checksum needs to be computed from byte 512 to byte 4096, which the iwleeprom tool will correctly provide with the patch mentioned above.

Supported devices detected:
  [1] 0000:02:00.0 [RW] AR928X Wireless Adapter (PCI-E) (168c:002a, 106b:008f)
Select device [1-1] (or 0 to quit): 1
Using device 0000:02:00.0 [RW] AR928X Wireless Adapter (PCI-E)
IO driver: ath9k
HW: AR9280 (PCI-E) rev 0002
RF: integrated
Checking NVM size...
ath9k short eeprom base: 512  size: 4096
MAC address : d4:9a:20:60:06:c6
Reg. domain : 0065
Capabilities: 0203
       Bands:  5GHz 2.4GHz
       HT 2G:  HT20 HT40
       HT 5G:  HT20 HT40
CRC (stored): 15ab
Calculating EEPROM CRC...............................
CRC (eval)  : 15ab

What needs to be programmed at byte 0x202-0x203 is computed in the CRC (eval) entry. Use your favorite hexeditor to change this and write it back. (make a backup of the file you want to edit first) Reload the ath9k module.

./iwleeprom -i modified.bin

rmmod ath9k; modprobe ath9k

and finally we get

Frequencies:
    * 5180 MHz [36] (20.0 dBm) (no IR)
    * 5200 MHz [40] (20.0 dBm) (no IR)
    * 5220 MHz [44] (20.0 dBm) (no IR)
    * 5240 MHz [48] (20.0 dBm) (no IR)
    * 5260 MHz [52] (20.0 dBm) (no IR, radar detection)
    * 5280 MHz [56] (20.0 dBm) (no IR, radar detection)
    * 5300 MHz [60] (20.0 dBm) (no IR, radar detection)
    * 5320 MHz [64] (20.0 dBm) (no IR, radar detection)
    * 5500 MHz [100] (27.0 dBm) (no IR, radar detection)
    * 5520 MHz [104] (27.0 dBm) (no IR, radar detection)
    * 5540 MHz [108] (27.0 dBm) (no IR, radar detection)
    * 5560 MHz [112] (27.0 dBm) (no IR, radar detection)
    * 5580 MHz [116] (27.0 dBm) (no IR, radar detection)
    * 5600 MHz [120] (27.0 dBm) (no IR, radar detection)
    * 5620 MHz [124] (27.0 dBm) (no IR, radar detection)
    * 5640 MHz [128] (27.0 dBm) (no IR, radar detection)
    * 5660 MHz [132] (27.0 dBm) (no IR, radar detection)
    * 5680 MHz [136] (27.0 dBm) (no IR, radar detection)
    * 5700 MHz [140] (27.0 dBm) (no IR, radar detection)
    * 5745 MHz [149] (disabled)
    * 5765 MHz [153] (disabled)
    * 5785 MHz [157] (disabled)
    * 5805 MHz [161] (disabled)
    * 5825 MHz [165] (disabled)

Mission accomplished!