Openwrt For Mac



After attempts at buying a GPS-equipped cellular router for a vehicular communications project fell through, I spent the weekend trying to find an alternative based on a standard Ethernet router. The process uncovered lots of new and poorly documented tasks so I hope my notes will save someone else a whole heap of time and frustration.

My first target was the Asus WL-500GL, after reading of success with oleg's firmware and gpsd. Unfortunately, combing all the local electronic retailers in my city (Newcastle, Australia) for Asus routers turned up only strange looks and zero routers. In desperation I found that the Linksys WRT54GL was a possibility, having good support for OpenWrt and at least one available serial port. However, to my dismay I found hundreds of WRT54G2, which despite the similar name, lack critical features that the unavailable WRT54GL sports.

Of the routers that were actually available, the only remaining glint of hope I found was in the D-Link DIR-615. The OpenWrt docs claim support for the C1 model, but the closest I could find was C2. Options were running dry fast, so I took the plunge on the C2 model.

Setup was straightforward. The router bag was sealed with large sticker and plenty of warnings that the software from the CD must be installed before connecting the router. I ignored them. I don't have a Windows machine handy and the CD only contains a compressed installer image. With the router up and running, it was time to create the build environment.

I'm running Mac OS X 10.6.3 (Snow Leopard) with the Developer Tools installed. I'll indicate commands for the host terminal with the prefix '$' and commands for the router terminal with the prefix '%'.

Mac address: no (hostapd/driver default) Overrides the MAC address used for the Wi-Fi interface. Warning: if the MAC address specified is a multicast address, this override will fail silently. To avoid this problem, ensure that the mac address specified is a valid unicast mac address. Dtimperiod: integer: no: 2 (hostapd default).

  • OpenWrt uses peer DNS servers as the upstream DNS provider for dnsmasq by default. These are typically provided by the upstream DHCP server. You can change them to any other DNS provider or even to a different local DNS server you have running already in your network. Make sure selected provider supports DNSSEC validation if required.
  • Mac address: no (hostapd/driver default) Overrides the MAC address used for the Wi-Fi interface. Warning: if the MAC address specified is a multicast address, this override will fail silently. To avoid this problem, ensure that the mac address specified is a valid unicast mac address. Dtimperiod: integer: no: 2 (hostapd default).

I used MacPorts to get some dependencies:

For

coreutils installs fileutils and findutils installs the GNU version of find, necessary when creating the build images.

The build system requires a case-sensitive filesystem, so I used Disk Utility to create a 4GB (yes, >3GB to compile sources!) Mac OS Extended (Case-sensitive) disk image, then used terminal to navigate to it.

Openwrt For Mac

I checked out the OpenWrt trunk source. I actually spent the first 6 hours working with the 8.09 branch (as suggested by the compatible hardware list) but found many problems, including lack of DIR-615 profiles, file too big problems and linker errors 'Nonrepresentable section on output'. So I switched to trunk and everything started to work. For what it is worth, I pulled trunk on the 4th April, 2 days after Backfire 10.03-rc3 was posted.

If make prereq succeeds, it may run menuconfig automatically. In any case, once I was in menuconfig I had to be very careful not to press an arrow key! It appears the arrow keys aren't escaped properly, and generally cause menuconfig to quit. Instead, I navigated using the accelerators, enter, esc, plus, minus, 'y', 'n' and spacebar.

I used menuconfig to:
* Change Target System to Atheros AR71xx
* Change Profile to D-Link DIR-615 C1

To save the config I pressed Esc from the main menu and then Enter to select 'Yes'. Then I built the configuration:

This took around 30 minutes on a 2.8GHz Intel Core 2 Duo. Once it was complete, my bin/ar71xx directory contained the following (preceded by file size):

3866648 openwrt-ar71xx-dir-615-c1-squashfs-factory.bin
2555908 openwrt-ar71xx-dir-615-c1-squashfs-sysupgrade.bin
2752512 openwrt-ar71xx-root.jffs2-128k
2621440 openwrt-ar71xx-root.jffs2-64k
1703936 openwrt-ar71xx-root.squashfs
1646596 openwrt-ar71xx-root.squashfs-4k
2005637 openwrt-ar71xx-rootfs.tgz
1183055 openwrt-ar71xx-uImage-gzip.bin
852722 openwrt-ar71xx-uImage-lzma.bin
2619896 openwrt-ar71xx-vmlinux.bin
2686288 openwrt-ar71xx-vmlinux.elf
1245184 openwrt-ar71xx-vmlinux.gz
917504 openwrt-ar71xx-vmlinux.lzma

And I was ready for the first flashing. This is where things get nervous. It turns out the DIR-615 has a ~200KB boot space reserved for the boot loader and the flash image takes up the remaining 3.8MB. That should make it pretty hard to brick the router, and I didn't have any problems, but you never know.

After mucking around with the router's 'emergency upgrade flash' mode (accessed by holding the reset button for 30 seconds until power light flashes amber) for a couple of hours, trying all manner of hardware IDs, I gave up and used the D-Link web interface instead. Under Tools there should be a 'Upgrade Firmware' link. I used this, uploaded 'openwrt-ar71xx-dir-615-c1-squashfs-factory.bin' and away it went!

In just 14 hours I had OpenWrt running on the DIR-615!

To restore access to the router I set my network settings to manual IP 192.168.1.100, then logged in:

I changed the lan option ipaddr to 192.168.0.1 so it didn't clash with my existing network.

Remember to change manual IP to 192.168.0.100 to suit new subnet.

