LEDE mass deployment25. Sep '17


In this article a howto is outlined for mass deployment of LEDE on commodity hardware:

  • TP-Link WDR3600 - 802.11an, 70€

  • TP-Link WDR4300 - 802.11an, 70€

  • TP-Link Archer C7 - 802.11ac, cost 100€

  • Comfast E380AC - 802.11ac, 48V PoE, cost 120€

All of those devices use Atheros chipsets, which means you get multiple SSID support and good compatibility with various client devices.

With WDR3600/4300 you get about 150Mbps actual throughput on 5Ghz band and 300-400Mbps with Comfast and Archer. Note that some mobile devices may be utilize only half of the bandwidth because of having only 1 receive stream available.

In noisy environment some of the devices drop to 2.4GHz band giving you about 70Mbps throughput there. 5GHz and 2.4GHz bands in total can serve 30 iPads for sure.

Image customization

In order to include custom configuration within the flashable image LEDE image builder can be used.

First fetch LEDE image builder:

wget http://downloads.lede-project.org/releases/17.01.4/targets/ar71xx/generic/lede-imagebuilder-17.01.4-ar71xx-generic.Linux-x86_64.tar.xz
tar xvf lede-imagebuilder-17.01.4-ar71xx-generic.Linux-x86_64.tar.xz
cd lede-imagebuilder-17.01.4-ar71xx-generic.Linux-x86_64/
mkdir -p overlay/etc/uci-default

To set colorful command prompt and window title in terminal emulator drop following to overlay/etc/profile:

[ -f /etc/banner ] && cat /etc/banner
[ -e /tmp/.failsafe ] && cat /etc/banner.failsafe

export PATH=/usr/bin:/usr/sbin:/bin:/sbin
export HOME=$(grep -e "^${USER:-root}:" /etc/passwd | cut -d ":" -f 6)
export HOME=${HOME:-/root}
export PS1='\u@\h:\w\$ '

[ -z "$KSH_VERSION" -o \! -s /etc/mkshrc ] || . /etc/mkshrc
[ -x /bin/more ] || alias more=less
[ -x /usr/bin/vim ] && alias vi=vim || alias vim=vi
[ -x /usr/bin/arp ] || arp() { cat /proc/net/arp; }
[ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; }

HOSTNAME=$(uci get system.@system[0].hostname)
DOMAIN=$(uci -q get dhcp.@dnsmasq[0].domain)

if [ $? -eq 0 ]; then

export PS1='\[\033[01;31m\]$FQDN\[\033[01;34m\] \W #\[\033[00m\] '
case "$TERM" in
        echo -ne "\033]0;${USER}@${FQDN}:${PWD}\007"

Generate unique hostname using overlay/etc/uci-defaults/40-hostname:

MODEL=$(cat /etc/board.json | jsonfilter -e '@["model"]["id"]')

# Hostname prefix
case $MODEL in
    tl-*|archer-*)  VENDOR=tplink ;;
    cf-*) VENDOR=comfast ;;
    *) VENDOR=ap ;;

# Network interface with relevant MAC address
case $MODEL in
    tl-wdr*) NIC=wlan1 ;;
    archer-*)  NIC=eth1 ;;
    cf-e380ac-v2) NIC=eth0 ;;
    *) NIC=wlan0 ;;

HOSTNAME=$VENDOR-$(cat /sys/class/net/$NIC/address | cut -d : -f 4- | sed -e 's/://g')
uci set system.@system[0].hostname=$HOSTNAME
uci set network.lan.hostname=$HOSTNAME

Reconfigure device to work as access point overlay/etc/uci-defaults/50-access-point:

# Disable DHCP servers
/etc/init.d/odhcpd disable
/etc/init.d/dnsmasq disable

# Remove firewall rules since AP bridges ethernet to wireless anyway
uci delete firewall.@zone[1]
uci delete firewall.@zone[0]
uci delete firewall.@forwarding[0]
for j in $(seq 0 10); do uci delete firewall.@rule[0]; done

# Remove WAN interface
uci delete network.wan
uci delete network.wan6

# Reconfigure DHCP client for bridge over LAN and WAN ports
uci delete network.lan.ipaddr
uci delete network.lan.netmask
uci delete network.lan.ip6assign
uci delete network.globals.ula_prefix
uci delete network.@switch_vlan[1]
uci delete dhcp.@dnsmasq[0].domain
uci set network.lan.proto=dhcp
uci set network.lan.ipv6=0
uci set network.lan.ifname='eth0'
uci set network.lan.stp=1

# Radio ordering differs among models
case $(uci get wireless.radio0.hwmode) in
    11a) uci rename wireless.radio0=radio5ghz;;
    11g) uci rename wireless.radio0=radio2ghz;;
