This is my first post (excuse me, frst psot) on this blog and so I think it’s fitting to leave the title at the WordPress default. I did change it to my preferred style of “Hello, world!” (capital H, lowercase w, comma and exclamation point, however. I’ve seen some Australians use “G’day, world!” which is silly, as your first day using a new programming language is likely to be anything but good. “Frustratin’ day, world!”, maybe.
This post is about Linux and ACPI and WOL. Before I describe what I’m trying to do, let’s look at my network. The solid lines are wired 10/100 Ethernet connections; the dashed lines are 802.11 b, g wireless connections.

Nate's network
The router is standard Netgear fare running DD-WRT (which warrants a post of its own). In this post I will italicize hostnames and IP addresses. I will bold commands, programs, and services.
Pelican is my media center computer (it’s monitor is a big TV, hence the broadcast television connection). Vista2 is my work computer (and does not warrant a cool bird name). Bluebird is an Acer Aspire One netbook.
My goal is to connect to Stork remotely (i.e. from the Internet) using SSH. I want the machine to be either suspended (ACPI mode S3), hibernated (ACPI mode S4) or turned off entirely. When I attempt to connect via SSH I want the computer to seamlessly resume/boot and accept the connection. When I’m done and the machine is idle I want it to return to suspend or power down.
Stork is running Debian GNU/Linux (Sid/unstable branch) with a 2.6.26 based kernel. It is currently running an SSH server; besides that it’s not doing much at all. It’s not running X.
My first goal was to get Stork suspending properly. In BIOS I enabled practically every ACPI option relating to suspend modes. I did leave the options for waking up on keyboard, mouse, etc. disabled as I didn’t want the machine to accidentally wake while I was moving things around. Booting into Debian I issued echo mem > /sys/power/state to put the system in suspend mode (S3).
It went down ok, everything powered off. Punching the power button brought it back up very quickly, except for the video card. Video cards are notorious trouble spots in ACPI implementations as they have to have their registers reprogrammed from scratch at resume; usually Linux relies on the BIOS to do this at boot (as video card makers are secretive about how it’s done), but as a resume from S3 does not use the BIOS for this purpose it’s not unusual for the video card to fail to resume properly.
After playing around with it I decided to install the pm-* suite of tools – in particular I was planning on using pm-suspend and pm-hibernate. These tools make use of the uswsusp suite (which provides s2disk, s2ram, and s2both). pm-* knows a lot of methods for putting finicky devices to sleep; without any further work on my part it seemed to handle the video card ok. Hibernate worked fine also.
At this point I could suspend or hibernate the machine by issuing either pm-suspend or pm-hibernate, and resume by pressing the power button. Very exciting!
The next step was to find a network card that supports wake-on-lan, or WOL. As it happened I found an old 8139-based card specifically labeled as a WOL device; I popped it in and Debian had no trouble loading the 8139too module to support it. I configured my router to give Stork the static IP address 192.168.1.2 and forwarded SSH to this IP.
Let’s stop and say a word about WOL. As I mentioned I disabled the options in BIOS that would allow the keyboard or mouse to wake up the sleeping computer. I did, however, enable the option that would allow a WOL compliant network card to wake the computer. What this means is that if I get Linux to configure the card properly before I suspend/hibernate, the card can wake up the computer (or turn it on from scratch) when it sees something of interest on the network.
Now, I’m using a router (as opposed to a switch) so the only thing that will possibly get through to Stork is unicast (to Stork) or broadcast packets. I don’t have a multicast network (does anyone?). The reason I’m mentioning this is because a network card that supports WOL can wake up the computer in a number of situations. Some cards support different options; here are the available ones.
- p: Any activity at the physical level will wake the machine. I found that this means the machine wakes as soon as it goes to sleep; not very practical.
- u: Unicast packets directed to the MAC address of the network card will wake the machine. This seems to be what I want; when a packet arrives to initiate an SSH session the card will wake the machine.
- m: Multicast packets that include the MAC address of the network card will wake the machine. Again, I don’t have a multicast network.
- b: Broadcast packets will wake the machine. I don’t want this, because this means things like pings and DHCP queries will wake the machine up. I only want it to wake when it is specifically addressed.
- a: ARP requests that the network card should answer (requests to find the MAC address that goes with a specific IP address) will wake the machine. As I found out, this is exactly what I want, but unfortunately my card (nor any else I’ve seen) supports it. More on this soon.
- g: Magic packets sent to the network card’s MAC address will wake the machine. This is the most commonly supported type of WOL. From a computer in the same subnet you run a command (supplying the MAC address of the target machine); when that special packet reaches the sleeping machine the network card wakes it up. I decided to use this type as well for testing.
- s: Same as g, but includes a password. I don’t know of any cards that support this.
Whew, ok. So in Debian I ran ethtool eth0. It informs me that my network card supports WOL modes p, u, m, b, and g. I enabled modes u and g by issuing the command ethtool -s eth0 wol ug.
I then issued pm-suspend to put the system in S3. Walking over to Bluebird (also running Debian, but it doesn’t really matter) I issued the command ssh 192.168.1.2. Unfortunately the machine did not wake up; instead I receive no route to host on Bluebird. I then tried sending a magic packet to Stork‘s MAC address using the etherwake program. Again, no luck, Stork remained asleep. I then woke the machine up by pressing the power button.
I tried the same process after issuing pm-hibernate, but had the exact same lack of success. However, after some research online I found a suggestion to change the mode by which pm-hibernate hibernates – from “platform” to “shutdown” (whatever that means). This is accomplished by editing the file /etc/uswsusp.conf (remember, pm-* uses the uswsusp tools):
# /etc/uswsusp.conf(8) -- Configuration file for s2disk/s2both
...
shutdown method = shutdown
...
After making that change, I issued the command pm-hibernate again. The machine went down and I trotted back across the room. ssh 192.168.1.2 still wouldn’t wake the machine (again, no route to host) but now etherwake sent its magic packet and BAM – the machine turned on, booted up, and resumed from hibernation! Very cool!
So why wasn’t SSH waking the machine? Well, Stork was not in Bluebird‘s ARP cache; that is to say, Bluebird did not know how to take the IP address 192.168.1.2 and come up with Bluebird‘s MAC address (since they are on the same subnet, Bluebird talks to Stork directly by MAC address). To find this MAC address it broadcast an ARP request. However, ARP requests are broadcast packets and Stork‘s network card was asleep with the rest of the system, waking only on unicast packets. Bluebird never got a reply and so couldn’t construct a route for the SSH connection. A magic packet, like the SSH packet, is sent directly to a MAC address, but it must be keyed into the etherwake program manually, thus avoiding the need for an ARP request.
Now, if the network card supported the WOL mode a, the ARP request would wake the system up. This would be perfect… except the network card does not support the WOL mode a. Oh well. If I were building a new system for this purpose I would definitely buy a network card that supports that mode.
The end result is that there is no easy way to wake Stork from Bluebird using unicast packets. There are some techniques for having the router act as a proxy ARP and spoof replies as if Stork was replying, but that’s not really what I want. I decided that if I’m in the same room I can just walk over and turn the machine on; after all, I did specify that I wanted the machine to turn on when accessing it remotely, from the Internet.
The problem isn’t solved completely, though… the router still needs to know Stork‘s MAC address! When the SSH packet arrives from the Internet and is forwarded to 192.168.1.2, the router has to perform an ARP query. To remedy this I modified the router firmware’s (DD-WRT) start-up script to install a permanent entry in the ARP cache (permament while the router is on, anyway). Now the router always knows that 192.168.1.2 is associated with Stork‘s MAC address and can forward any incoming SSH packets directly to the network card.
Interestingly, you might think that having established a static DHCP entry for Stork, which associates Stork‘s MAC address with 192.168.1.2 I have already achieved this permanent association. However the processes that control DHCP and ARP are seperate and do not share this information.
I rebooted the router, put Stork‘s network card into WOL modes u and g again, and once more put the machine into hibernation. This time I used Bluebird to connect to a remote machine (a server at my undergrad university) and from there attempted to SSH to my apartment. Down came the packet to my router. The router picked it up, saw that it was destined for the SSH port and redirected it to 192.168.1.2. It then checked it’s ARP table to see which MAC address goes with that IP address. It found the permanent entry I installed and forwarded the packet to Stork‘s network card. When the packet arrived the clouds parted, angels sang, and the machine turned on. Hooray!
So to summarize, I now have a machine that can wake from hibernation when either a magic packet is sent from the local network or an SSH connection is initiated from a remote network (the Internet). There are two things left to do.
First, I want the machine to automatically go into hibernation when idle. There is an easy way to do this in Linux: the sleepd daemon. Unfortunately the sleepd daemon considers “idle” to be “no keyboard or mouse action for a set amount of time”. That’s not very practical for me since I don’t intend to have any keyboard or mouse hooked up at all! I would prefer something along the lines of “no hard drive access for a set amount of time” or “no unicast network packets for a set amount of time”. I have yet to find an existing solution, so I may have to rig something up to do this. (What we really want is a simple DBus based daemon that puts the system to sleep in a variety of configurable ways, and a bunch of little clients, each one of which that sends the daemon a message when it sees the system as idle according to some classification. The existing behavior would be mimicked by loading an “idle daemon” that watches the keyboard and mouse; my desired behavior would be implemented with an idle daemon that watches the hard drive, and so on. But I’m getting side-tracked here!)
The second thing I still need is something I skipped over earlier. I didn’t mention it, but since I installed the network card Debian stalls about 1 to 3 minutes on boot. This occurs when loading the kernel and so delays resuming from hibernation. Either I need to fix this or get WOL working during suspend and use that instead. I prefer hibernation because I don’t need to worry about killing the power to my network at night, so the best situation would be to fix the delay. I’m not sure why it happens (it doesn’t depend on the PCI slot or interrupts used) but I haven’t looked into it too much.
Alright, that’s it for this long, boring post about technologies practically nobody uses. But how cool will it be when I can SSH to a completely turned-off system and have it boot up just for me (and shut back down again when I’m done)? Very cool, that’s how cool.