I realized while reading the last post that I sounded awfully negative about my research! I should note that I find what I’m doing fascinating; it’s my descriptions and attempts to convey that excitement that bore.

I guess I could just edit that post, but WordPress utilizes what may be the most complicated blogging software known to man. I’m not sure whether I’m writing a post or controlling a satellite. For instance, where might you expect to find the blog subtitle? Maybe under “Dashboard”? “Appearance”? “Settings”? “Blog info”? I worry that if I delve too deeply I will literally become lost in the pages. So the post stays.

Back to the item at hand. I made a little graphical thing that I think describes the grammar problem in a different way.

Grammar problem

Grammar problem

Notice how the referential arrows cross in the first case and do not cross in the second case. (The order in which I listed the cases is reversed from how I wrote it in my previous post.)

From here you can imagine larger constructions. Let’s say that the non-confusing form of the clause is The seeing of men about horses on Tuesdays. If the “split” form is proper at all, there are only two choices.

  1. Men, horses, Tuesdays, and the seeing thereof, thereabouts, thereon
  2. Men, horses, Tuesdays, and the seeing thereon, thereabouts, thereof

This cases correspond to the same sort of diagrams. For the first, the arrows are all crossing. For the second, the arrows are all nested. It is obviously wrong to mix the two; at least it certainly feels wrong, as it would imply that the rules of grammar being applied are dependent on the number of prepositional phrases, which is a little silly. For example, we can say via intuition that “men, horses, Tuesdays, and the seeing thereon, thereof, thereabouts” is incorrect.

The first form (crossing arrows) is akin to FIFO behavior: first in, first out. The second is LIFO: last in, first out. It’s this mathy, computer-sciency connection that interests me – are split prepositional phrases (making up the terminology) ordered FIFO or LIFO in English? What about other languages?

My vote is on LIFO, mainly because I think it feels niftier on the tongue.

Now if you’ll excuse me, there are men, horses, Tuesdays, barns, profit, and the seeing therefor, therein, thereon, thereabouts, thereof to which I must attend.

Advertisement

The other day I was writing a very long post about what I do here at school, but I gave up halfway as I realized I was boring myself. This is not a good sign.

I’m sitting here watching my code run. It runs, and eventually I stop it and I check what it’s doing. I then shake my head sadly and change a few lines of code and try again. Very exciting! I have some thoughts on Haskell, the programming language in which I’m working, that I’ll share at a later time.

Today, however, I’m going to write about grammar. I am an engineer by degree and so you mite expect me too right like this. I’m not particularly thrilled by language, but some parts of it interest me. This post may or may not interest you. Read on and find out!

In English there is a colloquialism: going to see a man about a horse. The subject of the trip can be adjusted (“going to see a man about a dog”, for example) and sometimes the noun too (“going to see a dog about a man” is sometimes used). The act denotes a private errand; the phrase is used to brush off a question regarding the same.

A: Sorry, I must leave now.
B: Where are you going?
A: I have to see a man about a horse.

It’s suggested that originally the phrase was used literally – as in, gambling on horse or dog races. Nowadays it is rare to have to see anyone about a horse and so unless you live on a farm you can be fairly certain that the speaker is avoiding discussing their personal business with you.

It’s a gentle euphamism, however – it doesn’t imply any impropriety in the asking. If you’re looking for something that rebukes the asker, I’d suggest none of your beeswax!

On to the grammar question. Now that we understand the phrase itself, let’s put it to use. Suppose we wanted to construct a noun clause that referred to the general act of seeing men about horses. Which of the following two options is correct?

  1. Men, horses, and the seeing thereabouts, thereof
  2. Men, horses, and the seeing thereof, thereabouts

If it’s unclear, thereabouts refers to the horses, who are the subject of the meeting. Thereof refers to the men, who will be met.

We could rearrange the clause as the seeing of men about horses. “Seeing” is a gerund, followed by two prepositional phrases: “of men” and “about horses”. While less accessible, we could exchange the two prepositional phrases: the seeing about horses of men.

In each of these we can split the last prepositional phrase, leading to the following:

  1. Horses, and the seeing of men thereabouts
  2. Men, and the seeing about horses thereof

But if we wished to split the remaining preposition, what do we do? In #1, should “men” be put after or before “horses”, and should “thereof” be placed before or after “thereabouts”? In #2 it is the same dilemma.

