Bridging a Wireless Access Point

I’ve got a Linksys WRT3200ACM WiFi router. Of course it runs OpenWRT, but it should bridge the associated WiFi clients to my LAN, not NAT them.

It’s kind of bogus to have a WiFi router use NAT to front clients to the network. If you’ve got a couple of WiFi routers, nothing is on the same broadcast segment, and if you’ve got a cabled printer it’s impossible for your WiFi clients to print to it. If you’ve got one of those bullshit “all-in-one” printer-scanner-copiers that do nothing well and have 4 pushbuttons and an LED interface, only the clients associated to the same WiFi router can use it. That’s a bad situation.

I want my router to bridge the DHCP service from my server, so that everything is routeable one to another.


I believe I bought the WRT3200ACM in 2018 or 2019 because my WiFi routers at the time had trouble covering the house I used to live in. Linksys’ page indicates that they started selling the router in 2016. It’s old tech at this point, perfect for a homelab.


The WRT3200ACM had been running OpenWRT 19.something for a while, so I upgraded to 23.05.0. Upgrading OpenWRT always feels risky, maybe because there’s no “console” to see what might have gone wrong. Flashing the initial OpenWRT image over the factory image is always downright weird, because Linksys does dumb things and doesn’t document them.

OpenWRT v19 didn’t help make the upgrade to 23.05.0 easy. It uses the dropbear ssh daemon, and my more-or-less up-to-date Arch Linux laptop didn’t want to connect to dropbear.

I had to tell my laptop’s ssh to use ssh-rsa cipher if necessary. The exact error message was:

Unable to negotiate with 172.24.0.3 port 22: no matching host key type found. Their offer: ssh-rsa

The message is uninformative, but it’s unique enough that there’s no information camouflage around it.

laptop$ ssh -oHostKeyAlgorithms=+ssh-rsa root@172.16.0.3
root@OpenWrt:~# cd /tmp 
root@OpenWrt:~# opkg update 
root@OpenWrt:~# opkg install wget 
root@OpenWrt:~# wget https://downloads.openwrt.org/releases/23.05.3/targets/mvebu/cortexa9/openwrt-23.05.3-mvebu-cortexa9-linksys_wrt3200acm-squashfs-sysupgrade.bin`
root@OpenWrt:~# sysupgrade -n -v openwrt-23.05.3-mvebu-cortexa9-linksys_wrt3200acm-squashfs-sysupgrade.bin

OpenWRT’s sysupgrade command did work, but there’s about 3 minutes of terror where all you can do is watch the LEDs on the front of the router blink a few times.

You’ll note the “172.16.0.3” address above. I had been running the WRT3200ACM in bridging mode all along. I set up my laptop to run a DHCP server on its ethernet port, and gave that ethernet port the address 172.16.0.1/24.

Setting up the ethernet port as a temporary server isn’t too hard, the key is to get dhcpcd, the client DHCP daemon, to ignore the ethernet port, while still doing DHCP for the wireless network device.

The key is to add a line in /etc/dhcpcd.conf:

denyinterfaces enp0s31f6

enp0s31f6 is the very intuitive name of my laptop’s ethernet socket. Another laptop, another computer, will almost certainly have a different name.

Then restart dhcpcd. You need to undo this config file change and restart dhcpcd again afterwards, otherwise the next time you plug in a CAT-5 cable, you’ll be vexed about why you don’t get an IP address.


The default OpenWRT wireless config is without any encryption. Using the LuCi point-n-click web interface to set encryption failed. I think that my browser (Firefox) wouldn’t re-connect to the WRT3200ACM because the browser used an http:// URL to reconnect after 90 seconds. Adding encryption meant that the next access would have to be via https://.

Luckily, OpenWRT really is Linux, so after ssh-ing to the router, I set up encryption via the command line:

root@OpenWrt:~# uci set wireless.@wifi-iface[0].encryption=psk2
root@OpenWrt:~# uci set wireless.@wifi-iface[0].key="SexistPig"
root@OpenWrt:~# uci set wireless.@wifi-iface[1].encryption=psk2
root@OpenWrt:~# uci set wireless.@wifi-iface[1].key="SexistPig"
root@OpenWrt:~# uci commit wireless
root@OpenWrt:~# wifi
'radio2' is disabled
Connection to 192.168.1.1 closed.

That’s straight out of the OpenWRT wiki entry. I connected to the WRT3200ACM via wireless, that’s why “Connection to 192.168.1.1 closed” appears.

Note for OpenWRT 23.05.3

You’ve got to set the radios’ country code and explicity set “disabled” to false to get the radios to work:

root@OpenWrt:~# uci set wireless.radio0.country='US'
root@OpenWrt:~# uci set wireless.radio1.country='US'
root@OpenWrt:~# uci set wireless.radio1.disabled='0'
root@OpenWrt:~# uci set wireless.radio0.disabled='0'
root@OpenWrt:~# uci commit wireless
root@OpenWrt:~# wifi reload

