Summary attempt: The WiFi chip limitation status of Linksys WRT 1900, 3200 and 32X

H, greetings

I am new to OpenWRT installed on the WRT series of Linksys.
I once bought a WRT 32X a while ago, over the time struggling a lot with WIFI packet losses on the stock firmware (some threads on the internet confirmed these packet loss issues, recommended going to OpenWRT), which brought me to switch to OpenWRT. I actually even bought the device at that time, having in mind that there is a large community backing the future of the device.
OpenWRT mostly fixed the packet drops on first sight, but OpenWRT has shown some heavy WiFi restrictions that seem hardware-related.

It took me some days of research, to hunt down the overall OpenWRT WiFi status of the 32X. I would like to try to summarize it and ask for feedback from you guys, if my summary is correct. The following is subjective summary/impression of me. I had a bit of hard time following up in a lot of discussion threads. Please correct me, if my assumptions or impressions regarding the WRT routers collected here are incorrect.

So there are WiFi restrictions affecting Linksys WRT 1900/3200/32X, but not WRT 1200. The 1200 does not seem affected merely because the 1200 is no longer sold and the WRT device WiFi restrictions seemed to have been introduced somewhat around 2017, around the same time when the 1200 went out of stock.

Subvariants of WRT 1900/3200/32X routers seem to exist:

  • From my understanding at least for the 1900 and 3200 there seem to be variants available ("old" and "new" versions), which seem to differ that the newer versions (since ~2017??) have a regulatory-locked-down WIFI firmware chip, which is the main reason for the current WiFi restriction problems.
  • It seems like the 32X exists only as WiFi regulatory-locked-down edition.
  • According to my browsing on lots of GITHUB threads and this forum, also regional variants of the 3 routers seem to exist, where the Wifi chip is prelocked-down to certain regionals (e.g. US or EU). And this seems not due to a regional specific WIFI Firmware blob, but due to a lock-down implemented in the WiFi hardware?
  • 32X seems to be the same hardware as the newer variant of 3200, with just a different case color and different partition layout and different initial vendor firmware and a different initial price tag.

The WRT3200 and WRT32X have a third radio, this 3rd radio can be set to either WiFi n or WiFI AC. The 1900 does not seem to have that third radio. The 3rd radio seems to have a 10-device-connection-limit and has only a single antenna (1x1), while radio 0 (5GHz) is 3x3 MIMO and radio 1 (2.4 Ghz) is 2x2 MIMO.

  • The primary radios 0 and 1 of all three (1900, 3200, 32X) is a 88W8964, which relies on driver "mwlwifi"
  • The secondary radio 2 chip on 3200 and on 32X is a 88W8887 and uses driver "mwifiex"

The radio 2 (88W8887) firmware is not that much locked down/crippled, but misses a practical MIMO antenna design, so its just useful as a secondary WiFi.
The main WiFi chip 88W8964 firmware is crippled down heavily, basically preventing a lot of WiFi things, like setting a WiFi country code or configuring certain power settings, even if certain settings would be regulatory-allowed in your country. In the end, this is due to WiFi chip and WiFi firmware restrictions, that ignores most attempts of OpenWRT, to set several custom settings. The device WiFi will ignore that and instead use pre-encoded hardware defaults.

My tests are based on the current OpenWRT version 19.07.7.

Currently it does not seem possible to change or view the correct WiFI region via LUCI GUI on any of the three routers.
You can change the WiFi country code in LUCI, but afterwards "iw reg get" on the SSH command line will still always show "FR" on EU-variants and "US" on US-variants of the router (no idea what other world-wide hardware variant exist and will show). The routers sold in Europe all seem to be locked to country code "FR".
On the EU(FR) variants, the "iw reg show" on command line will always show "98" for the global region on the W32X, while the radios 0 and 1 show "FR". Radio 2 country can actually be adapted individually.
On the WRT3200, it seems like "global" changes to the contry code as the 3 radios, when radio 2 is manually set to the same region code as radios 0 and 1.

