Sunday 14 November 2010

Bluetooth 3G Modems on Debian Linux: Chatscripts and rfcomm bluez

I've been using 3G mobile broadband to my primary Internet connection for a couple of years now, and ever since I moved out of college it has become my only Internet connection at home - It's saved me the cost, delays and headache of dealing with Telstra to sort out some kind of wired link.

In my particular setup I removed the 3G data SIM card from the USB modem that came with my plan and placed it in my Nokia N900, which I use as a bluetooth modem for my various computers (my N95 used to fill this role) as well as having the convenience of having the N900 itself connected wherever and whenever I want.

Every now and again I get asked about my setup - a lot of people seem to have had trouble setting up bluetooth modems in Linux. This is understandable - last time I checked out Network Manager I found that it could set up a USB 3G modem pretty easily but had zero provisions to set up a bluetooth modem, and the Linux bluetooth stack (bluez) also leaves something to be desired (try using bluez 4 to pair to something without X... fail). I've previously been directing these people to some posts I made on the CLUG mailing list that had my configuration files, but it's clear that it will be easier to direct people to a blog post.

The quickstart guide for those people would be scan this post, grab the file excerpts and place them where they belong, restart bluetooth and run the pon <profile> command to try to bring up the 3G connection. Then when that inevitably doesn't work read the rest of the article to figure out what you need to change to make it work. I should note that I'm using Debian so some of this article may not apply to other non Debian derived distributions (the pon and poff commands came from Debian, for example)

Firstly, a little background on the technical details we care about: 3G modems provide PPP (Point-to-Point Protocol) links to your ISP, just like the dial-up modems of old did. We even use the same protocol and method to talk to them that we used to use to talk to dial-up modems - the AT command set over some kind of serial like interface (itself encapsulated in a USB or bluetooth link).

A few things have changed though - for one they are much faster than dial-up modems. Authentication is also handled differently - we no longer (typically) use a username and password, instead handling the authentication in the SIM card. And instead of calling a phone number for your local ISP, we instead call a special number (such as *99#) to establish the link. Added to this, we now also have something called an APN (Access Point Name) to identify the IP packet data network that we want to communicate with.

There are a few important consequences of all of this. Firstly, we are using the same infrastructure (ppp, chatscripts, wvdial, ...) in Linux to connect to 3G that we used to use to connect old dial-up connections. Secondly, despite not requiring a username and password any more we still have to provide something in their stead to make everything happy even though they are ignored. We also still have the same nonsense of every ISP having a subtle difference in their authentication that affects how we connect to them. There can also be subtle differences in the AT commands we need to communicate with different modems to get them to do what we want.

Some people like using wvdial to establish their ppp links. If that works for you that's great, but my experience has been that wvdial fails in many circumstances, and getting it to work in those cases is quite often impossible, so I'm going to cover a much more tunable back to basics method: ppp + chatscripts + rfcomm.

Firstly, make sure ppp is installed (apt-get install ppp)... I hope you have some other connection than your 3G link to get that... Perhaps whatever you are reading this blog on?

We'll start with a USB connection - no sense adding the extra complexities of a bluetooth link to the mix until we have that working. I'll show the profiles I use for both the Huawei E220 USB modem that came with the plan and the USB link to my N900 (or N95).

We need two configuration files for each profile - the configuration for the ppp side of the link goes under /etc/ppp/peers/<profile> and the chatscript which tells the modem how to establish the ppp link under /etc/chatscripts/<profile>. The chatscript is referenced from the ppp configuration file, so it is possible to use one chatscript for multiple profiles, assuming the profiles are talking to the same modem (or at least that one modem doesn't require special treatment) and using the same APN.

The chatscript is responsible for initialising the modem and getting the connection to the point where pppd can take over, so I'll start with that. Here's the chatscript that I use for my Nokia N900 (USB and bluetooth), Nokia N95 and Huawei E220 USB mdoem:

/etc/chatscripts/optus-n900
ABORT BUSY
ABORT ERROR
ABORT 'NO CARRIER'
REPORT CONNECT
TIMEOUT 10
"" "ATZ"
OK "ATE1V1&D2&C1S0=0+IFC=2,2"
OK AT+CGDCONT=1,"IP","<APN>"
OK "ATE1"

OK "ATDT*99#"

CONNECT \c

IMPORTANT: Replace <APN> with the APN for your connection (for me on Optus post-paid mobile broadband that is "connect", for Lucy on Three pre-paid mobile broadband that is "3services" - refer to the documentation that came with your plan to find out what it is for you). If you don't you will run into inexplicable problems later.

I said above that some modems need to be treated specially in the chatscript. I used to have to use this on my Huawei E220 because I could not find one script that would satisfy both it and my N95 (the AT+IPR line below was necessary for the E220, but caused the N95 to fail), but the differences no longer seem to be necessary (firmware upgrade? Some other change I made and forgot about? Phase of the moon? I can't recall), but it might help someone so here it is:

/etc/chatscripts/optus-huawei
ABORT BUSY
ABORT ERROR
ABORT 'NO CARRIER'
REPORT CONNECT
TIMEOUT 10
"" "ATZ"
OK AT+CGDCONT=1,"ip","connect"
OK "ATE1V1&D2&C1S0=0+IFC=2,2"
OK "AT+IPR=115200"

OK "ATE1"

TIMEOUT 60
"" "ATD*99#"

CONNECT \c

Now we need a profile for ppp that references that chatscript and contains all the settings necessary to establish a successful ppp link. I have a number of these for different profiles, depending on which modem I'm using and whether I'm using my Optus link or Lucy's Three link, but they all pretty similar and include some common elements, so I'll just show one combined file with comments for differences between them. All these options and more are described in man pppd:

/etc/ppp/peers/<profile>
# This can help track down problems:
#debug

# The modem device to talk to:
/dev/ttyACM0 # N900/N95 USB
#/dev/ttyUSB0 # Huawei USB
#/dev/rfcomm0 # N900 Bluetooth

# In some cases it may be necessary to specify a baud rate,
# but generally it's best to let ppp detect this:
#115200
#230400
#460800
#... etc

# Optus requires both of these options, Three requires neither.
# Other ISPs may have different authentication requirements:
refuse-chap
require-pap

# When to detach from the console:
updetach
#nodetach

# These are generally necessary:
crtscts
noauth
noipdefault

# If the connection drops out try to reopen it:
persist

# We want this to be the default internet connection:
defaultroute
replacedefaultroute

# Get DNS settings from the ISP:
usepeerdns

# not used, but we must provide something:
user "na"
password "na"

# Playing with these compression options *may* improve
# performance, but get it working first:
noccp
nobsdcomp
novj
#nodeflate

#What chatscript we are using in this profile:
connect "/usr/sbin/chat -s -S -V -f /etc/chatscripts/optus-n900"
#connect "/usr/sbin/chat -s -S -V -f /etc/chatscripts/optus-huawei"


Got that? Great, let's give it a go! Connect your modem by USB, do whatever magic incantations you need to get your modem to reveal it's modem aspects to Linux (for Nokia phones this is usually select the PC suite mode when you plug it in, some people report having to do strange things with kernel modules and udev to poke their Huawei E220 modems, though I have never found that necessary myself), shutdown your network manager and run this in a terminal:

pon <profile>

All going well hopefully you will see some output like this:

ATZ
OK
ATE1V1&D2&C1S0=0+IFC=2,2
OK
AT+CGDCONT=1,"IP","connect"
OK
ATE1
OK
ATDT*99#
CONNECTchat: Nov 14 13:12:13 CONNECT
Serial connection established.
Using interface ppp0
Connect: ppp0 <--> /dev/rfcomm0
PAP authentication succeeded
Cannot determine ethernet address for proxy ARP
local IP address www.xxx.yyy.zzz
remote IP address 10.6.6.6
primary DNS address 211.29.132.12
secondary DNS address 61.88.88.88

Obviously the exact output will vary, but usually if you see some IP and DNS addresses you have successfully connected. Otherwise you really should try to get this working before continuing to the bluetooth part. If you got as far as the CONNECT... "Serial connection established." your modem and chatscripts are probably working (assuming you APN in the chatscript is correct) and you may need to look at the ppp configuration, though you might just try a few times first - sometimes my connections take a few attempts to come up successfully.

If you haven't got as far as the CONNECT you'll need to check your modem, coverage and chatscripts to try to locate the problem. Also double check that you have specified the correct device in the ppp configuration. If you are using a phone as your modem you might try rebooting it. If you get a NO CARRIER you are likely out of coverage or your modem couldn't connect to a nearby base station for some other reason (such as it being full), though the symptoms for that are unfortunately not always consistent - failing to connect to the modem at all can also be a symptom of that (and a host of other possible causes) for instance.

There's just too many things that can go wrong by this point for me to cover here. Google is your friend. You may be able to find other people's chatscripts and ppp configuration for your modem and/or ISP that you could try.

Now you've successfully got a connection with ppp + chatscripts it's time to add bluetooth into the mix. Serial connections over bluetooth are handled with the rfcomm protocol. They are controlled with the rfcomm program and once bound show up as /dev/rfcomm0 and similar. A device can have different serial services listening on different rfcomm "channels" (like IP ports), and there is no guarantee for which services appear on which rfcomm channel. My Nokia N95 reveals it's modem on rfcomm channel 2 and it's GPS on rfcomm channel 5 (via ExtGPS), while my N900 reveals it's modem on rfcomm channel 1 (In fact it is actually running rfcomm -S -- listen -1 1 /usr/bin/pnatd {}). You can use an rfcomm scanner like rfcomm_scan from Collin Mulliner's BT Audit suite or do some trial and error to find the channel you need (there's only 30 channels and it's usually a low number).

Add a section like the following to your /etc/bluetooth/rfcomm.conf:

/etc/bluetooth/rfcomm.conf:
rfcomm0 {
 bind yes;
 device AA:BB:CC:DD:EE:FF;
 channel 1;
 comment "N900 Data";
}

Replacing the bluetooth address and channel number as appropriate. Then tell rfcomm to bind rfcomm0 to this device with rfcomm bind 0 (this will also happen automatically at boot).

You should now see a new file /dev/rfcomm0 which we use to communicate with the modem over bluetooth. You should make a copy of the /etc/ppp/peers/<profile> you were using to connect over bluetooth and change the new profile to use /dev/rfcomm0.

Now, we need to pair the devices together and tell the phone to trust the computer to connect whenever it wants. Pairing in bluez is still a bit hairy, particularly if you aren't using KDE or GNOME (like me) which provide their own bluez agents. In that case you don't have many options available to you. Bluez 3 used to have a hack in which you could specify a PIN to pair with under /var/lib/bluetooth/<device>/pincodes to allow pairing without an agent, however that does not work in bluez 4. Bluez provides an example console agent in the examples directory, but I have never managed to get it to work reliably with bluez 3 or bluez 4, so we now need a bluez agent, which lacking any decent console/curses agents means we need X (FAIL). This nonsense is now true even of HID devices which could previously be paired and activated with a simple hidd --search, which now doesn't trust them to re-pair to the computer so they stop working as soon as they start power saving (FAIL). Sigh, one day I'll get around to writing a decent ncurses bluez agent if no one beats me to it, but I digress.

If you aren't using GNOME or KDE you might try using the GTK bluez agent blueman instead. You'll need to have it's system tray applet (blueman-applet) running for blueman-manager to work properly (FAIL - I don't have a system tray. At least it doesn't actually need to show the tray icon to work, though if you want that "trayer" or "stalonetray" can be used to provide a temporary system tray).

Anyway, once you have some kind of bluez agent running, be it KDE's kbluetooth, gnome-bluetooth or blueman you can try to pair your phone. I say "try" because even with an agent, pairing with bluez is still hairy. In theory running the pon <profile> command will attempt to open the bluetooth link and initiate pairing, causing both phone and computer to ask for a PIN to authenticate each other - enter the same on each. If you're really lucky they might even remember that they have been paired so you don't have to do it again the next time. If you're unlucky and that didn't work you can try deleting any existing pairing from the computer and phone then using your bluetooth agent's interface to initiate a pairing. Rebooting and walking around your computer in circles while chanting "all hail bluez" over and over may also help - I wish you luck.

The good news is that you only need the bluez agent while pairing - once you successfully pair and manage to get the 3G link up (and down and up a second time to make sure it remembered what to do) you usually don't have to touch bluez again and things get a lot easier. Unless one of the devices pairings get lost or confused... Or your bluetooth address changes, or ...

Hopefully by this stage you have successfully managed to pair your computer and phone you should be able to use the pon and poff commands to bring the connection up and down as above. Congratulations, you're done! You can stop reading now. If you are getting a "host is down" error you have not successfully paired or the bluetooth link has otherwise failed. Another symptom of (non-pairing) bluetooth related problems that I've seen was getting no OK response after the initial ATZ. If you are pairing OK but only getting partway through the connection sequence you may have to go back to debugging your chatscripts and ppp options like I talked about above.


The (broadcom) bluetooth dongle I use on my EeePC introduces another complexity to the process - every time it is plugged in a couple of bits in it's bluetooth address change at random for no good reason (check with hciconfig), which as you can imagine makes it rather hard to maintain a pairing between it and anything else. I've also come across some (broadcom) bluetooth dongles with a bluetooth address of 00:00:00:00:00:00. Oddly enough, very few devices like pairing with them, and fewer still will re-pair with them automatically. If you have this problem tell broadcom they suck buy a CSR dongle you might try the dbaddr utility in the bluez source to force them to use a particular bluetooth address (if they support changing it through software, which of course is no guarantee). The script I use on my EeePC to connect shuts down my network manager and any running DHCP client, changes the bluetooth address on the dongle and opens the 3G connection:

/etc/init.d/wicd stop
killall dhclient
killall dhclient3

/usr/local/sbin/dbaddr AA:BB:CC:DD:EE:FF
hciconfig hci0 reset

pon optus-blue

No comments: