This post is about making an OpenWRT image with USB dongle support. We, as a part of our kit that collects and sends data of energy meters over the net required to use routers in the solution along with the raspberry.
We settled on TP-LINK MR3020 with USB dongle support. Now, there is always an issue with USB dongles which causes them to lose connectivity and they go into a hung state which can be resolved by just plugging out and plugging in the dongle back. But in a system that has to be deployed, has to work without manual intervention, that can’t be a solution. So we needed more control over the router, and hence OpenWRT.
OpenWRT has a pretty decent documentation wiki of its own, but it is a little scattered, and this post is intended to describe the making of an image with the 3g dongle usage in mind. The steps listed here should work with pretty much any router just by replacing a few words in the command which I will highlight as and when required.
(This is the link to the OpenWRT documentation on how to make a custom image. — http://wiki.openwrt.org/doc/howto/obtain.firmware.generate )
Firstly, check the architecture of your router and download the appropriate image builder from here (go to the folder of your router’s architecture and download the ImageBuilder archive. For TLMR3020, I went to ar71xx)—http://downloads.openwrt.org/barrier_breaker/14.07/
Extract the archive. Go to the extracted folder (for me it was OpenWrt-ImageBuilder-ar71xx_generic-for-linux-x86_64). Configure the package repositories in the repositories.conf file. My repositories file looked like (copied from the OpenWRT wiki)
src/gz barrier_breaker_base http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/base src/gz barrier_breaker_luci http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/luci src/gz barrier_breaker_management http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/management src/gz barrier_breaker_oldpackages http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/oldpackages src/gz barrier_breaker_packages http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/packages src/gz barrier_breaker_routing http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/routing src/gz barrier_breaker_telephony http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/telephony ## This is the local package repository, do not remove! src imagebuilder file:packages
The command to build the image is
make image PROFILE=XXX PACKAGES="pkg1 pkg2 pkg3 -pkg4 -pkg5 -pkg6" FILES=files/
PROFILE
Check the name of your profile for your router, most likely it would be the router’s name. For me, it was TLMR3020. You can check the list of available profiles by running <make info> command in the extracted folder. The list of profiles available for ar71xx are — http://pastebin.com/WbudpBDJ.
PACKAGES
Following are the packages required for the usb dongle to work and for luci (the web interface. You can exclude it if just ssh access is fine for you)
comgt kmod-usb-serial kmod-usb-serial-option kmod-usb-serial-wwan usb-modeswitch kmod-usb-storage block-mount kmod-fs-vfat kmod-nls-cp437 kmod-nls-iso8859–1 luci-proto-3g luci
FILES
This is the important part for the image to work out of the box. For wireless and usb dongle to work as soon as you install the image (this is important for those who are update the firmware over remote access, as was the case for me), some files need to be included in the image. The way to include the files is extremely simple. You just make a directory in which you include the files exactly in the same structure as you want them in the router and pass the path of that directory. I included the following files in my directory –
/etc/chatscripts/3g.chat
ABORT BUSY ABORT ‘NO CARRIER’ ABORT ERROR REPORT CONNECT TIMEOUT 10 “” “AT&F” OK “ATE1" OK ‘AT+CGDCONT=1,”IP”,”$USE_APN”’ SAY “Calling UMTS/GPRS” TIMEOUT 30 OK “ATD*99#” CONNECT ‘ ‘
The second last line might need to be changed according to your ISP.
/etc/config/firewall
config defaults option syn_flood 1 option input ACCEPT option output ACCEPT option forward REJECT # Uncomment this line to disable ipv6 rules # option disable_ipv6 1
config zone option name lan list network ‘lan’ option input ACCEPT option output ACCEPT option forward ACCEPT
config zone option name wan list network ‘wan’ list network ‘wan6' option input REJECT option output ACCEPT option forward REJECT option masq 1 option mtu_fix 1
config forwarding option src lan option dest wan
# We need to accept udp packets on port 68, # see https://dev.openwrt.org/ticket/4108 config rule option name Allow-DHCP-Renew option src wan option proto udp option dest_port 68 option target ACCEPT option family ipv4
# Allow IPv4 ping config rule option name Allow-Ping option src wan option proto icmp option icmp_type echo-request option family ipv4 option target ACCEPT
# Allow DHCPv6 replies # see https://dev.openwrt.org/ticket/10381 config rule option name Allow-DHCPv6 option src wan option proto udp option src_ip fe80::/10 option src_port 547 option dest_ip fe80::/10 option dest_port 546 option family ipv6 option target ACCEPT
# Allow essential incoming IPv6 ICMP traffic config rule option name Allow-ICMPv6-Input option src wan option proto icmp list icmp_type echo-request list icmp_type echo-reply list icmp_type destination-unreachable list icmp_type packet-too-big list icmp_type time-exceeded list icmp_type bad-header list icmp_type unknown-header-type list icmp_type router-solicitation list icmp_type neighbour-solicitation list icmp_type router-advertisement list icmp_type neighbour-advertisement option limit 1000/sec option family ipv6 option target ACCEPT
# Allow essential forwarded IPv6 ICMP traffic config rule option name Allow-ICMPv6-Forward option src wan option dest * option proto icmp list icmp_type echo-request list icmp_type echo-reply list icmp_type destination-unreachable list icmp_type packet-too-big list icmp_type time-exceeded list icmp_type bad-header list icmp_type unknown-header-type option limit 1000/sec option family ipv6 option target ACCEPT
# include a file with users custom iptables rules config include option path /etc/firewall.user
/etc/config/network
config interface ‘loopback’ option ifname ‘lo’ option proto ‘static’ option ipaddr ‘127.0.0.1' option netmask ‘255.0.0.0'
config globals ‘globals’ option ula_prefix ‘fd66:0dee:5f2c::/48'
config interface ‘lan’ option force_link ‘1' option type ‘bridge’ option proto ‘static’ option ipaddr ‘192.168.1.1' option netmask ‘255.255.255.0' option ip6assign ‘60' option _orig_ifname ‘eth0 wlan0' option _orig_bridge ‘true’ option ifname ‘eth0'
config interface ‘wan’ option _orig_ifname ‘radio0.network1' option _orig_bridge ‘false’ option proto ‘3g’ option device ‘/dev/ttyUSB0' option service ‘gprs_only’ option apn ‘internet’
config wifi-device ‘radio0' option type ‘mac80211' option channel ‘11' option hwmode ‘11g’ option path ‘platform/ar933x_wmac’ option htmode ‘HT20' option txpower ‘30' option country ‘US’
config wifi-iface option device ‘radio0' option mode ‘ap’ option ssid ‘OpenWRT-Wifi’ option encryption ‘none’ option wmm ‘0' option network ‘lan’
Last three files are just copied from the router once all the options had been configured.
The next 3 files are two fix the dongle reset problem.
What we figured out was that every now and then the dongle got reset and lost its connection which can be solved by plugging out and plugging back the dongle. To emulate this a script is there by name of donglereset which checks if the internet is not working it switches the usb power off and on again after a couple of seconds. This is done by switching off the GPIO pin on the router.This pin might be different for different routers. The current script works for TLMR3020 with pin 8 for usb. The other two files are for initiating the cron and one crontab which runs the cron every 15 minutes.
/root/donglereset
#!/bin/bash
wget -s http://google.com if [[ $? -eq 0 ]]; then echo “Online” else echo “Offline” ifdown wan # turn off USB power echo 0 > /sys/devices/virtual/gpio/gpio8/value # let things settle sleep 2 # turn on USB power echo 1 > /sys/devices/virtual/gpio/gpio8/value # restart the interface ifup wan fi
/etc/crontabs/root
*/15 * * * * ash /root/donglereset
/etc/init.d/S60cron
#!/bin/sh
# start crond /usr/sbin/crond -c /etc/crontabs
All these files are to be included in a directory files within the extracted folder and with the same directory structure as mentioned.
MAKING IMAGE
Now, run the make image command. For me, it was
sudo make image PROFILE=TLMR3020 PACKAGES=”comgt kmod-usb-serial kmod-usb-serial-option kmod-usb-serial-wwan usb-modeswitch kmod-usb-storage block-mount kmod-fs-vfat kmod-nls-cp437 kmod-nls-iso8859–1 luci-proto-3g luci” FILES=files/
You now will have the image in bin folder of the extracted folder in the directory name of your architecture. Mine’s name was openwrt-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin. You can now use upload this image via the firmeware upgrade option in the router.