Sunday, 16 November 2014

Configure your WR703n with a switch (or two)


The TP-Link TL-WR703n is a versatile piece of hardware and very handy to have with you when you need WIFI connectivity... The problem is that you need to configure it to fit your needs every time.

This mod aims to re-configure it by the flip of a switch (or two):

  • Choose between WIFI Access point or client.
  • Choose between bridged or NAT/DHCP for WIFI & wired networks.
Here are some use cases:
  • Be at a friend's or hotel and use your home wifi creadential to connect to a wired network
  • Connect a wired device to your network
Although this is absolutely not necessary, I'm performing this mod on my already previously modded wr703n router with 16MB of ROM (handy to install packages without using exroot) and 64MB of RAM which is much more comfortable and a serial console mod to get easy access to the serial terminal with a FTDI adapter or use it as an arduino wifi 'shield'.

This mod however assumes you're using OpenWRT on your TL-WR703N. Please refer to this other hack if you want to see how to open the wr703n.

Image source: OpenWRT wiki

Finding two available GPIO 'pins' in the TL-WR703N

According to the specs found on OpenWrt's wiki, we can reuse GPIO 7 and 29, located on R15 and R17 (see image on the right).

Connect these GPIO to 3V3 (top right on the pic) and the GPIO will read '1', disconnect it and it will read '0'.

Wiring GPIO 7 and 29 to a dip switch

The difficult part of this step is not understanding how it is done but rather doing it... You need to solder three wires:
  • 3V3 (on the top-right of the picture)
  • GPIO 7 (connect it to the lower side of the resistor on the picture)
  • GPIO 29 (same)
Soldering in these place is quite tricky as components are really small. After testing your connections are OK, remember to secure them with hot glue, epoxy or whatever you fancy.

I connected these three wires to a (female) pin header to make connections/deconnections to the switch easier:
GPIOs + 3V3 connected to a 3P female pin header

I then drilled a square hole in the top cover: used a drill + file to make it square, (instant) glued the switch in the hole and glued a 3P male pin header next to it to connect the GPIOs (and 3V3) to it:

Male pin header glued under the top cover
and connected to the switch
Wiring is as follows (for :

  • Pin 1 (left): 3V3 and is connected to both switches
  • Pin 2 (middle): GPIO 7, and is connected to switch 1 (other side, obviously)
  • Pin 2 (middle): GPIO 29, and is connected to switch 2

Your next step is to connect the pins headers together and test.
Debugging the switches with FTDI adapter

Test your connections

Testing should be done before glueing, securing your connections (especially for those securing them with epoxy).

Connect to your router's terminal. Use SSH or the serial console (see my FTDI adapter post) to connect on root on the router.

Export both pins
echo 7 > /sys/class/gpio/export
echo 29 > /sys/class/gpio/export

Set both pins as input
echo in > /sys/class/gpio/gpio7/direction
echo in > /sys/class/gpio/gpio29/direction

You can then read the value of both pins with these commands:
cat /sys/class/gpio/gpio7/value
cat /sys/class/gpio/gpio29/value
If it returns 1, it means the GPIO pin is connected to 3V3, it will return 0 otherwise.

Working ... I can close it now!

A script to switch between configuations at boot time

Why at boot time and not continuously?
If you want to continuously monitor pins, you have to either use hotplug (you need compile your own OpenWRT then) or write a script continuously checking the pin (which is CPU consuming). Since I can afford to reset the router when switching configurations, I'm fine with loading the right configuration at boot time. More info here.

Separate configuration folders

/etc/config contains the router's configuration and I decided to make four copies of it (one for each switch combination of positions). These are named /etc/config.XX0 where XX corresponds to the switches positions.

I first created a copy of the origninal folder so I would always have a backup/reference folder, should anything happen:
Create original config file folder
cp -r /etc/config /etc/config.orig

Option 1: Now you can create your alternate configuration folders the same way:
cp -r /etc/config /etc/config.00
cp -r /etc/config /etc/config.01
cp -r /etc/config /etc/config.10
cp -r /etc/config /etc/config.11

Option 2: Making your configuration fully independent from each other, or you can use simlinks to share your configuration files:
mkdir /etc/config.01
for I in $(ls /etc/config.orig/*) ; do ln -sf $I /etc/config.01/$(basename $I); done

but copy files you intent to change:
cp /etc/config.orig/wireless /etc/config.01/
cp /etc/config.orig/network /etc/config.01/
cp /etc/config.orig/firewall /etc/config.01/

Remeber to change the list above to match your needs. All other configuration files will remain in common.

If you want to manually switch between configuration you can use the following commans:
umount /etc/config   #to avoid mounting it multiple times
mount --bind /etc/config.01/ /etc/config
/etc/init.d/network restart

Loading the configuration at boot time

Create /etc/init.d/buttons and paste the following script in it:
#!/bin/sh /etc/rc.common
START=19
start() {
        /bin/umount /etc/config 2>/dev/null
        echo in > /sys/class/gpio/gpio7/direction 2> /dev/null
        echo in > /sys/class/gpio/gpio29/direction 2> /dev/null
        echo 7 > /sys/class/gpio/export 2> /dev/null
        echo 29 > /sys/class/gpio/export 2> /dev/null
        if [ "$(cat /sys/class/gpio/gpio7/value)" == "1" ] ; then
                if [ "$(cat /sys/class/gpio/gpio29/value)" == "1" ] ; then
                        ## BUTTONS: 11
                        ## WIFI:   AP ESSID=MnMs
                        ## WIRED:  NAT/DHCP
                        echo "BUTTONS: 11" > /tmp/buttons
                        /bin/mount -o bind /etc/config.01 /etc/config
                else
                        ## BUTTONS: 10
                        ## WIFI:   AP ESSID=MnMs
                        ## WIRED:  BRIDGED (to wifi)
                        echo "BUTTONS: 10" > /tmp/buttons
                        /bin/mount -o bind /etc/config.01 /etc/config
                fi
        else
                if [ "$(cat /sys/class/gpio/gpio29/value)" = "1" ] ; then
                        ## BUTTONS: 01
                        ## WIFI:   TBD
                        ## WIRED:  TBD
                        echo "BUTTONS: 01" > /tmp/buttons
                        /bin/mount -o bind /etc/config.01 /etc/config
                else
                        ## BUTTONS: 00
                        ## WIFI:   CLIENT ESSID=MnMs
                        ## WIRED:  NAT/DHCP
                        echo "BUTTONS: 00" > /tmp/buttons
                        /bin/mount -o bind /etc/config.00 /etc/config
                fi
        fi
}


You can now give it execution rights (so the system can execute it):
Using the switches to select the configuration before booting
chmod +x /etc/init.d/buttons

And set it to be run at boot time:
/etc/init.d/buttons enable

You're done !

Note if for some reason the router does not run it at startup, you can always edit /etc/init.d/network and add the following command at the begining of its "start" section:
/etc/init.d/buttons start