So what do you think? Which do we use?

  1. Men, horses, and the seeing thereabouts, thereof
  2. Men, horses, and the seeing thereof, thereabouts

I know very little about English grammar and I don’t have the answer. It could be that neither clause is grammatically sensible. After all, the listener needs to be able to determine that we do not mean that we are going to see a horse about a man.

I may pose the question to a professor in the field, if I find one wandering the streets looking for confusing clauses to dissect. Otherwise I’ll continue using whichever pops into my head first and encourage you to do the same.

Today’s post is something a little mathier than the linux stuff I wrote about during the past few days. A p-beauty contest is a game (in the real and mathematical sense of the word) in which n players must simultaneously and secretly guess an integer between 0 and m, inclusive. The judge then computes the average x of all the guesses. The winners are those players who guessed the integer closest to p x of the average, where 0 < p < 1.

Let's see an example with real numbers before we go on. Let's say that p=0.5 and we have n=20 players choosing integers between 0 and m=100, inclusive. Suppose all the players choose at random; the average is x=50. Then p x = 0.5 \cdot 50 = 25. The winners are all those players who chose 25 as their guess. If nobody chose 25 exactly, then the winners are those that chose 24 or 26 (and so on).

The reason this is called a "beauty contest" is because it is very closely related to a game called a "Keynesian beauty contest" (after John Maynard Keynes, the famous economist who first described it). In a Keynesian beauty contest, a newspaper publishes pictures of beautiful women. The readers are then told to vote on which one is the most beautiful. The woman who gets the most votes wins a prize, and the readers who voted for that woman also win a small prize.

The implication is obvious; you are not voting for the most beautiful woman, but for the woman whom you think will be voted most beautiful. But if everyone figures this out, then you’re really voting on the woman whom you think everyone else will think will be voted most beautiful. But if everyone figures this out too…

The p-beauty contest is the same idea. Let’s see how it works in our previous example. Bob is playing the game, and the judge says “Go!” and everyone begins writing down their answers. Bob looks around and sees Alice, who appears to be counting the number of polka dots on her shirt as a method for coming up with her guess. “Oh ho, you rube!”, thinks Bob. “If everyone is just like Alice and picks their number randomly, the average will be 50. 0.50 times 50 is 25 and so if I guess 25 I’ll win!” Bob writes down 25 and smirks.

Carol is sitting next to Bob. She sees the smirk on his face and thinks “Hmm, you know, I bet Bob thinks he’s really clever. I bet he figured out that if everyone guesses randomly, the winning guess will be that closest to 25. But I don’t think Bob is all that smart. In fact, I think that everyone is that smart, and they’ll all guess 25.” She bites the eraser on her pencil and thinks a bit more. “If everybody guesses 25 then the average will be, well, 25. So then 0.50 times 25 is 17.5, which rounds to 18. Therefore I will guess 18, and I’ll win!”.

Little does Carol know that Dave is sitting just behind her and sees her chewing on her pencil. Dave applies the same thought process and concludes that if everyone is as smart as Carol, everyone will pick 18. Accordingly, he picks 0.5 \cdot 18 = 9.

You can see where this is going. If everyone playing the game follows this logic forever, the numbers keep dividing by 2 forever. And since \lim_{k \rightarrow \infty} a / (2^k) = 0, the only possible outcome for such a game played by rational players is for all players to choose 0, at which point all players win.

Of course in real life, the players are not rational. If all but one of the players are rational, they will all choose 0, but the remaining player will throw the average off by choosing something else. It may still be close to 0 (making the rational players the winners), but that depends on how many irrational players are in the game and what numbers they choose. It doesn’t take many before the rational players will almost always lose.

But then in real life, the players (even the rational ones) know that their competitors are not necessarily rational. This is a very different game now! Being rational will almost certainly cause you to lose – you must be irrational, but cleverly so.

In the example given, Alice was a “level 0” player: she chose randomly. Bob was a level 1 player: he chose believing that everyone else was a level 0 player. Carol was a level 2 player: she chose believing that everyone else was like Bob, a level 1 player. And Dave was a level 3 player.