Radio 2 on 3200 and 32X (radio 2 being the "third" radio with the 1x1 antenna and 10 device limit) can be freely changed to any region, but this needs a custom command. You cannot use LUCI for that: Instead use command line:
echo "mwifiex reg_alpha2=FR" > /etc/modules.d/mwifiex
(This setting is said to survive reboots and shutdowns, but is currently not in sync with the LUCI GUI settings or the "uci" command line)

If you switch country code of radio 2 (the only one with a customizable country code) to a different country (different from the hard-coded country of radio 0 and 1), the lowest common limitation denominator of the two country settings is said to apply to all radios. So since radio 0 and 1 are hard-locked to a specific country like FR or US (depending on the regional hardware variant you purchased initially), you may need to basically set radio 2 to the same region of radio 0 and 1, to not even further botch down your device on top of the already mandatory WiFi regulatory restrictions of radio 0 and 1.

My own experiments so far with the radio 2 on WRT32X(EU variant with FR country code) showed that several WiFi settings are not possible to be set on radio 2, even though OpenWRT 19.07.7 offers them as choice:

  • WiFi n with 2.4 GhZ seems not to have any issues running on radio 2.
  • But several WiFi AC-channels do not seem to work on radio 2. A channel that did work successfully for me was channel 44.
  • I was unable to fire up radio 2 with a channel width of 80 MHz. 40 MHz did work though for radio 2.
  • since LUCI country is not in sync with the real country code of the WiFi chip, I cannot set several maximum transmit power settings offered in LUCI GUI.
    If radio 2 does not start up, I basically check the log file via SSH "logread", to find out clues which LUCI setting might have prevented the radio 2 start up and try to vary the settings.

Furthermore "WMM mode" on radio 0 and 1 is said to have issues with certain WiFi client device chips (ESP8266). Disabling "WMM Mode" is said to fix some of these problems.
Radio 2 is not having those issues with ESP8266-based client devices.

Furthermore some threads teasered hints that some radio 0 WiFi channel width variants available in "uci" command line are not shown in LUCI GUI. And some of these combinations of WiFi channel (?), width (?) and encryption cipher (?) seem to prevent Linksys WRT radio 0 (5Hgz AC) from starting up on all of 1900, 3200 and 32X. Several owners of 3200 and 32X have pointed out in threads, that radio 0 may not start up and for some that in the end, a lot of try attempts of switching of country code and channel width and channel, combined with reboots in some cases helped firing up radio 0 (the primary 5 GHz AC radio).
I also had some radio 0 issues. For me, several of the following attempts on the command line got my radio 0 up and running:
wifi status
wifi up radio1
/etc/init.d/network restart
(+some reboots)
(my issues were not due to delays of DFS search, I was waiting for 2h before starting to mess with the command line)

Several threads showed that developers are unhappily trying to contact Linksys and the WiFi chip vendor for better open source WiFi support, as originally advertised by the vendor. This being just recent contact attempt activities of early year 2021. So far a dead end. Even unaccepted GIT pull requests are said exist.
Even an unanswered petition exist, to get better vendor support for the dead end device WiFi issues:

so my conclusion is:
The Linksys WRT series 1900/3220/32X has noticable and for some disappointing WiFi restrictions under OpenWRT. Better check these WiFi restrictions first before buying, if the previous mentioned restrictions and the lack of WiFi vendor support bothers you or not.
So again, the previous is just a summary attempt, of what I have understood so far. Please feel free to respond, to correct wrong assumptions or summaries of me.
I think that may help not just me, but others as well, to get a comprehensive summary of what to expect from the WiFi of these WRT devices.
My post is not meant to provide bad talk about the 3 devices, but to be informed better, what the WRT WiFi can do and what it cannot do.

some (not all) of the threads I scavanged for this summary:


For the 1900 they actually released a V1 and V2 so they are easily identifiable. The later model had stricter power tables (i.e. hardcoded) if i remember correctly.
For the 3200, the old and new variants were a silent update to the flash or memory modules only. Wifi is unaffected by this change.