At this point, I had the WRT3200ACM back on my LAN. It was acting like a standard consumer WAP, giving out 192.168.1.0/24 addresses to clients connecting via wireless, and getting a 10.0.0.0/24 address for its own “Internet” CAT-5 cabled port from my server.

UPDATE 2024-04-20

In my efforts to get the Kea DHCP server running, I ended up upgrading to OpenWRT 23.05.3 in an effort to get reliable DHCP OFFER and ACK packets out to clients.

I did not follow the “dumb wireless access” point the second time around.

See my post on kea DHCP daemon for more details, and don’t do anything more from this post.

Setting up bridging worked as below, but apparently OpenWRT 23.05.0 had some problems. The kea DHCP daemon post has a simpler way to do bridging.

UPDATE 2024-04-20 - WRONG FROM HERE DOWN

I decided to follow the OpenWRT wiki entry for a dumb wireless access point. It seemed simpler than the “bridging” wiki entry.

I followed the instructions for Switch and Dedicated WAN devices post 21.01

I edited /etc/config/network to this:

config device                                  
        option name 'br-lan'                   
        option type 'bridge'                   
        list ports 'lan1'                      
        list ports 'lan2'                      
        list ports 'lan3'                      
        list ports 'lan4'                      
                            
config interface 'lan'      
        option device 'br-lan'
        option proto 'static' 
        option ipaddr '10.0.0.145'
        option netmask '255.255.255.0'
        option ip6assign '60'         

Essentially, I modified the config interface 'lan' section, and commented out the config device section for wan.

I didn’t change any of /etc/config/wireless - it seemed to already fit the instructions in the wiki entry.

Additionally, I turned off some other servers:

/etc/init.d/dnsmasq disable
/etc/init.d/dnsmasq stop

/etc/init.d/odhcpd disable
/etc/init.d/odhcpd stop

/etc/init.d/firewall disable
/etc/init.d/firewall stop

Then did this magic:

/etc/init.d/network reload

I ended up rebooting the router, since it didn’t seem to bridge everything right away.

I had to unplug the CAT-5 cable from the WAN, “Internet” port, and plug it into one of the 4 “LAN” ports on the back of the router.

At first, I didn’t think that my main server was doing DHCP, but after ate dinner and took a shower, it seems to be working.

Chronology of steps

  1. Set up laptop’s ethernet cable port as a “server”
    1. laptop$ /usr/bin/ip link set dev $INTERNAL up
    2. laptop$ /usr/bin/ip addr add 172.16.0.1/24 dev $INTERNAL
    3. laptop$ sleep 10
    4. laptop$ modprobe -v iptable_nat
    5. laptop$ echo 1 > /proc/sys/net/ipv4/ip_forward
    6. laptop$ /sbin/iptables -t nat -A POSTROUTING -o $EXTERNAL -j MASQUERADE
    7. laptop$ /sbin/iptables -A FORWARD -i $EXTERNAL -o $INTERNAL -m state --state RELATED,ESTABLISHED -j ACCEPT
    8. laptop$ /sbin/iptables -A FORWARD -i $INTERNAL -o $EXTERNAL -j ACCEPT
    9. configure and run a DHCP server on ethernet port
  2. Plug in a cable between laptop’s ethernet port and one of WRT3200ACM’s “LAN” ports
  3. Turn on WRT3200ACM and wait for reboot and all the DHCP back and forth
  4. laptop$ ssh -oHostKeyAlgorithms=+ssh-rsa root@172.16.0.3 to get to the OpenWRT 19.x command line
  5. root@OpenWrt:~# cd /tmp && opkg update && opkg install wget && wget https://downloads.openwrt.org/releases/23.05.3/targets/mvebu/cortexa9/openwrt-23.05.3-mvebu-cortexa9-linksys_wrt3200acm-squashfs-sysupgrade.bin
  6. root@OpenWrt:~# sysupgrade -n -v openwrt-23.05.3-mvebu-cortexa9-linksys_wrt3200acm-squashfs-sysupgrade.bin
  7. Change the WRT3200ACM end of the CAT-5 cable from step 3 to the “Internet” socket.
  8. Kill the dhcpd on the laptop, reset its ethernet port to use DHCP to acquire an IP address and routing info.
  9. laptop$ ssh root@192.168.1.1, it does not have a password.
  10. root@OpenWrt:~# opkg remove kmod-mwifiex-sdio; reboot
  11. `ssh back into the laptop, set a root password
  12. Edit /etc/config/wireless to add a clever wireless name to the config wifi-iface 'default_radio0' and config wifi-iface 'default_radio1', at the option ssid lines.
  13. Set encryption and add a WiFi password (“private shared key”) via uci commands.
  14. Follow the “dumb apd” OpenWRT recipe to make it do a bridge.