Are higher level players better than lower level players? Well, that depends how accurate their estimation is. Dave chose 9 because he assumed that everyone is a level 2 player. And Carol chose 18 because she assumed that everyone is a level 1 player. But what if it was really Bob that was right, and everyone (except for Bob, Carol, and Dave) picked randomly? In this case we have an average of (17 \cdot 50 + 1 \cdot 25 + 1 \cdot 18 + 1 \cdot 9) / 20 = 45.10. The winning guess is that closest to 0.5 \cdot 45.10 = 22.55. Out of the “advanced” players, Bob came closest with his guess of 25!

Carol and Dave overestimated the ability of the majority. Bob underestimated Carol and Dave, but estimated correctly the majority, and so his guess was closest. Note that Bob still might not have won, since a level 0 player could have randomly guessed closer to 23 than Bob, but Bob’s strategy was best in this situation.

The point here is that when the players take into account the strategies of the other players, that itself becomes part of their “meta-strategy”, if you will. And they need to realize that other players may very well be taking that meta-strategy into account in their own. In the perfectly rational game, everyone takes this concept so far that they all end up guessing 0 (and winning). In real life, however, you need to make some estimate of the rationality of the group.

I’ll end this post with a related riddle that I like. There’s probably an “official” name for the this, but I don’t know it so I’ll just tell it.

A logician is arrested on a Sunday afternoon by the Spanish Inquisition. The magistrate tells him that he is to be put to death at exactly noon on one of the upcoming 5 weekdays. Furthermore the magistrate tells him that there will be no prior warning of the moment of execution; at noon on the chosen day the executioner will appear outside the logician’s cell. He ensures the poor logician that it will be a shock, saying “you will be completely and utterly surprised when the moment comes.”

The logician is taken away and put in a cell. To further the torment, a large clock is erected just outside the bars. As the rest of that Sunday passes, the logician stares fearfully as the hands of the clock slowly move. At midnight the clock booms; he sits in the corner of the cell and shakes with the fear of being completely and utterly surprised by the moment of execution. “If I only had some idea when it would happen, it would be much easier to bear! But the judge said I would be completely and utterly surprised.”

Monday morning comes and the hands continue to turn. At 10 o’clock he is fearful; at 11 he is terrified; at 11:59 he is shaking, and as the clock strikes noon he darts to the bars… but no-one is there. He lets out a gasp and sinks to the floor. “Well, I wasn’t executed today, so that leaves Tuesday, Wednesday, Thursday, and Friday. If only I weren’t to be completely and utterly surprised!”

That night the logician is thinking to himself. “I wish I could narrow down the day – the fright would not be as much!” As he paces the cell watching the hands climb over midnight, he comes to a realization. “Ah ha! Suppose it was Thursday night. Were I still alive to ponder the question, I would know that Friday must be the day of my execution. And that would mean that as the minutes grow closer to noon on Friday I would know the executioner is coming. And that would mean that I would not be completely and utterly surprised!” He stops pacing and looks at the clock triumphantly. “Therefore, since I must be completely and utterly surprised, my execution cannot be Friday!”

The logician lays back down on the thin prison mattress. The hands of the clock continue to wind around the face into the early morning of Tuesday, but he can’t sleep. As 6 o’clock comes he suddenly sits upright with another revelation: “Oh ho! Suppose it is Wednesday evening. Were my head still upon my shoulders, I would know that Thursday must be the day of my execution, having already ruled out Friday. And that means that as noon on Thursday approaches I would know the executioner is on his way. And that would mean that I would not be completely and utterly surprised!” Now his mind is working at full speed. “Therefore, since I must be completely and utterly surprised, my execution cannot be Thursday!”

Satisfied that he has narrowed down the day of his execution to Tuesday or Wednesday, he lays down. Before long it is 11 o’clock. Again he stands before the bars, trying to get a glimpse down the hallway. The minutes tick by and he begins to sweat. At 11:45 he is gripping the bars so tight his hands whiten. At 11:59 he grits his teeth, closes his eyes, and waits for the sound of the executioner entering the hall. But as the clock strikes 12 he is still alone.