case $(uci get wireless.radio1.hwmode) in
    11a) uci rename wireless.radio1=radio5ghz;;
    11g) uci rename wireless.radio1=radio2ghz;;

# Reset virtual SSID-s
uci delete wireless.@wifi-iface[1]
uci delete wireless.@wifi-iface[0]

# Pseudorandomize channel selection, should work with 80MHz on 5GHz band
case $(uci get system.@system[0].hostname | md5sum) in
   1*|2*|3*|4*) uci set wireless.radio2ghz.channel=1; uci set wireless.radio5ghz.channel=36 ;;
   5*|6*|7*|8*) uci set wireless.radio2ghz.channel=5; uci set wireless.radio5ghz.channel=52 ;;
   9*|0*|a*|b*) uci set wireless.radio2ghz.channel=9; uci set wireless.radio5ghz.channel=100 ;;
   c*|d*|e*|f*) uci set wireless.radio2ghz.channel=13; uci set wireless.radio5ghz.channel=132 ;;

# Create bridge for guests
uci set network.guest=interface
uci set network.guest.proto='static'
uci set network.guest.address=''
uci set network.guest.type='bridge'
uci set network.guest.ifname='eth0.156' # tag id 156 for guest network
uci set network.guest.ipaddr=''
uci set network.guest.ipv6=0
uci set network.guest.stp=1

# Disable switch tagging and bridge all ports on TP-Link WDR3600/WDR4300
case $(cat /etc/board.json | jsonfilter -e '@["model"]["id"]') in
        uci set network.@switch[0].enable_vlan=0
        uci set network.@switch_vlan[0].ports='0 1 2 3 4 5 6'
    *) ;;

Configure site-specific settings in overlay/etc/uci-defaults/99-site-name:

# Configure tagging
uci set network.lan.ifname='eth0.3' # Password protected network VLAN3 tagged
uci set network.guest.ifname='eth0.4' # Public network VLAN4 tagged

# Configure wireless networks
for band in 2ghz 5ghz; do
    uci delete wireless.radio$band.disabled
    uci set wireless.radio$band.country=EE

    uci set wireless.lan$band=wifi-iface
    uci set wireless.lan$band.network=lan
    uci set wireless.lan$band.mode=ap
    uci set wireless.lan$band.device=radio$band
    uci set wireless.lan$band.encryption=psk2+ccmp
    uci set wireless.lan$band.ssid=Robootikaklubi
    uci set wireless.lan$band.key='salakala'

    uci set wireless.guest$band=wifi-iface
    uci set wireless.guest$band.network=guest
    uci set wireless.guest$band.mode=ap
    uci set wireless.guest$band.device=radio$band
    uci set wireless.guest$band.encryption=none
    uci set wireless.guest$band.ssid=RobootikaklubiAvalik


# Add Lauri's Yubikey
cat > /etc/dropbear/authorized_keys << \EOF
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCb4iqSrJrA13ygAZTZb6ElPsMXrlXXrztxt3bcKuEbAiWOm9lR17puRLMZbM2tvAW+iwsDHfQAs0E6HDprP68nt+SGkQvItUtYeJBWDI405DbRodmDMySahmb6o6S3sqI4vryydOg1G+Z0DITksZzp91Ow+C++emk6aqWfXh7xATexCvKphfwXrBL+MDIwx6drIiN0FD08yd/zxGAlcQpR8o6uecmXdk32wL5W3+qqwbJrLjZmOweij5KSXuEARuQhM20KXzYzzQIAKqhIoALRSEX31L0bwxOqfVaotzk4TWKJSeetEhBOd7PtH0ZrmOHF+B20Ym+V3UkRY5P4calF

# Set root password to 'salakala'
sed -i 's|^root::|root:$1$LLo9T/Zr$cCp.dy5W.Om9oQ4LboQNz.:|' /etc/shadow

Use following command to build the image, this shall include collectd, strongswan and some other useful utils:

export PACKAGES="luci luci-app-commands \
    collectd collectd-mod-conntrack collectd-mod-interface \
    collectd-mod-iwinfo collectd-mod-load collectd-mod-memory \
    collectd-mod-network collectd-mod-protocols collectd-mod-tcpconns \
    collectd-mod-uptime \
    openssl-util curl ca-certificates \
    strongswan-mod-aes strongswan-mod-gmp strongswan-mod-hmac \
    strongswan-mod-kernel-netlink strongswan-mod-md5 strongswan-mod-random \
    strongswan-mod-sha1 strongswan-mod-updown strongswan-mod-curl \
    strongswan-mod-resolve strongswan-minimal \
    kmod-crypto-authenc kmod-crypto-cbc kmod-crypto-hmac \
    kmod-crypto-md5 kmod-crypto-sha1 \
    htop iftop tcpdump nmap nano -odhcp6c -odhcpd -dnsmasq \
    -luci-app-firewall \
    -pppd -luci-proto-ppp -kmod-ppp -ppp -ppp-mod-pppoe \
    -kmod-ip6tables -ip6tables -luci-proto-ipv6 -kmod-iptunnel6 -kmod-ipsec6"

