19.16 Bluetooth

Written by Pav Lucistnik.

19.16.1 Introduction

Bluetooth is a wireless technology for creating personal networks operating in the 2.4 GHz unlicensed band, with a range of 10 meters. Networks are usually formed ad-hoc from portable devices like mobile phones, handhelds and laptops. Unlike the other popular wireless technology, Wi-Fi, Bluetooth offers higher level service profiles, e.g. FTP-like file servers, file pushing, voice transport, serial line emulation and more.

The Bluetooth stack in FreeBSD is implemented using the Netgraph facility (see netgraph(4)). A Broad variety of USB dongles is supported by the ng_ubt(4) driver. The 3Com PC Card 3CRWB60-A is supported by the ng_bt3c(4) driver. Serial and UART based Bluetooth devices are supported via ng_h4(4) and hcseriald(8). This chapter describes using a USB Bluetooth dongle. Bluetooth support is available in FreeBSD 5.0 and newer systems.

19.16.2 Plugging in the Device

Device drivers are by default available as kernel modules. Before attaching a device, you need to load the driver into the kernel:

# kldload ng_ubt

If the Bluetooth device is present in the system during system startup, load the module from /boot/loader.conf:

ng_ubt_load="YES"

Plug in your USB dongle. Similar output will appear on the console (or in 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

Copy /usr/src/share/examples/netgraph/bluetooth/rc.bluetooth to some convenient place, like /etc/rc.bluetooth. This script is used to start and stop the Bluetooth stack. It is a good idea to stop the stack before unplugging the device, but it is not (usually) fatal. When starting 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

19.16.3 HCI and Inquiry

Now it is time to discover some nearby Bluetooth devices. Tasks like discovering devices, and such are done with the hccontrol(8) utility. You will 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 a Bluetooth device, similar to MAC addresses of network cards. This address is needed for further communication with a device. Let us 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

If you perform a discovery on a different Bluetooth device, it will find your computer as ``your.host.name (ubt0)''.

You can list active baseband connections:

% 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

Handle is useful for manually disconnecting a connection:

# hccontrol -n ubt0hci disconnect 41
Connection handle: 41
Reason: Connection terminated by local host [0x16]

Refer to hccontrol help for a complete listing of available commands. Note that the majority of commands does not require superuser privileges.

19.16.4 L2CAP

L2CAP is a higher level of connection in Bluetooth standards. A useful command is l2ping(8), which can be used to ping other devices. Some devices might not return all of the data send to them, so 0 bytes as in this example is a normal state.

# 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(8) utility is used to configure L2CAP nodes and read their state. This example shows file transfer to a Palm handheld:

% l2control -a 00:02:72:00:d4:1a read_channel_list
L2CAP channels:
Remote BD_ADDR     SCID/ DCID   PSM  IMTU/ OMTU State
00:07:e0:00:0b:ca    66/   64     3   132/  672 OPEN
% l2control -a 00:02:72:00:d4:1a read_connection_list
L2CAP connections:
Remote BD_ADDR    Handle Flags Pending State
00:07:e0:00:0b:ca     41 O           0 OPEN

Another diagnostic tool is btsockstat(1). It does a similar job as netstat(1) does, but for Bluetooth sockets, logical connections on top of baseband connections. The example output shows the same connection as l2control above:

% btsockstat
Active L2CAP sockets
PCB      Recv-Q Send-Q Local address/PSM       Foreign address   CID   State
c2afe900      0      0 00:02:72:00:d4:1a/3     00:07:e0:00:0b:ca 66    OPEN
Active RFCOMM sessions
L2PCB    PCB      Flag MTU   Out-Q DLCs State
c2afe900 c2b53380 1    127   0     Yes  OPEN
Active RFCOMM sockets
PCB      Recv-Q Send-Q Local address     Foreign address   Chan DLCI State
c2e8bc80      0    250 00:02:72:00:d4:1a 00:07:e0:00:0b:ca 3    6    OPEN

19.16.5 Pairing of Devices

By default, Bluetooth communication is not authenticated and any device can talk to any other device. Some devices, like mobile phones, require 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(8). Copy /usr/src/usr.sbin/bluetooth/hcsecd/hcsecd.conf to /usr/local/etc and edit it. The following is an example section for a mobile phone, with the PIN arbitrarily 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. Start hcsecd -d. The -d switch forces the daemon to stay in the terminal and not fork to the background, so we can see what is happening. Set the remote device to receive pairing and initiate the HCI connection to the remote device. The remote device should say that pairing was accepted, and let you enter the PIN. Enter the same PIN as you have in your hcsecd.conf. Now your PC and remote device are paired. Alternatively, you can initiate pairing on the remote device. This will appear in the 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

19.16.6 Service Discovery Protocol (SDP)

If you want to know which services a Bluetooth device offers, and on which RFCOMM channels, build libbluetooth and sdp-1.0rc3 from Maksim Yevmenkin's snapshot. Then, run sdptool and observe (the output is 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 do not support browsing, they return an empty list, but you can try searching for a specific service.

# sdptool search --bdaddr 00:07:e0:00:0b:ca OPUSH

Offering services on FreeBSD to other devices is done using the sdpd server.

# sdpd

Registering a given Bluetooth service to a RFCOMM channel number:

# sdptool add --channel=7 LAN

Checking services offered by our computer:

# sdptool browse ff:ff:ff:00:00:00

19.16.7 Dial-up Networking (DUN) and Local Area Network (LAN)

Bluetooth can be used for connecting to the Internet, either over PPP (mobile phones) or the local network (access points). The Dial-up Networking profile on FreeBSD is implemented with ppp(8) and rfcomm_pppd(8), a wrapper that converts RFCOMM Bluetooth connections to something PPP can operate with. Create PPP labels in /etc/ppp/ppp.conf, examples from the rfcomm_pppd(8) manual page can be used.

Connecting to the Internet through a mobile phone (DUN profile). First, find out the correct RFCOMM channel on the remote device using sdptool. Then, use rfcomm_pppd(8):

# rfcomm_pppd -a 00:80:37:29:19:a4 -c -C 1 -l rfcomm-dialup

Running a Bluetooth access point on FreeBSD. First, register a RFCOMM channel for LAN service on the local sdpd. Then, start the PPP server. Use BD_ADDR of the local Bluetooth device and the channel number registered with sdpd.

# rfcomm_pppd -a 00:02:72:00:d4:1a -s -C 7 -l rfcomm-server

19.16.8 OBEX Push (OPUSH)

OBEX is a widely used protocol for simple file transfers between mobile devices. It's main use is in infrared communication, where it is used for generic file transfers between notebooks or Palm handhelds, and for sending business cards or calendar entries between mobile phones and other devices with PIM applications.

The OBEX client is implemented in the obexapp utility from Maksim Yevmenkin's snapshot. It needs the openobex library from same package and the devel/glib12 port. Note that obexapp does not require root privileges to operate.

OBEX client. First, find which channel on the remote device is IrMC Synchronization or OBEX Object Push. After that, use obexapp. Here is an example session where we download a file (device info from a mobile phone) and send a file (business card to the phone's 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)

OBEX server. First, register the OPUSH service with the local sdpd. If OPUSH does not work, you can try the FTRN service instead. Then, start the OBEX daemon using the channel number registered with sdpd:

# obexapp -s -C 10

Received files will appear in /var/spool/obex. This can be overriden with the -r switch. Make sure the directory exists, obexapp will not create it. On a typical workstation with a single user it is useful to set a default owner of received files. See obexapp(1) for details.

19.16.9 Serial Port Profile (SP)

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(1) 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

19.16.10 Troubleshooting

19.16.10.1 A remote device cannot connect to us

Some older devices do not support role switching. By default, when FreeBSD is accepting a connection, it tries to switch roles to become a master. Devices which do not support this will not be able to connect. Role switching is performed when a connection is being established, so we cannot ask the remote device if it does support role switching. There is a driver option to disable role switching on our side:

# hccontrol -n ubt0hci write_node_role_switch 0

19.16.10.2 Something is going wrong, can I see what exactly is happening?

Yes, you can. Use the hcidump tool from Maksim Yevmenkin's snapshot, which works much like tcpdump(1). You can use it to display the content of Bluetooth packets on the terminal and to record Bluetooth communication for later analyzation.

This, and other documents, can be downloaded from ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

For questions about FreeBSD, read the documentation before contacting <questions@FreeBSD.org>.
For questions about this documentation, e-mail <doc@FreeBSD.org>.