1900 = 88W8864
3200/32X = 88W8964
Yes both are mwlwifi.

In your list of sources, no where did you mention the OpenWrt Wiki/ToH, which would have provided at least an introductory background to most things you've mentioned. If you feel you've uncovered additional information, you should put it back into the wiki.

Just one addition: radio 2 can be disabled completely (by uninstalling the corresponding packages) to avoid interfering with the operation of the other two.

Is this really true (i.e in OpenWrt)? My understanding was that this is purely a function of regdb i.e.user-space software and not even the firmware blob, far be it hard-coded in hardware. Can current owners of the WRT series on this forum share their experience, if this limitation exists in OpenWrt and if so, where exactly does it reside?

It is true as stated.
The limitation is that the wifi firmware is written in a way such to ignore attempts from regdb (or any other source) to adjust country codes, power levels, allowed channels etc.
As the driver is a black box (closed source), there's nothing that can be done.
Some users have modified the driver (open source) to allow a different country code, but all this does is stop the driver and OpenWrt falling over each other. The powertables are still hard coded.

This was a move from Linksys in response to a potential FCC action which was to force the inability to change transmission limits (even in open source). It was an overreaction to something which I don't think ever got enforced?
This is all well documented. No need to doubt.

1 Like

One exception to this is the wrt32x which for some regional variants actually loads it's power tables from a text file on the OEM firmware.
Unfortunately the format of the file is a mystery, and the driver was never modified to allow this method of loading the tables.
That's about as close to unlocked as you would get, if we understood both black box elements.

Just to confirm, the limitation is in the wifi firmware blob, and not in the hardware, is that right?

Thanks for confirming what @Pico posted above. I still find it difficult to believe, because that would imply that Marvell has to release a different wifi firmware blob for every country that the router would be used and somehow prevent these firmware blobs from being swapped out by end users for different countries. Is that so? The latter seems almost impossible, given the open source nature of the driver and OS. Or am I missing something very basic here?

To check if a wrtpac device loads from DTS

root@mamba:/etc/config# cat /sys/kernel/debug/ieee80211/phy0/mwlwifi/info
power table loaded from dts: yes

if the answer is no, the power table comes from info embedded in the eeprom.
mamba, cobra, caiman (V1), shelby(V1) should all say yes. Things changed after the release of those.

In an attempt to deal with CC

From 664cb677488e733ae7606a8f16c150496a96c544 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Santamar=C3=ADa=20Rogado?= <>
Date: Wed, 11 Sep 2019 22:41:51 +0200
Subject: [PATCH] mwlwifi: Don't lock system reg domain
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

mwlwifi forces the firmware hardcoded reg domain and this causes several issues.
This patch from McDebian makes mwlwifi to don't mess up the kernel reg domain.

Signed-off-by: David Santamaría Rogado <>
 .../kernel/mwlwifi/patches/002-regfree.patch  | 104 ++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 package/kernel/mwlwifi/patches/002-regfree.patch

