Modifying regulations in Intel Wi-Fi card EEPROM

Regulations in EEPROM

Wi-Fi regulation defines various restirctions such as transmission power, initial radiation, and dynamic frequency switching for Wi-Fi to operate in a certain country. Most OSs including Linux contain regulations in their kernels, and we can bypass them by modifying a regulation file or a kernel.

However, certain Wi-Fi cards such as Intel’s have their own regulations in their EEPROM, which takes precedence to kernel’s regulations. Here’s how to modify regulations in Intel Wi-Fi card’s EEPROM. In this article, Intel Ultimate N WiFi Link 5300 is used

Preparing a Tool

iwleeprom is a software to read and write content in an EEPROM. Clone, build and install it:

1
2
3
4
$ git clone [https://github.com/0x90/iwleeprom](https://github.com/0x90/iwleeprom)
$ cd iwleeprom
$ make
$ [sudo] make install

Interpreting a Regulation Flag

First, let’s have a look at what EEPROM contains. To read regulations in EEPROM, type iwleeprom -s:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ iwleeprom -s
Supported devices detected:
[1] 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 (8086:4236, 8086:1011)
Select device [1-1] (or 0 to quit): 1
Using device 0000:03:00.0 [RW] Ultimate N WiFi Link 5300
No file names given or patch option selected!
No EEPROM actions will be performed, just write-enable test
Regulatory data from card EEPROM...
Regulatory base: 0156
Channel 1: 0e6f
Channel 2: 0f6f
...
Channel 64: 0f31
...
Channel 1 (HT40): 0a6f
Channel 2 (HT40): 0f6f
...
Channel 157 (HT40): 0f61

What those 0e6f, 0f31 and other things mean? Those are flags defining regulations. So, which bit stands for what? When you are looking into Linux kernel source code, specifically, iwlwifi driver, you can see flag definition as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* enum iwl_eeprom_channel_flags - channel flags in EEPROM
* @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo
* @EEPROM_CHANNEL_IBSS: usable as an IBSS channel
* @EEPROM_CHANNEL_ACTIVE: active scanning allowed
* @EEPROM_CHANNEL_RADAR: radar detection required
* @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?)
* @EEPROM_CHANNEL_DFS: dynamic freq selection candidate
*/
enum iwl_eeprom_channel_flags {
EEPROM_CHANNEL_VALID = BIT(0),
EEPROM_CHANNEL_IBSS = BIT(1),
EEPROM_CHANNEL_ACTIVE = BIT(3),
EEPROM_CHANNEL_RADAR = BIT(4),
EEPROM_CHANNEL_WIDE = BIT(5),
EEPROM_CHANNEL_DFS = BIT(7),
};

For example, channel 1 has flags 0e6f, which is 1110 0110 1111 in binary. Its interpretation is:

1
2
3
4
5
6
7
8
1110 0110 1111
.............1 This channel is valid
............1. Not valid for IBSS
...........1.. (Unknown)
..........1... Active scanning is allowed
........0..... RADAR detection is not required
.......1...... Supports wide band
......1....... Candidate for dynamic frequency selection

Reading EEPROM

To read and dump EEPROM, type iwleeprom -o <outfile>:

1
2
3
4
5
6
7
8
9
10
11
12
$ iwleeprom -b -o eeprom_dump
Supported devices detected:
[1] 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 (8086:4236, 8086:1011)
Select device [1-1] (or 0 to quit): 1
Using device 0000:03:00.0 [RW] Ultimate N WiFi Link 5300
Saving dump with byte order: BIG ENDIAN
0000 [................................................................]
0080 [................................................................]
...
0780 [................................................................]

EEPROM has been dumped to eeprom_dump

We can view the dumped EEPROM with xxd command or hex mode (:%!xxd) in vim, and can find channel flags. They are written in the same order of channels, but their offsets are not in linear relationships. You can manually locate an offset of each channel:

1
2
3
4
5
6
7
8
9
10
11
12
$ vim eeprom_dump
:%!xxd
00000000: 5a40 0050 7000 0410 0030 0000 0280 8086 4236 8086 1011 0d01 [email protected].......
...
00000150: ---- ---- ---- ---- ---- ---- ---- --0e 6f0f 6f0f 6f0f 6f0f :.........oM.W...o.o.o.o.
00000168: 6f0f 6f0f 6f0f 6f0f 6f0f 6f0f 6f0f 610f 6100 0000 0000 0000 :o.o.o.o.o.o.o.a.a.......
00000180: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 :........................
00000198: 0000 000f e100 000f e100 000f e100 000f e10f 310f 310f 310f :..................1.1.1.
000001b0: 3100 000f 310f 310f 310f 310f 310f 310f 310f 310f 310f 310f :1...1.1.1.1.1.1.1.1.1.1.
000001c8: 3100 0000 000f a10f a10f a10f a10f a100 000d 0a6f 0f6f 0f6f :1..................o.o.o
000001e0: 0f6f 0f6f 0f6f 0c6f 0000 0ce1 0fe1 0f31 0d31 0e31 0f31 0f31 :.o.o.o.o.......1.1.1.1.1
000001f8: 0f31 0f31 0f61 0f61 :.1.1.a.a

Modifying Regulations

It is easy. Open the dumped EEPROM in vim and set to hex mode (:%!xxd). And change the content as you want. To save changes, reert hex mode (:%!xxd -r) and save it (:w)

Writing New Regulations in EEPROM

After finishing modification, rewrite EEPROM with iwleeprom -m -c -i <infile>:

1
2
3
4
5
6
7
8
9
10
11
12
$ iwleeprom -m -c -i eeprom_dump
Supported devices detected:
[1] 0000:03:00.0 [RW] Ultimate N WiFi Link 5300 (8086:4236, 8086:1011)
Select device [1-1] (or 0 to quit): 1
Using device 0000:03:00.0 [RW] Ultimate N WiFi Link 5300
Dump file byte order: BIG ENDIAN
0000 [================================================================]
0080 [================================================================]
...
0780 [================================================================]

EEPROM has been written from eeprom_dump

Finally, you can check modification is applied via iw phy command