OpenWRT White Russian + VLANs


This is not intended as a guide on how to modify your WRT54G. It merely documents my experiences. If you choose to modify your router similar to how I have, realize that improper changes can turn your router into an expensive paperweight. Make sure your wireless settings are set so that you can connect in to your router wirelessly. If you screw up the VLAN or wired network configurations, that’s the only way you’ll be able to get in. Also, make sure your “boot_wait” nvram variable is set to “on”. Without this setting, it’s a pain in the ass (or impossible) to rescue a comatose router.

You’ve been warned.


I bought a few WRT54GLs with the sole intent of putting linux on them and exploring the possibilities of what could be done with them. After some reading, I discovered that all of the internal differentiation between the Internet and Local sides of the router was done with VLANs internally, and that each switch port on the router could be individually configured to use certain VLANs just as more advanced switches can.

First Attempt

As an exercise, I decided to take one of them and try to mimic the network setup of my gateway machine. It currently has four physical network interfaces – one each for three private subnets, and one for connecting to the internet. I wanted to set up four seperate VLANs in the WRT54GL to mimic the four physical interfaces, and if possible, use the same firewall ruleset I have set up on the gateway to enforce the same rules.

Once I figured out how to manipulate the networking scripts that OpenWRT provides, the process wasn’t too difficult. By default, there is one network configuration for the local subnet, called “lan”. I wanted three local subnets, so I duplicated these settings three times, can called them “mylan0”, “mylan1”, and “mylan2”. All of the configuration data is stored in nvram, then retrieved by the init scripts and put into effect when the device boots. I had to change the init scripts to tell it which interfaces to bring up – my three “mylanX” configurations instead of the “lan” configuration.

The second part of the modification involved allocating three different VLANs to serve as the interfaces that the “mylanX” configurations would ‘attach’ themselves to. This was a bit confusing at first, but once I figured how it was done, it wasn’t so bad. It involves setting more nvram parameters to control how the switch ports are configured at boot time. There must be a nvram line set for each VLAN to be used, and in the following format.

vlan11ports="2 0t* 5t*"

This states that port 2 will send and recieve packets from VLAN 11 in an unencapsulated manner, and ports 0 and 5 will trunk VLAN11 packets, which means they’ll be sent across the line in an encapsulated format. This allows for any normal device that should reside on VLAN11 to be plugged into port 2, while other devices capable of utilizing 802.1q VLAN encapsulation can be plugged into port 0 (port 5 is the physical connection to the CPU). Trunked ports can contain any subset or all of the VLANs configured in the device, so it’s possible to carry traffic from multiple VLANs over the same line between devices.

With this in mind, I set up my WRT54GL with something similar to the following…

vlan0ports="3 0t* 5t*"
vlan1ports="2 0t* 5t*"
vlan2ports="1 0t* 5t*"
vlan9ports="4 5"

This allowed for the ‘internet’ port to still function as such, but the three other VLANs would have their own ports (1-3 externally, labeled as 3-1, respectively), while the remaining port (externally labeled as 4, internally as port 0) would be a trunk port that carried all internal VLANs. This would allow me to connect that port to a VLAN-aware switch, and pick and choose what ports were connected to which VLAN.

In this setup, the wireless interface (eth1), was totally seperate to do as it pleased. I never used this for anything really, so I didn’t use the wireless interface for anything except sniffing network traffic using kismet_drone.

Current Setup

After a few months of not really messing around with the routers, I was motivated to start playing with them again. I picked up a few Cisco 2424XL switches from the MSU Surplus Store, which have the VLAN capability I was planning for with the inital networking setup. On a whim, I decided to see if the WRT54GL’s were capable of serving as access points and kismet drones at the same time. I was mildly suprised that they could.

This gave me the inclination to dink with them further. I decided to convert both of them into access points with a similar networking setup to what I had before. This involved figuring out how to connect the wireless interface to one of the VLAN interfaces. That wasn’t terribly difficult because the default setup just uses standard linux bridging to connect the wireless interface to the vlan interface. The larger difficulty was figuring out how OpenWRT’s init scripts brought the interfaces online at boot time.

After comparing my highly modified OpenWRT install to my other vanilla OpenWRT install, I was able to figure out how they were doing things. The scripts looked for the [configname]_ifname variable in nvram, and if it contained what appeared to be a bridge name (brX), it would check the [configname]_ifnames setting to figure out what interfaces should be bridged together. (The following is an example from my current configuration, not the vanilla OpenWRT setup)

mylan1_ifnames="eth1 vlan11"

