Note: Modification of this text is now a Bluetooth chapter of The FreeBSD Handbook.
I purchased an Anycom bluetooth USB dongle and here is my experience with making it work under FreeBSD.
The Bluetooth stack is developed only for the 5-CURRENT branch. I suggest you to track -CURRENT, but you can use 5.1-RELEASE if you want. Bluetooth support is now integrated in FreeBSD CVS tree. If you run 5.0-RELEASE, I suggest you to upgrade to 5.1-RELEASE or -CURRENT.
Some userland utilities are not in FreeBSD CVS tree. You want to download latest snapshot from Maksim Yevmenkin's site, build new libbluetooth from src/lib/libbluetooth and then build ports subdirectory manually:
make && make install && make cleandir
Edit your /boot/loader.conf
and add the line
ng_ubt_load="YES"
Reboot. You should now have a working Bluetooth stack. Plug in your USB dongle and watch this on your console (or syslog):
ubt0: vendor 0x0a12 product 0x0001, rev 1.10/5.25, addr 2 ubt0: Interface 0 endpoints: interrupt=0x81, bulk-in=0x82, bulk-out=0x2 ubt0: Interface 1 (alt.config 5) endpoints: isoc-in=0x83, isoc-out=0x3; wMaxPacketSize=49; nframes=6, buffer size=294
In the archive you downloaded, there is a rc.bluetooth
in src/share/examples
directory.
Copy it to some convenient place, like /etc/rc.bluetooth
. This script is used to start and stop
the Bluetooth stack. It's a good idea to stop the stack before unplugging the device. But it's not (usually) fatal.
Start the stack. You will receive output similar to this:
# /etc/rc.bluetooth start ubt0 BD_ADDR: 00:02:72:00:d4:1a Features: 0xff 0xff 0xf 00 00 00 00 00 <3-Slot> <5-Slot> <Encryption> <Slot offset> <Timing accuracy> <Switch> <Hold mode> <Sniff mode> <Park mode> <RSSI> <Channel quality> <SCO link> <HV2 packets> <HV3 packets> <u-law log> <A-law log> <CVSD> <Paging scheme> <Power control> <Transparent SCO data> Max. ACL packet size: 192 bytes Number of ACL packets: 8 Max. SCO packet size: 64 bytes Number of SCO packets: 8
Problem: My kernel spits out these lines when starting rc.bluetooth
:
Mar 26 11:18:34 tylendel kernel: link_elf: symbol _mtx_assert undefined Mar 26 11:18:34 tylendel nomad[576]: Failed to load ng_btsocket
Solution: Your kernel options do not match the snapshot Makefile options. Either edit the module Makefile in snapshot
and remove -DWITNESSxxx
and -DINVARIANTSxxx
,
or add options WITNESS, options WITNESS_SKIPSPIN,
options INVARIANTS and options INVARIANTS_SUPPORT
to your kernel configuration.
Those options are used to catch locking bugs.
Problem: I plug in the USB Bluetooth device and I get this:
kernel: uhub0: device problem, disabling port 1
Solution: There is no solution. The USB stack did not attach and activate your device. This is not a Bluetooth problem. This seems to occur when the device is connected via USB hub. To find out if you have an extra hub, run:
# usbdevs -v -d Controller /dev/usb0: addr 1: full speed, self powered, config 1, UHCI root hub(0x0000), Intel (0x0000), rev 1.00 uhub0 port 1 powered port 2 addr 2: full speed, self powered, config 1, UT-USB41 hub(0x1446), Texas Instruments(0x0451), rev 1.00 uhub1 port 1 powered port 2 powered port 3 powered port 4 powered
Here, Maksim's notebook Toshiba Tecra 8100 in the docking station, has an extra hub (addr 2). The only solution is to plug the Bluetooth device directly into the root hub (into notebook).
Now it's time to discover some nearby bluetooth devices. I used my Ericsson T39 mobile phone for all examples.
Discovering devices and many other interesting tasks is done with the hccontrol
utility.
You shall receive a list of discoverable devices in a few seconds:
$ hccontrol -n ubt0hci inquiry Inquiry result, num_responses=1 Inquiry result #0 BD_ADDR: 00:80:37:29:19:a4 Page Scan Rep. Mode: 0x1 Page Scan Period Mode: 00 Page Scan Mode: 00 Class: 52:02:04 Clock offset: 0x78ef Inquiry complete. Status: No error [00]
BD_ADDR is the unique address of bluetooth device, similar to MAC addresses of network cards. You will need this address for further communication with a device. Let's try to read the device's name:
$ hccontrol -n ubt0hci remote_name_request 00:80:37:29:19:a4 0 0 0 BD_ADDR: 00:80:37:29:19:a4 Name: Pav's T39
Now try to perform a discovery on your mobile phone (or any other device). You should find your computer as
your.host.name (ubt0)
. You can try a simple connection with your phone:
# hccontrol -n ubt0hci create_connection 00:80:37:29:19:a4 BD_ADDR: 00:80:37:29:19:a4 Connection handle: 41 Encryption mode: Disabled [0]
The connection handle is important here, as you will need it for any further handling of the connection. Don't panic if you forget it, you can list active raw connections anytime:
$ hccontrol -n ubt0hci read_connection_list Remote BD_ADDR Handle Type Mode Role Encrypt Pending Queue State 00:80:37:29:19:a4 41 ACL 0 MAST NONE 0 0 OPEN
Reading quality of connection:
$ hccontrol -n ubt0hci get_link_quality 41 Connection handle: 41 Link quality: 255
It's on the maximal possible quality. Well, both devices are some two feet apart from each other, so it's no big surprise. :)
Try hccontrol help
for list of all commands. Now disconnect:
# hccontrol -n ubt0hci disconnect 41 Connection handle: 41 Reason: Connection terminated by local host [0x16]
L2CAP is a higher level of connection in Bluetooth standards. The most interesting command is l2ping
,
which can be used to ping other devices:
# l2ping -a 00:80:37:29:19:a4 0 bytes from 0:80:37:29:19:a4 seq_no=0 time=48.633 ms result=0 0 bytes from 0:80:37:29:19:a4 seq_no=1 time=37.551 ms result=0 0 bytes from 0:80:37:29:19:a4 seq_no=2 time=28.324 ms result=0 0 bytes from 0:80:37:29:19:a4 seq_no=3 time=46.150 ms result=0
The l2control
utility is used to configure L2CAP connections:
$ l2control -a 00:02:72:00:d4:1a read_connection_list L2CAP connections: Remote BD_ADDR Handle Flags Pending State 00:80:37:29:19:a4 41 0 OPEN
Another diagnostic tool is btsockstat
.
It does a similar job as hccontrol read_connection_list
does,
but on a higher level - it prints Bluetooth sockets, logical connections on top of HCI raw connections.
Here is a dial-up connection (over a RFCOMM socket):
$ btsockstat Active L2CAP sockets PCB Recv-Q Send-Q Local address/PSM Foreign address CID State c2ae2900 0 0 00:02:72:00:d4:1a/3 00:80:37:29:19:a4 68 OPEN c238e200 0 0 */3 * 0 LISTEN Active RFCOMM sockets PCB Recv-Q Send-Q Local address Foreign address Chan DLCI State c266c400 0 0 00:02:72:00:d4:1a 00:80:37:29:19:a4 1 2 OPEN
By default, Bluetooth communication is not authorized and any device can talk to any other device.
Some devices, like mobile phones, requires authentication for some functionality, like Internet connections.
This is done with PIN numbers - you enter the same (up to 16 digits long) number on both devices.
This operation is called pairing.
The daemon that answers pairing requests is hcsecd
.
Copy over src/usr.sbin/bluetooth/hcsecd/hcsecd.conf
to /usr/local/etc
and edit it. Section for my mobile phone, with the PIN arbitrary set to 1234:
device { bdaddr 00:80:37:29:19:a4; name "Pav's T39"; key nokey; pin "1234"; }
You can choose any PIN you like. Note that some devices, like headsets, have a fixed PIN built in. If you're originating pairing from PC, you need to turn on authentication:
# hccontrol -n ubt0hci write_authentication_enable 1 # hccontrol -n ubt0hci read_authentication_enable Authentication Enable: Enabled [1]
If you're originating pairing on remote device, this is not necessary.
Now, start hcsecd -d
. The -d switch is to force the daemon to stay in the terminal
and not fork to the background, so you can see what's happening.
Set the phone to receive pairing and initiate the HCI connection to the remote device.
The phone should say that pairing was successful, and let you enter the PIN. Enter the same PIN as you have in your
hcsecd.conf
. Now your PC and phone is paired.
This will appear in hcsecd
output:
hcsecd[16484]: Got Link_Key_Request event from 'ubt0hci', remote bdaddr 0:80:37:29:19:a4 hcsecd[16484]: Found matching entry, remote bdaddr 0:80:37:29:19:a4, name 'Pav's T39', link key doesn't exist hcsecd[16484]: Sending Link_Key_Negative_Reply to 'ubt0hci' for remote bdaddr 0:80:37:29:19:a4 hcsecd[16484]: Got PIN_Code_Request event from 'ubt0hci', remote bdaddr 0:80:37:29:19:a4 hcsecd[16484]: Found matching entry, remote bdaddr 0:80:37:29:19:a4, name 'Pav's T39', PIN code exists hcsecd[16484]: Sending PIN_Code_Reply to 'ubt0hci' for remote bdaddr 0:80:37:29:19:a4
A little cleanup: set authentication back to "not required" and kill hcsecd:
# hccontrol -n ubt0hci write_authentication_enable 0 # killall hcsecd
You can pair in opposite direction too (originating pairing on the phone). If your phone (like my Ericsson T39) does not support role switching, consult the section Phone can't connect to me below.
If you want to know which services a Bluetooth device offers, and on which RFCOMM channels, build libbluetooth
and sdp-1.0rc3
from ports
directory. Then, run sdptool
and observe (the output snipped a bit, as this tool is quite talky):
# sdptool browse 00:80:37:29:19:a4 Browsing 00:80:37:29:19:A4 ... Service Name: Dial-up Networking Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 1 Service Name: Fax Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 2 Service Name: Voice gateway Service Class ID List: "Headset Audio Gateway" (0x1112) "Generic Audio" (0x1203) Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 3
... and so on. You will need the channel number later for using a given service. Some devices does not support browsing, they return an empty list, but you can try searching for a specific service. Example is my Palm m125 and the OPUSH service:
# sdptool search --bdaddr 00:07:e0:00:0b:ca OPUSH
We will use the ordinary ppp
command to connect, with rfcomm_pppd
, a wrapper
that convert RFCOMM Bluetooth connections to something ppp
can handle. You will need to configure
ppp
. Open the rfcomm_pppd
man page, there are some good examples of ppp
configurations there. Copy the rfcomm-dialup
section to /etc/ppp/ppp.conf
.
I raised the timeout from the example's 30 seconds to 10 minutes (600 seconds), and added
set nat enable
to enable sharing of my Bluetooth Internet connection on my home network.
(Note: to use NAT you have to turn on the net.inet.ip.forwarding
sysctl.)
If you have your phone paired with your PC, you should be ready to connect:
# rfcomm_pppd -a 00:80:37:29:19:a4 -c -C 1 -d -l rfcomm-dialup
where -a 00:80:37:29:19:a4
is the BD_ADDR of your phone, -C 1
is RFCOMM Channel
of the DUN service on the phone, -l rfcomm-dialup
selects rfcomm-dialup section from ppp.conf
and -d
again prevents ppp
to detach from terminal and become a daemon.
To disconnect, simply kill rfcomm_pppd
. Note that this will disconnect you from Internet,
but Bluetooth connection to your phone is still up and running.
OBEX is a widely used protocol for simple file transfers between devices. It's main use is in infrared communication, where it's used for generic file sending between notebooks, or Palm handhelds, and for sending contact cards or calendar entries between mobile phones and other devices.
The OBEX client is implemented in the obexapp
utility.
It needs the openobex
library from snapshot
and the devel/glib12
library from the FreeBSD ports collection.
First, find which channel on remote device is
IrMC Synchronization
. On my Ericsson T39 it's channel 11. I was able to use service
OBEX Object Push
(channel 10) too. Implementation of OBEX widely differs from phone to phone.
Some commonly used remote filenames are in the obexapp manual page.
Note that obexapp
does not require root privileges to operate.
Now, start obexapp
in client mode.
We're going to download device info from the phone and send one new card to the phone directory:
$ obexapp -a 00:80:37:29:19:a4 -C 10 obex> get get: remote file> telecom/devinfo.txt get: local file> devinfo-t39.txt Success, response: OK, Success (0x20) obex> put put: local file> new.vcf put: remote file> new.vcf Success, response: OK, Success (0x20) obex> di Success, response: OK, Success (0x20)
Now let's send items in the opposite direction, from phone to PC. You'll need to compile sdp-1.0rc3
from the snapshot. SDP (Service Discovery Protocol) is used to announce our services
to other devices. We already described it when we was searching for the channel number of the DUN profile earlier in
this article. Here we will start a local SDP daemon and configure it:
# sdpd # sdptool add --channel=10 OPUSH
If OPUSH does not work, you should try FTRN instead. You can check configuration of SDP daemon by browsing this magic address:
# sdptool browse ff:ff:ff:00:00:00 Browsing FF:FF:FF:00:00:00 ... Service Name: SDP Server Service Description: Bluetooth service discovery server Service Provider: BlueZ [...] Service Name: OBEX Object Push Service RecHandle: 0x80541d0 Service Class ID List: "OBEX Object Push" (0x1105) Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 10 "OBEX" (0x0008) Profile Descriptor List: "OBEX Object Push" (0x1105) Version: 0x0100
Note the RFCOMM channel and Service RecHandle. RecHandle is needed to remove service from a sdpd configuration. Now start the OBEX daemon using the channel number registered with sdpd:
# obexapp -s -C 10
And now you should be able to send items from the phone to your PC. Received items will appear in
/var/spool/obex
, so make sure this directory exists, or override it with
-r
switch.
I had successfully sent and received these items from/to my Ericsson T39: contacts, tasks, appointments, background wallpaper, ring tone (both directions) and SMS messages as print job (from phone to PC).
Bluetooth can be used to emulate serial port connections. To connect to a remote device, first locate the RFCOMM
channel with the Serial Port profile. Then, start the Serial Port Profile Daemon rfcomm_sppd
with a free pseudo tty:
# rfcomm_sppd -a 00:07:E0:00:0B:CA -c 1 -t /dev/ttyp6 rfcomm_sppd[94692]: Starting on /dev/ttyp6...
Now connect this pseudo tty to your actual terminal:
# cu -l ttyp6
Some devices, like my Ericsson T39 phone, does not support role switching. By default, when the PC is accepting a connection, it tries to switch roles to become master. These devices will not be able to connect. Role switching is performed when connection is being established, so we can't ask remote device if it does support role switching. But we can disable role switching on our side with this option:
# hccontrol -n ubt0hci write_node_role_switch 0
This option is new in 20030407 snapshot.
I'm the owner of a Palm m125 handheld and Bluetooth SDIO card. Pairing of a Palm with FreeBSD works fine. Sending
files from FreeBSD to Palm is done using OBEX Push. You have to search for channel using sdptool
, Palm does not support SDP browsing. Channel for sending files is 3 on my Palm, but it
changes from time to time. I can send diary items and prc/pdb files to the Palm's memory using obexapp
and connecting to service None. After file is transfered, I have to manually kill the
baseband connection to Palm using hccontrol disconnect
to get rid of Disconnecting... window
on Palm. The FreeBSD stack intentionally leave baseband connection opened where other stacks and devices close it.
There will be an auto-disconnect functionality in the next snapshot.
You can send files from Palm to FreeBSD using sdpd
and obexapp
same way as when we was sending business cards from the cell phone. Apply this patch to ports/sdp-1.0rc3/tools/sdptool.c
, otherwise you'll
not be able to send databases. Builtin PIM applications allows you to send business cards, todo items etc. Builtin
Launcher in Palm allows you to send only programs over Bluetooth, if you want to send any database, you will have to buy
some launcher replacement or file manager, like ZLauncher 3.
I would like to thank a lot to Maksim Yevmenkin <Maksim.Yevmenkin@cw.com>
, who wrote Bluetooth
stack for FreeBSD, and who provided me with useful hints and excellent support.
Surprisingly quickly someone made japanese translation of this page. Thanks.
How to connect two computers over Bluetooth
FreeBSD on IBM ThinkPad T40p notebook
Last revision: Sun 24 Aug 2003 19:19:48 GMT