Frowning, the logician lets go of the bars and walks to the back of the cell. He leans against the stone wall and looks at the clock thoughtfully. Slowly a realization comes upon him and he runs forward and shouts at the clock: “Ah ha! I have figured you out! You see, as I was not executed Monday, nor was I executed today, and I have already proven that it cannot happen Friday, nor Thursday, then the day must be Wednesday!” He is surprisingly happy for a man who has named his own execution date, and he continues: “But when noon approaches tomorrow I will know that the executioner is sharpening his blade, and when you point your hands to 12 I will know that I am to be killed. But that means that I will definitely not be completely and utterly surprised! And therefore Wednesday cannot be the day of my execution!”

He is practically jumping up and down at this point, shouting at the clock with glee. “And since I wasn’t executed Monday, and I wasn’t executed today, and I can’t be executed Wednesday, Thursday, or Friday, then I shan’t be executed at all!” Grinning, he returns to the bed and sits down, having proven conclusively that he will not be executed.

The clock continues to tick, apparently ignoring his demonstration. Tuesday concludes and Wednesday begins. The logician, sure of his safety, is soundly asleep as 9 passes on Wednesday morning, then 10, then 11. At 11:59 he is dreaming of lectures to be given and proofs to be written. But our poor logician has sealed his own fate.

The clock booms, signaling noon on Wednesday, and the logician suddenly wakes to the clanking sound of a key in a lock. He sits upright and rubs his eyes, and then makes out the hooded figure of the executioner standing just within the cell door.

With shock our doomed hero exclaims: “But it cannot be today! Why, I proved it could not be today! I proved it could not be at all! This is impossible! How can this be? I am completely and utterly surprised!”

Hopefully you enjoyed my version of the riddle. The relation to the p-beauty contest is pretty clear; the magistrate thought one step ahead and estimated the intelligence of the logician. The logician’s own estimation was what doomed him, much like Dave losing the contest because his estimate places him far from the correct answer. It’s unfortunate for our logician that game theory wasn’t developed until the 1940’s!

As promised, a much better cron script for putting the computer to sleep. It’s actually two scripts – I split the hibernating functionality away from the “is idle” functionality. The hibernate script is simple and just includes my final result from this post. I stored this as /root/hibernate.

#!/bin/sh
#
# Hibernate this machine for WOL with unicast and magic packets.
# 2009 Nathan Blythe
#

ethtool -s eth0 wol ug
pm-hibernate

The script that does the idle checking is stored to /root/useridle:

#!/bin/sh
#
# Execute command if system is "user-idle"
# 2009 Nathan Blythe
#
# Run without arguments for usage.
#

# Filepath of temporary file used by this script.
#
FIL=/tmp/useridle.tmp


# Get the command line arguments.
#
idl=$1
cmd=$2


# Invalid arguments.
#
if [ "$idl" != "reset" ] && [ -z "$cmd" ]; then
  echo "Usage:"
  echo "  useridle [reset]"
  echo "    Reset the system idle time."
  echo
  echo "  useridle  "
  echo "    If the system has been userless for idl seconds, execute"
  echo "    cmd and reset."
  echo
  exit
fi


# Determine the current time.
#
newtime=$(date +%s)


# Reset.
#
# Write the current time to the temporary file.
#
if [ "$idl" = "reset" ]; then
    echo $newtime > $FIL
# Ordinary operation.
#
else
  # If the temporary file does not exist or at least one user is
  # logged in, write the current time to the temporary file.
  #
  if [ ! -e $FIL ] || [ "$(users)" ]; then
    echo $newtime > $FIL


  # Otherwise if it's been at least idl seconds since the time in the
  # temporary file, execute cmd and then reset the temporary file.
  #
  else
    oldtime=$(( $(cat $FIL) + $idl ))

    if [ $newtime -ge $oldtime ]; then
      $cmd
      echo $newtime > $FIL
    fi
  fi
fi

This is a simple script (most of that is just fuzz) that keeps track of the time at which users were seen on the system. When you run it, it checks to see if there are users logged in; if so, it stores the current time to a file. If there are no users logged in, it checks the file to see when was the last time users were logged in. If the desired amount of time has gone by, the provided command is executed.

I use this script by adding the following lines to /etc/crontab.

@reboot         root    /root/useridle reset
*  *    * * *   root    /root/useridle 180 /root/hibernate

This runs my script with the “reset” argument when the computer starts up – this is to make sure it doesn’t hibernate immediately, since the file might have the time from before the machine was shut down. Every 60 seconds it also runs the script with the arguments “180” and my hibernate script. Thus every 60 seconds the machine checks if there haven’t been any users logged on in the past 3 minutes. If this is the case, it hibernates until it is woken by a remote login.

All that needs to be done to configure the script is to edit /etc/crontable. There I can change the first “*” on the second line to, for instance, “*/5” or “*/15” to have the script run every 5 or 15 minutes, respectively, and adjust the “180” argument. So long as the idl parameter (180 seconds, currently) is significantly longer than the period of the cron job (60 seconds, currently) it will be somewhat accurate.

Pretty nifty, huh? I haven’t solved the problem of SSH only waking the machine (on the first try) and having to try again to log in. I think that might just not be doable without changing how SSH attempts to connect. I may forward another port to the server so I can use some common command to boot the system. Either way, I’m happy with how it works.

I will post a summary of all this information at some point in case anybody ever wants a similar set up. It sure is power efficient, especially for doing things like a remote SSH file transfer for backups. I may forward rsync to the machine too… a backup server that (more or less) transparently boots up when needed and shuts down when finished… very nifty!

Sorry Hani, I couldn’t resist that title!

Yesterday I summarized my adventures with Linux and ACPI and WOL, culminating in a machine that would wake up from hibernation when a user initiated an SSH session from a remote (outside my apartment) network. I ended the post saying that there were two things left to do. Today I got those two things working!

First, the second thing. I said that when the computer in question, Stork booted there was a long (1 to 3 minutes) delay. It was something to do with the network card, becaues it only occurred when the card was installed. Different slots and combinations of BIOS settings made no difference.

Today I noticed that the 2.6.30 kernel has made it into unstable (it must have gone in during the past few days, as when I installed the machine three days ago it wasn’t available yet). I went ahead and installed it and rebooted and sure enough, the long delay is gone. I have a suspicion this is more to do with building a new initrd, and that I could probably have solved the problem by rebuilding the ram image for my previously installed kernel. I may go back and try this, but it’s working now anyway. Boot up time on a cold-start is less than 45 seconds, and resume from hibernation shaves another 20 off that. That includes a 4 second GRUB wait, which I may trim down.

The first problem was a desire to have the machine go into hibernate automatically, as a result of no activity. I decided that I would approach this with a cron script (which may or may not be the best short-term approach). I wrote a very simple script as below.

#!/bin/sh
#
# Hibernator cron job
# 2009 Nathan Blythe
#

# Delay to give the user time to log in.
#
sleep 60

# Anybody logged in?
#
if [ -z "$(users)" ]; then
  # Put the NIC in WOL modes u and g.
  #
  ethtool -s eth2 wol ug

  # Hibernate.
  #
  pm-hibernate
fi

There you have it; doesn’t get much simpler than that. I stored the file as /root/hibernator. I added a line to /etc/crontab that looks like this:

*/5  *  *  *  *  root  /root/hibernator

This tells cron to run the script every 5 minutes. So why the sleep 60 command in the script? Well I found that when the machine resumes it has a tendency to run the cron job immediately. This means that if you don’t have a bit of a delay between when the script starts and when it actually does the deed, the user won’t have time to finish logging in. The SSH packet arrives, the machine wakes, and before they can finish entering their password, it hibernates again.

A better cron job may be in the works. Running the script every 5 minutes gets the job done, but it means that when a user logs out there could be a 5 minute delay until the machine goes down or just a few seconds, depending on the time. A better system would run every 5 minutes or so and store the time at which it saw users to a file. Then if it doesn’t see users it checks if a certain amount of time has gone by (since the time in the file). If so, then it hibernates.

Furthermore, a better script would also do some lsof or netstat magic to determine if a user is logging in at the moment (remotely anyway… local users still have to beat the clock). I may work on such a script later.

A new problem has come up, however. I’ve realized that when I attempt to connect remotely, the SSH packet does indeed wake the system, but then the connection is not made until SSH is tried again. The packet that wakes the system is thrown away, and for whatever reason SSH doesn’t try again. I’ll have to think of a way around this. It could be I just use some port as a “wakeup” port… for instance, port 80. Issuing an HTTP request to my network wakes up the machine, after which SSH works. I’d prefer a more smooth system, but we’ll see.

Stay tuned for a better cron script!

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

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.