And we're in! The router automatically picked up a WAN address from my ADSL modem and everything worked as expected. I even tried commenting out 'open disabled 1' in /etc/config/wireless and found that wireless worked without a hitch.

With the default OpenWrt kernel installed I was able to run opkg to install gpsd which worked well. In order to test the system however, I really needed some more software. At first I investigated modifying the gpsd package to include gpsfake, but after discovering that it requires python which is a large package itself, I decided to include my own software instead.

I found the easiest way to include my own software was to create a basic package and stick it in trunk/package:

Most of the packages actually download their source from the Internet, but a neat trick in the package Makefile allows the source to be included locally. My Makefile looks like this:

The src directory then, contains a simple c source file and a very small Makefile. Both can be developed in the native host environment before including in OpenWrt.

While I was adding software to the kernel image, it made sense to add gpsd as well.

Adding the uclibc++ dependency now saves a lot of wasted time later!

menuconfig automatically picks up the new packages:

This time I entered Network and hit 'y' for gpsd and gpssim. I also entered Libraries and noted that uclibc++ had been added as a required build. Esc and Enter to exit and save menuconfig.

This time the openwrt-ar71xx-dir-615-c1-squashfs-factory.bin image was created with the extra packages included. Now how to flash the new image, since we've lost the D-Link web interface? At first I tried many permutations of mtd after deciphering /proc/mtd and dmesg, but couldn't get past this:

So I tried tftp instead:

At this point I power cycled the router and immediately began issuing this command over and over again:

Eventually the 'sendto: No route to hose' message doesn't come back, and the following appears instead:

The router then automatically reboots and loads the new firmware. It also resets itself to 192.168.1.1, so to get it back I switched my manual IP to 192.168.1.100 and then:

Change ipaddr back to 192.168.0.1…

Change manual IP back to 192.168.0.100…

Openwrt Dhcp

And we're done! A working OpenWrt install complete with custom software, ready to try to get gpsd to work. The first thing I did was add enable gpsd at boot by creating /etc/init.d/gpsd with the following contents:

So far I've done some preliminary tests to find and enable the serial port. I've found that the 4 vias near the bottom left of this photo are likely serial suspects.

Openwrt Mac Filter

The top via is ground, the next two are Rx and Tx (I'll check which is which using an oscilloscope tomorrow) and the bottom is 3.3V. I've confirmed I can send and receive data (albeit, unreliably) via this interface by sticking a paper clip between the middle two vias, running '% cat < /dev/ttyS0' in one session and 'echo 'Hello, world!' > /dev/ttyS0' in another.

What remains is to dump the information I've found about this router for Google fodder and also in case someone wants to update the wiki!

* Another shot of the internals appears below, but the FCC also have photos from their tests on their website.

* It turns out the C2 hardware version I have actually has a circuit board with C1 stamped on it inside. So I do not know what the difference between C1 and C2 is.

* Filesystem:

* cpuinfo:

* Chips on board:
** AR9130-BC1E
** W9425G6EH-5: 4M, 16 BITS DDR SDRAM (there seems to be confusion about 4MB/8MB - it only has 4MB but each location is 16 bits)
** AR8216: Ethernet switch
** MX25l3205: 32Mbit CMOS Flash (RAM and FLASH sizes are reported backwards in some docs)
** RT9183H: Linear Regulator

* The router comes with DIR-615_3.01-tomizone-1.0.2 firmware. This version does not appear to be on ftp.dlink.com, but is available from http://www.tomizone.com/downloads/firmware. It looks like tomizone support is the difference between C1 and C2. Given the trouble I had getting the emergency flash upgrade page to accept any images, it may be difficult to return to router to D-Link firmware.

More to come as I work on interfacing a Garmin GPS 18x OEM LVC to the serial port.

I decided to restrict Internet access from my LAN to known IP/MAC pairs only. Primary to block Internet access from my PS3, virtual machines and computers that do not need it. Simplest way to achieve this on Linux: filter packet coming from LAN interface in FORWARD chain.

On OpenWRT custom firewall rules can be defined in /etc/firewall.user. Before creating rules we need some method to create and (easily) maintain IP/MAC pairs. I decided t use /etc/ethers and /etc/hosts that already contains MACs, hostnames nad IPs (used by dnsmasq).

On my router I have /etc/ethers in format:

And /etc/hosts:

The only problem I found is parsing all those information in a simple way (eg. in a one line of sh/awk/perl/whatever script). Perl is not available in default installation of OpenWRT. SH cannot easily handle text files. Finally awk with grep seems to be really simple and efficient:

(awk'{ printf 'iptables -A forwarding_rule -i br0 -m mac --mac-source ' $1 ' -s ' ;
cmd = 'cat /etc/hosts | grep ' $2 ; cmd | getline ; print $1 ' -j ACCEPT' }'
/etc/ethers ;
echo'iptables -A forwarding_rule -i br0 -j DROP')

This command (script?) parses /etc/ethers and /etc/hosts and creates firewall rules on standard output:

Now it is easy to attach it to OpenWRT firewall in /etc/firewall.user. Just after flush rules insert:

# Forward only traffic from known clients
(awk'{ printf 'iptables -A forwarding_rule -i br0 -m mac --mac-source ' $1 ' -s ' ;
cmd = 'cat /etc/hosts | grep ' $2 ; cmd | getline ; print $1 ' -j ACCEPT' }'
/etc/ethers ;
echo'iptables -A forwarding_rule -i br0 -j DROP')|sh

Note “| sh” at the end of command. This is needed to execute created rules.

Finally reload firewall rules:

Openwrt Clone Mac

Try to access any Internet hosts from allowed and blocked (any not allowed) clients. Than check if it works: