Skip to content

Controlling Bluetooth DUN with upstart on the n900

Wow, it’s been a long time since I posted anything. But I’ve got something worth coming out of hibernation for.

Perhaps, unsurprisingly, I got myself an n900 and it’s a great device; I’m using it as my primary phone and it really is impressive.

One thing that doesn’t work out of the box is DUN (Dial-Up Networking) over Bluetooth. DUN is one of the simplest ways to tether a computer to a phone, so it’s a useful feature to have. (The n900 does support DUN over USB by default). Fortunately, it’s very easy to turn on, as documented on the maemo wiki. However, if you want the feature to always be ready to go (say, after you restart your phone), you need to do a little more.

Like modern versions of Ubuntu, the n900 with Maemo 5 uses upstart to control most startup services, such as bluetooth. So, if we want the DUN service to be nicely coordinated, we should start it with upstart too. Here’s my script:


description "DUN over Bluetooth"
author "Philip Langdale"

respawn
console none

start on started bluetoothd
stop on stopping bluetoothd

pre-start script
sdptool add --channel 1 DUN
end script

exec rfcomm -S -- listen -1 1 /usr/bin/pnatd '{}'

post-stop script
sdptool del `sdptool browse local | grep Dial-Up -A 1 -m 1 | tail -n 1 | cut -d ' ' -f 3`
sleep 1
end script

So, what is this doing? As upstart is pretty new, and quite different from old style init-scripts, it’s worth explaining a bit.

The description and author fields are just for documentation. respawn means to restart if the main process exits. console none means don’t log stdout or stderr anywhere.

Now, the start on and stop on directives are the heart of Upstart. They allow you to express dependencies between services, events, and each other. In this case, we want to start the DUN server after bluetoothd is started and stop it as soon as we start stopping bluetoothd. You can express multiple start and stop conditions and the upstart site documents these.

With that done, we can move on to the functional code. From the wiki page, we see that the invocation of rfcomm is the key call. What happens here is rfcomm will wait for an incoming connectio request on channel 1 and then spawn pnatd and connect it to that channel. When the connection is complete, pnatd will exit and then rfcomm will too. Upstart either tracks a particular binary or a script. In either case, it execs the binary or script and watches the resulting process to see when it exits. So, we can conveniently transfer the rfcomm command line to an upstart exec directive.

However, there’s more to do. We have to register the service with sdpd so that clients know we offer DUN, and we have to unregister when the service is terminated. This can be done with the pre-start and post-stop blocks. This also gives us a place to enforce the one second delay suggested by the example script.

Registering the service is easy, but unregistering it is a bit of a chore. The example script can avoid it because it uses the while loop, but for upstart, the entire service is ‘inside’ the loop, so we must unregister to avoid adding an extra registration each time. The problem arises because you can only unregister by the service record ID which is selected at registration time, but not provided back to us. So, we must look for it ourselves. The long command line searches the list of services for DUN and then extracts the ID.

Now, all you have to do is drop the script into /etc/event.d/ and then execute start bluetooth-dun, assuming you name the script “bluetooth-dun”. Obviously, you must be root for both these steps.

You can download the script from here. I’ll probably package it up as a deb in due course, but I don’t have a working scratchbox environment right now.

Enjoy!

Update: It seems that it’s not perfect yet. I’ve had a report, and reproduced, it failing to start when the phone boots, even though it starts reliably if you stop/start bluetoothd. My suspicion is that there’s an additional dependency (maybe the rfcomm kernel module) that needs to be accounted for. I will investigate.

{ 7 } Comments