Cliff Hacks Things.

Saturday, November 24, 2007

eeebuntu tip: wireless with hal and NetworkManager

I've been away from Linux for quite a while, off in Mac-land, where things generally just work. I was delighted to notice, upon my return, that the community (and RedHat in particular) noticed that manually configuring your wireless interfaces is lame, and built a solution: NetworkManager.

NetworkManager is built atop hal, a daemon that interrogates hardware and makes the information available over a dbus interface. (dbus is a simple mechanism for interprocess messaging and procedure call, similar to DCOP, but more general.)

If you install Ubuntu and subsequently bring up your network using a panel applet, you're using NetworkManager -- and boy, is it nice. Unfortunately, most instructions for getting the eee's wireless working on Ubuntu revolve around the "old-world" configuration mechanism in /etc/network/interfaces. While Ubuntu has graphical configurators that generate this file, using it prevents you from applying the full power of NetworkManager. (Fun fact: NetworkManager will silently ignore any interfaces that are configured in /etc/network/interfaces.)

NetworkManager and hal are really poorly documented. (No offense to the authors intended; the tech is impressive, and I understand that sometimes precious little time is left over to write a design document.) I don't understand the system well enough to write a general tutorial, so here's a specific one: how to get NetworkManager and hal playing nice with the binary Atheros drivers on "eeebuntu" -- Ubuntu 7.10 using the ASUS-compatible 2.6.21.4 kernel I described in my last post.

Getting hal to create ath0 automatically



The Atheros wireless drivers create two network interfaces: wlan0 by default, which seems to be good for very little, and ath0 on demand, which is what you actually use to speak to the intarweb. You have to explicitly request creation of the ath0 interface like so:
wlanconfig ath0 create wlandev wlan0 wlanmode sta


hal, by default, sees the wlan0 interface as an 802.e interface, and does not see ath0 at all. What we want is for hal to ignore wlan0 and treat ath0 as an 802.11 interface. hal supports policy files (written in XML, which surprised me in a Linux tool) that rewrite its view of devices -- and that's what we'll use to fix this.

But first -- we need ath0 created automatically when wlan0 appears. A simple script suffices. I've put mine in a file called /etc/hal/callouts/eee-wifi for reasons that will become apparent in the next step. The script need only contain:

#!/bin/sh

case $HALD_ACTION in
add)
sleep 1 # May be unnecessary, experiment
/sbin/wlanconfig ath0 create wlandev wlan0 wlanmode sta
sleep 1
;;
remove)
/sbin/wlanconfig ath0 destroy
;;
esac


Notice that the script takes its input, not from a command-line parameter, but from an environment variable named HALD_ACTION. This will make sense in a minute. For now, you can test the script thusly:

# Should create ath0 if wlan0 exists and drivers are loaded
env HALD_ACTION=add /etc/hal/callouts/eee-wifi
# Should remove ath0
env HALD_ACTION=remove /etc/hal/callouts/eee-wifi


Now, we convince hal to invoke our script when wlan0 appears or disappears. Create a file named /etc/hal/fdi/policy/10-networking-ath0.fdi containing the following:

<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
<device>
<match key="net.interface" string="wlan0">
<append key="info.callouts.add" type="strlist">/etc/hal/callouts/eee-wifi</append>
</match>
</device>
</deviceinfo>


This adds our script as a "callout" for wlan0 -- hal's notion of an event handler. hal will invoke our script when wlan0 comes or goes, and set HALD_ACTION appropriately.

Restart hal (or killall -HUP hald) and try loading or unloading the Atheros drivers. ath0 should be created and destroyed automatically. (Make sure the ath0 interface is down when you do this.)

Letting NetworkManager configure ath0



For NetworkManager to configure an interface, a few conditions must be met:

  1. hal must see the interface and recognize it correctly (e.g. seeing ath0 as a wired Ethernet connection is not good);

  2. The interface must not be configured in /etc/network/interfaces. If you currently have a stanza configuring ath0 or wlan0, remove it.



First things first. Modify the 10-networking-ath0.fdi policy we created in the last step by adding the code marked below:

<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
<device>
<match key="net.interface" string="wlan0">
<append key="info.callouts.add" type="strlist">/etc/hal/callouts/eee-wifi</append>
<merge key="info.capabilities" type="strlist">net</merge>
<append key="info.capabilities" type="strlist">net.80211</append>
<merge key="info.category" type="string">net.80211</merge>
<merge key="net.interface" type="string">ath0</merge>
<merge key="net.80211.mac_address" type="copy_property">net.80203.mac_address</merge>
<remove key="net.80203.mac_address"></remove>
<merge key="linux.sysfs_path" type="string">/sys/class/net/ath0</merge>

</match>
</device>
</deviceinfo>

Note: special thanks to "Triarm" on the eeeuser forums for pointing out this approach.

Line by line, this does the following:

  1. Replaces wlan0's info.capabilities property with the single item "net", indicating that it's a network interface.

  2. Appends "net.80211", indicating that it's a wireless interface.

  3. Changes the device's category, again to indicate that it's a wireless interface.

  4. Switches the entry to refer to ath0, instead of wlan0.

  5. Copies the 802.3 (wired Ethernet) MAC address to the 802.11 MAC address (I'm surprised that these are separate).

  6. Removes the old 802.3 MAC address.

  7. Rewrites the entry's sysfs path to point to ath0's.



To sum up, at this point we have:

  1. Instructed hal to invoke our callout when wlan0 is added or removed, thereby automagically creating/destroying ath0.

  2. Rewritten the device descriptor for wlan0 to describe ath0 (which is unfortunately not picked up automatically by hal).

  3. Removed wlan0/ath0 configuration from /etc/network/interfaces. (You remembered that, right?)



Bring NetworkManager down, restart or HUP hald, and bring NetworkManager back up. (The control script for NetworkManager on Ubuntu 7.10 is at /etc/dbus-1/event.d/25NetworkManager.)

Assuming I haven't forgotten anything, NetworkManager should now offer to configure your wireless, and the interface should show up in configurators like nm-applet.

If it doesn't work, try rebooting. (I know it's lame to say that, but the Atheros drivers are incredibly sensitive and can get into weird states that make your interface stop working, usually after you remove/readd them or suspend/resume. I have a magic dance that repairs the driver, but it's lengthy so I'll post it in a followup.)

Labels: ,

19 Comments:

Post a Comment

<< Home