With that hurdle out of the way, I was able to get things working pretty easily. I modified the VLAN port layouts from my first attempt, since there would be no need for an internet port. I set the internet port as another trunking port. This allows me to stack the WRT54GLs in close proxmity, connected to each other via the trunk ports, and connected to one of the Cisco switches using one ethernet cable instead of two.

Another hurdle I ran into was an incompatibility with the way I chose to set up my VLANs and how OpenWRT handled things in its init scripts. Since I’m kind of anal and like visual associations whenever I can manage, I decided to use VLANs 10-12 to correspond to my three subnets (192.168.0.x, 192.168.1.x, and 192.168.2.x) so that the last number of the VLAN would correspond to the third octet in the subnet. Yah, I know. Anal. However, a bug in OpenWRTs logic only allowed for bringing up single-digit VLAN numbers even though the internal switch could handle VLANs 0-15. I found the code responsible in /etc/, on line 10 specifically.

    [ "${1%%[0-9]}" = "vlan" ] && (

I’m not sure what this syntax does exactly, but it seems to say “take the variable $1 and pull off a single character that matches 0-9, and if you’re left with ‘vlan’, then we match and the logic proceeds”. So, I tried to add another 0-9 at the end of that statement, and my problems went away.

    [ "${1%%[0-9][0-9]}" = "vlan" ] && (

This also breaks single-digit VLANs, but since I don’t have any configured in my switch, it doesn’t matter much to me.

With the hurdles out of the way, I was able to configure everything to work properly on boot-up. I used the following script to set up all of my networking configuration.

nvram set lan_ifnames="vlan0 eth1 eth2 eth3"
nvram set vlan10hwname=et0
nvram set vlan10ports="3 0t* 4t* 5t*"
nvram set vlan11hwname=et0
nvram set vlan11ports="2 0t* 4t* 5t*"
nvram set vlan12hwname=et0
nvram set vlan12ports="1 0t* 4t* 5t*"

nvram set mylan0_gateway=
nvram set mylan0_domain=
nvram set mylan0_route=
nvram set mylan0_netmask=
nvram set mylan0_lease=86400
nvram set mylan0_stp=0
nvram set mylan0_dhcp=0
nvram set mylan0_hwaddr=
nvram set mylan0_ifnames=vlan10
nvram set mylan0_dns=
nvram set mylan0_proto=static
nvram set mylan0_ipaddr=
nvram set mylan0_ifname=vlan10
nvram set mylan0_wins=
nvram set mylan0_hwnames=
nvram set mylan1_gateway=
nvram set mylan1_domain=
nvram set mylan1_route=
nvram set mylan1_netmask=
nvram set mylan1_lease=86400
nvram set mylan1_stp=0
nvram set mylan1_dhcp=0
nvram set mylan1_hwaddr=
nvram set mylan1_ifnames="eth1 vlan11"
nvram set mylan1_dns=
nvram set mylan1_proto=static
nvram set mylan1_ipaddr=
nvram set mylan1_ifname=br0
nvram set mylan1_wins=
nvram set mylan1_hwnames=
nvram set mylan2_gateway=
nvram set mylan2_domain=
nvram set mylan2_route=
nvram set mylan2_netmask=
nvram set mylan2_lease=86400
nvram set mylan2_stp=0
nvram set mylan2_dhcp=0
nvram set mylan2_hwaddr=
nvram set mylan2_ifnames=vlan12
nvram set mylan2_dns=
nvram set mylan2_proto=static
nvram set mylan2_ipaddr=
nvram set mylan2_ifname=vlan12
nvram set mylan2_wins=
nvram set mylan2_hwnames=

nvram unset vlan0hwname
nvram unset vlan0ports
nvram unset vlan1hwname
nvram unset vlan1ports
nvram unset vlan2hwname
nvram unset vlan2ports
nvram unset vlan3hwnam

The last section removed the VLAN configurations provided in the vanilla OpenWRT install and my first attempt at VLANs. I don’t know if not removing the VLAN configurations was required or not, but I wanted to keep things as clean as possible.

I also needed to modify the network init script to bring up my “mylanX” interfaces instead of the default “lan” interfaces. My current init script is as follows…

case "$1" in
   #ifup lan

   ifup mylan0
   ifup mylan1
   ifup mylan2

   #ifup wan
   ifup wifi
   wifi up

   for route in $(nvram get static_route); do {
     eval "set $(echo $route | sed 's/:/ /g')"
     $DEBUG route add -net $1 netmask $2 gw $3 metric $4 dev $5
   } done

If memory serves, that was all there was to it. I’ll update things if I remember anything else.

Helpful Links

Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>