for MODEL in tl-wdr3600-v1 tl-wdr4300-v1 archer-c7-v2 cf-e380ac-v2; do

Image deployment

I use Turris as my portable flashing unit since it has enough built in storage to house all the images I need:

mkdir -p /srv/tftpboot
uci set dhcp.@dnsmasq[0].enable_tftp=1
uci set dhcp.@dnsmasq[0].tftp_root=/srv/tftpboot
uci commit
/etc/init.d/dnsmasq restart

Create IP aliases, I put this in /etc/rc.local:

ifconfig br-lan:1 # WDR3600, WDR3400 uses
ifconfig br-lan:2 # TP-Link Archer C7 uses
ifconfig br-lan:3 # Comfast E380AC uses

Copy image builder generated images to your TFTP server:

scp bin/targets/ar71xx/generic/*-cf-e380ac-v2-squashfs-sysupgrade.bin \
scp bin/targets/ar71xx/generic/*-archer-c7-v2-squashfs-factory-eu.bin \
scp bin/targets/ar71xx/generic/*-tl-wdr4300-v1-squashfs-factory.bin \
scp bin/targets/ar71xx/generic/*-tl-wdr3600-v1-squashfs-factory.bin \

The bootloaders of the devices expect to find firmware images on the TFTP by known filenames, so rename the files:

cd /srv/tftpboot/
cp *-tl-wdr3600-v1-squashfs-factory.bin wdr3600v1_tp_recovery.bin
cp *-tl-wdr4300-v1-squashfs-factory.bin wdr4300v1_tp_recovery.bin
cp *-archer-c7-v2-squashfs-factory-eu.bin ArcherC7v2_tp_recovery.bin
cp *-cf-e380ac-v2-squashfs-sysupgrade.bin firmware_auto.bin

TP-Link WDR3600 from v1.5 on expects u-boot prepended image, to work around the issue you can prepend the u-boot blob from the original firmware:

opkg update
opkg install unzip
wget http://www.tplink.com/res/down/soft/TL-WDR3600_V1_150518.zip
unzip -n TL-WDR3600_V1_150518.zip
dd if='wdr3600v1_en_3_14_3_up_boot(150518).bin' bs=512 count=257 of=/tmp/recovery-header.bin
cat /tmp/recovery-header.bin *-tl-wdr3600-v1-squashfs-factory.bin  > /tmp/concat.bin
dd if=/tmp/concat.bin of=wdr3600v1_tp_recovery.bin bs=512 count=16001

Same goes for TP-Link WDR4300:

wget http://www.tplink.com/res/down/soft/TL-WDR4300_V1_150518.zip
unzip -n TL-WDR4300_V1_150518.zip
dd if='wdr4300v1_en_3_14_3_up_boot(150518).bin' bs=512 count=257 of=/tmp/recovery-header.bin
cat /tmp/recovery-header.bin *-tl-wdr4300-v1-squashfs-factory.bin  > /tmp/concat.bin
dd if=/tmp/concat.bin of=wdr4300v1_tp_recovery.bin bs=512 count=16001

To force device to flash itself from TFTP server:

  • TP-Link Archer C7, WDR4300 - Plug network cable into one of the yellow ports, hold reset and power on the device

  • Comfast E380AC always tries to load firmware over TFTP during boot, on one hand this might look like a security flaw, yet again this makes updating image easier, just double flip the circuit braker

Observe TFTP server log, in case of Turris:

tail -f /var/log/messages | grep dnsmasq
logread -f | grep dnsmasq

You should see something similar:

2017-09-15T06:17:15+02:00 info dnsmasq-tftp[18681]: sent /srv/tftpboot/ArcherC7v2_tp_recovery.bin to
2017-09-15T07:59:16+02:00 info dnsmasq-tftp[22031]: sent /srv/tftpboot/wdr3600v1_tp_recovery.bin to
2017-09-15T08:30:10+02:00 info dnsmasq-tftp[22031]: sent /srv/tftpboot/firmware_auto.bin to


For a budget wireless networks this is a competitive alternative.


TP-Link WDR3600 and WDR4300 being flashed similar fashion

Only missing bit is central management

LEDE Comfast TP-Link OpenWrt