diff --git a/package/kernel/mwlwifi/patches/002-regfree.patch b/package/kernel/mwlwifi/patches/002-regfree.patch
new file mode 100644
index 00000000000..8e476b20dfd
--- /dev/null
+++ b/package/kernel/mwlwifi/patches/002-regfree.patch
@@ -0,0 +1,104 @@
+--- a/core.c
++++ b/core.c
+@@ -858,11 +858,7 @@
+ 		mwl_fwcmd_get_txpwrlmt_cfg_data(hw);
+ 	}
+-	if (priv->chip_type == MWL8964)
+-		rc = mwl_fwcmd_get_fw_region_code_sc4(hw,
+-						      &priv->fw_region_code);
+-	else
+-		rc = mwl_fwcmd_get_fw_region_code(hw, &priv->fw_region_code);
++	rc = mwl_fwcmd_get_fw_region_code(hw, &priv->fw_region_code);
+ 	if (!rc) {
+ 		priv->fw_device_pwrtbl = true;
+ 		mwl_regd_init(priv);
+--- a/hif/fwcmd.c
++++ b/hif/fwcmd.c
+@@ -94,7 +94,6 @@
+ 		{ HOSTCMD_CMD_GET_DEVICE_PWR_TBL, "GetDevicePwrTbl" },
+ 		{ HOSTCMD_CMD_SET_RATE_DROP, "SetRateDrop" },
+ 		{ HOSTCMD_CMD_QUIET_MODE, "QuietMode" },
+ 		{ HOSTCMD_CMD_CORE_DUMP_DIAG_MODE, "CoreDumpDiagMode" },
+@@ -3431,42 +3430,6 @@
+ }
+-int mwl_fwcmd_get_fw_region_code_sc4(struct ieee80211_hw *hw,
+-				     u32 *fw_region_code)
+-	struct mwl_priv *priv = hw->priv;
+-	struct hostcmd_cmd_get_fw_region_code_sc4 *pcmd;
+-	u16 cmd;
+-	pcmd = (struct hostcmd_cmd_get_fw_region_code_sc4 *)&priv->pcmd_buf[0];
+-	mutex_lock(&priv->fwcmd_mutex);
+-	memset(pcmd, 0x00, sizeof(*pcmd));
+-	pcmd->cmd_hdr.cmd = cpu_to_le16(cmd);
+-	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
+-	if (mwl_hif_exec_cmd(hw, cmd)) {
+-		mutex_unlock(&priv->fwcmd_mutex);
+-		return -EIO;
+-	}
+-	if (pcmd->cmd_hdr.result != 0) {
+-		mutex_unlock(&priv->fwcmd_mutex);
+-		return -EINVAL;
+-	}
+-	if (pcmd->status)
+-		*fw_region_code = (pcmd->status == 1) ? 0 : pcmd->status;
+-	else
+-		*fw_region_code = le32_to_cpu(pcmd->fw_region_code);
+-	mutex_unlock(&priv->fwcmd_mutex);
+-	return 0;
+ int mwl_fwcmd_get_pwr_tbl_sc4(struct ieee80211_hw *hw,
+ 			      struct mwl_device_pwr_tbl *device_ch_pwrtbl,
+ 			      u8 *region_code,
+--- a/hif/fwcmd.h
++++ b/hif/fwcmd.h
+@@ -253,9 +253,6 @@
+ int mwl_fwcmd_newdp_dmathread_start(struct ieee80211_hw *hw);
+-int mwl_fwcmd_get_fw_region_code_sc4(struct ieee80211_hw *hw,
+-				     u32 *fw_region_code);
+ int mwl_fwcmd_get_pwr_tbl_sc4(struct ieee80211_hw *hw,
+ 			      struct mwl_device_pwr_tbl *device_ch_pwrtbl,
+ 			      u8 *region_code,
+--- a/hif/hostcmd.h
++++ b/hif/hostcmd.h
+@@ -73,7 +73,6 @@
+ #define HOSTCMD_CMD_GET_DEVICE_PWR_TBL          0x116B
+ #define HOSTCMD_CMD_SET_RATE_DROP               0x1172
+-#define HOSTCMD_CMD_GET_FW_REGION_CODE_SC4      0x118A
+ #define HOSTCMD_CMD_GET_DEVICE_PWR_TBL_SC4      0x118B
+ #define HOSTCMD_CMD_QUIET_MODE                  0x1201
+ #define HOSTCMD_CMD_CORE_DUMP_DIAG_MODE         0x1202
+@@ -1110,13 +1109,6 @@
+ 	struct hostcmd_header cmd_hdr;
+ } __packed;
+-struct hostcmd_cmd_get_fw_region_code_sc4 {
+-	struct hostcmd_header cmd_hdr;
+-	__le32 status; /* 0 = Found, 1 = Error */
+-	__le32 fw_region_code;
+-} __packed;
+ #define HAL_TRPC_ID_MAX_SC4        32
+ #define MAX_GROUP_PER_CHANNEL_5G   39
Index: mwlwifi-2019-03-02-31d93860/hif/fwcmd.c
--- mwlwifi-2019-03-02-31d93860.orig/hif/fwcmd.c
+++ mwlwifi-2019-03-02-31d93860/hif/fwcmd.c
@@ -1141,6 +1141,9 @@ int mwl_fwcmd_max_tx_power(struct ieee80
 	int i, tmp;
 	int rc = 0;
+	// do not set tx power
+	return rc;
 	if ((priv->chip_type != MWL8997) && (priv->forbidden_setting))
 		return rc;
@@ -1188,6 +1191,13 @@ int mwl_fwcmd_max_tx_power(struct ieee80
 			sub_ch = EXT_CH_BELOW_CTRL_CH;
+	case NL80211_CHAN_WIDTH_160:
+		width = CH_160_MHZ_WIDTH;
+		if (conf->chandef.center_freq1 > channel->center_freq)
+			sub_ch = EXT_CH_ABOVE_CTRL_CH;
+		else
+			sub_ch = EXT_CH_BELOW_CTRL_CH;
+		break;
 		return -EINVAL;
@@ -1250,6 +1260,9 @@ int mwl_fwcmd_tx_power(struct ieee80211_
 	int i, tmp;
 	int rc = 0;
+	// do not set tx power
+	return rc;
 	if ((priv->chip_type != MWL8997) && (priv->forbidden_setting))
 		return rc;
@@ -1297,6 +1310,13 @@ int mwl_fwcmd_tx_power(struct ieee80211_
 			sub_ch = EXT_CH_BELOW_CTRL_CH;
+	case NL80211_CHAN_WIDTH_160:
+		width = CH_160_MHZ_WIDTH;
+		if (conf->chandef.center_freq1 > channel->center_freq)
+			sub_ch = EXT_CH_ABOVE_CTRL_CH;
+		else
+			sub_ch = EXT_CH_BELOW_CTRL_CH;
+		break;
 		return -EINVAL;
@@ -3163,6 +3183,10 @@ int mwl_fwcmd_set_cdd(struct ieee80211_h
 	struct mwl_priv *priv = hw->priv;
 	struct hostcmd_cmd_set_cdd *pcmd;
+	// force-enable Cyclic delay diversity
+	//
+	priv->cdd = 1;
 	pcmd = (struct hostcmd_cmd_set_cdd *)&priv->pcmd_buf[0];
@@ -3438,6 +3462,9 @@ int mwl_fwcmd_get_fw_region_code_sc4(str
 	struct hostcmd_cmd_get_fw_region_code_sc4 *pcmd;
 	u16 cmd;
+	// do not load the firmware region
+	return -EIO;
 	pcmd = (struct hostcmd_cmd_get_fw_region_code_sc4 *)&priv->pcmd_buf[0];
@@ -3478,6 +3505,9 @@ int mwl_fwcmd_get_pwr_tbl_sc4(struct iee
 	int status;
 	u16 cmd;
+	// do not load the regulatory power table
+	return -EIO;
 	pcmd = (struct hostcmd_cmd_get_device_pwr_tbl_sc4 *)&priv->pcmd_buf[0];
Index: backports-5.4-rc8-1/drivers/net/wireless/marvell/mwifiex/cfg80211.c
--- backports-5.4-rc8-1.orig/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ backports-5.4-rc8-1/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4439,7 +4439,8 @@ int mwifiex_register_cfg80211(struct mwi
 				country_code =
-				if (country_code &&
+				// do not load the firmware region
+				if (0 && country_code &&
 				    regulatory_hint(wiphy, country_code))
 					mwifiex_dbg(priv->adapter, ERROR,
 						    "regulatory_hint() failed\n");

mostly applicable to those in the EU attempting to get client devices in agreement about the region code. No idea if they even apply any longer.

BLOBs are common, one for 88W8864, one for 88W8964.

This makes a lot more sense - that the blobs are common (else it would be a huge hassle managing them), and that the power table is loaded either from DTS (i.e. software which can hopefully be updated to match one's country regulations) or in EEPROM. It would be interesting to know if it is truly EEPROM for caiman v2, shelly v2, rango and venom, or if it is OTP. If it is EEPROM, then in theory it should be changeable, but if it OTP, then it would indeed be a hardware limitation.

Shame on me. I think, I was not yet used to the Wiki structure. On the WRT32X device page, I actually missed to check the link to the AC family series, which has further WiFi details, which then has a link to the WiFi driver GIT page.
I think, a note like "Please also consider the ac_series Wiki page for further technical details related to this device. This page only contains device-specific technical content" might have been helpful instead of the "this device is part of the ac series" link (that did not really trigger me to consider clicking the current link).

The following could be added to the WiFi chapter of the wrt_ac_series page, that would be helpful for non-experts like me:

  • The 5GHz LED is always inactive due to deficits in the open source WiFi driver implementation (it's not an OpenWRT bug, its a missing driver feature)
  • The country code is hard-coded in the WiFi chip of radio 0 and 1 and cannot be changed. The current country code can neither be read or set via LUCI. Changing the country code in LUCI has no effect or may have negative side effect. To read the country code use SSH command line "iw reg show". Any device for Europe has country hard-coded to "FR", even if you use it in a different European country. Exceptions to this country code limitation are WRT1900* V1 and a few regional versions of some other devices (it is not documented which country specific device variants are shipped non-locked)
  • the country code of the 3rd radio of 3200 and 32X can be change via software. Though this has to be done on command line, not via LUCI:
    echo "mwifiex reg_alpha2=FR" > /etc/modules.d/mwifiex
  • 160MhZ channel width of radio 0 can only be activated on channels >= 100
  • the 3rd radio has limited throughput due to a 1x1 MIMO antenna (WiFi of radio 0 is 3x3 MIMO). The 3rd radio cannot use some channel / width combinations, the radio will not startup with some settings.
  • check the OpenWRT log via SSH command line ("logread" command), if any of the radios does not startup, to identify conflicting WiFi parameter combinations
  • A petition exists, to motivate Linksys to better support the WiFi driver. Sign it, to increase the chance to improve the currently sub-par open source WiFi driver quality:

Yet I feel that I do not yet understand the issue with the 3rd radio:

  • What are the actual side effects of activating the 3rd radio? - does it cause reduced transmit power of radio 0 and 1? issues with proper channel selection?
  • You recommend uninstalling the 3rd radio driver. What different effect does "uninstalling driver" have compared to "not enabling 3rd WiFi" or "setting a correct custom country code on 3rd WiFi"?
  • If I want to activate the 3rd radio, i need to use commandline "iw" when wanting to change the country code of the 3rd WiFi. But what country code should then be used? 00? 98? the same as the hard-coded country code of radio 0/1? Or leave the OpenWRT factory default value? Is there anything else I should consider when activating the 3rd radio?

The country for radio 0 and radio 1 cannot be changed, and the country for radio 2 cannot be changed using uci/LuCi. If you leave radio 2 active, and configured to a different country, then radio 0 and radio 1 will only work on channels and power levels available on any country.

I don't remember this being true... 5GHz was one of the LEDs which was used so frequently on my device that it started to fade in intensity (another common and ridiculous fault with these devices).

(Update) I think you are right: LEDs are there, but probably worn out. Just had some back and forth booting and it seems difficult to say at first depending on light situation.

...fresh news that I have not yet seen mentioned here: Yet another directional change for Linksys:

Fortinet has announced to invest 75Mio$ into Linksys (Fortinet stands for locked down appliances, so nothing really good to expect):

So, Linksys is going to create a new line if routers, with some Fortinet client pre-installed, similar to Cisco Meraki routers. A company can distribute those routers to employees, create a secure connection from their homes, and controll them remotely.

I do not think that is going to have any impact on OpenWrt at all.