Table of Contents
Bluetooth is a digital radio protocol used for short range and low power communications. NetBSD 4.0 introduced support for the Bluetooth protocol stack, and some integration of service profiles into the NetBSD device framework.
The lower layers of the Bluetooth protocol stack pertaining to actual radio links between devices are handled inside the Bluetooth Controller, which communicates with the Host computer using the “Host Controller Interface” (HCI) protocol which can be accessed via a raw packet BTPROTO_HCI socket interface.
Most of the Bluetooth protocols or services layer atop the “Link Layer Control and Adaptation Protocol” (L2CAP), which can be accessed via a BTPROTO_L2CAP socket interface. This provides sequential packet connections to remote devices, with up to 64k channels. When an L2CAP channel is opened, the protocol or service that is required is identified by a “Protocol/Service Multiplexer” (PSM) value.
Service Discovery in the Bluetooth environment is provided for by the sdp(3) library and the sdpd(8) daemon (both ported from FreeBSD), which allow programs to register services and makes the information available to remote devices performing queries. Limited queries can be made with the sdpquery(1) program.
Security on Bluetooth links can be enabled by encryption and authentication options to btconfig(8) which apply to all baseband links that a controller makes, or encryption and authentication can be enabled for individual RFCOMM and L2CAP links as required. When authentication is requested, a PIN is presented by each side (generally entered by the operator, some limited input devices have a fixed PIN). The controller uses this PIN to generate a Link Key and reports this to the Host which may be asked to produce it to authenticate subsequent connections. On NetBSD, the bthcid(8) daemon is responsible for storing link keys and responding to Link Key Requests, and also provides an interface to allow unprivileged users to specify a PIN with a PIN client, such as btpin(1).
Because Bluetooth controllers normally use the standard HCI protocol as specified in the “Bluetooth 2.0 Core” documentation to communicate with the host, the NetBSD Bluetooth stack is compatible with most controllers, only requiring an interface driver, with the following drivers available in NetBSD 4.0:
If support for the NetBSD Bluetooth stack is enabled in the kernel, autoconfiguration messages will show up in the dmesg output, for example:
bt3c0 at pcmcia0 function 0: <3COM, 3CRWB60-A, Bluetooth PC Card> ubt0 at uhub1 port 4 configuration 1 interface 0 ubt0: Cambridge Silicon Radio Bluetooth USB Adapter, rev 2.00/19.58, addr 4 ubt1 at uhub1 port 2 configuration 1 interface 0 ubt1: Broadcom Belkin Bluetooth Device, rev 1.10/0.01, addr 5
When support is not already compiled in, it can be added to the kernel configuration file for any platform that supports USB and/or PCMCIA (see Section 18.9, “Tuning del Kernel”), using the following declarations, as required:
# Bluetooth Controller and Device support # Bluetooth PCMCIA Controllers bt3c* at pcmcia? function ? # 3Com 3CRWB6096-A # Bluetooth USB Controllers ubt* at uhub? port ? # Bluetooth Device Hub bthub* at bt3c? bthub* at ubt? # Bluetooth HID support bthidev* at bthub? # Bluetooth Mouse btms* at bthidev? reportid ? wsmouse* at btms? mux 0 # Bluetooth Keyboard btkbd* at bthidev? reportid ? wskbd* at btkbd? console ? mux 1 # Bluetooth Audio support btsco* at bthub? audio* at btsco?
Some older USB Bluetooth dongles based on the Broadcom BCM2033 chip require firmware to be loaded before they can function, and these devices will be attached to ugen(4). Use the “sysutils/bcmfw” package from the NetBSD Package Collection, to load firmware and enable these.
To fully enable Bluetooth services on NetBSD, the following
lines should be added to the /etc/rc.conf
file.
btconfig=YES
btconfig_args="up pscan switch class 0x02010c"
btdevctl=YES
bthcid=YES
sdpd=YES
and either reboot, or execute the following commands:
#
/etc/rc.d/btconfig start
#
/etc/rc.d/bthcid start
#
/etc/rc.d/btdevctl start
#
/etc/rc.d/sdpd start
Configuration of Bluetooth controllers is done with the btconfig(8) program, and the above argument provides only basic functionality, see the manual page for other useful options.
bthcid(8) must be running in order to make authenticated connections with remote devices, and authentication may be requested by either device.
Support for “Human Interface Devices” (HIDs), which operate using the USB HID protocol over a pair of L2CAP channels is provided by the bthidev(4) driver. Currently, keyboards and mice are catered for, and attach to wscons(4) as normal.
Bluetooth Mice can be attached to the system with the btms(4) driver, using btdevctl(8).
First, you must discover the BDADDR of the device. This may be printed on the box, but the easiest way is to place the device into discoverable mode and perform a device inquiry with the appropriate controller:
%
btconfig ubt0 inquiry
Device Discovery on ubt0 .... 1 response 1: bdaddr 00:14:51:c1:b9:2d (unknown) : name "Mighty Mouse" : class: [0x002580] Peripheral Mouse <Limited Discoverable> : page scan rep mode 0x01 : page scan period mode 0x02 : page scan mode 0x00 : clock offset 6944
For ease of use, you may want to add the address to the
/etc/bluetooth/hosts
file, so that
you can refer to the mouse by alias:
#
echo "00:14:51:c1:b9:2d mouse" >>/etc/bluetooth/hosts
Now, you can query the mouse, which will likely request authentication before it accepts connections. The fixed PIN should be listed in the documentation, though “0000” is often used. Set the PIN first using the btpin(1) program:
%
btpin -d ubt0 -a mouse -p 0000
#
btdevctl -d ubt0 -a mouse -s HID
local bdaddr: 00:08:1b:8d:ba:6d remote bdaddr: 00:14:51:c1:b9:2d link mode: auth device type: bthidev control psm: 0x0011 interrupt psm: 0x0013 Collection page=Generic_Desktop usage=Mouse Input id=2 size=1 count=1 page=Button usage=Button_1 Variable, logical range 0..1 Input id=2 size=1 count=1 page=Button usage=Button_2 Variable, logical range 0..1 Input id=2 size=1 count=1 page=Button usage=Button_3 Variable, logical range 0..1 Input id=2 size=1 count=1 page=Button usage=Button_4 Variable, logical range 0..1 Input id=2 size=4 count=1 page=0x0000 usage=0x0000 Const Variable, logical range 0..1 Collection page=Generic_Desktop usage=Pointer Input id=2 size=8 count=1 page=Generic_Desktop usage=X Variable Relative, logical range -127..127 Input id=2 size=8 count=1 page=Generic_Desktop usage=Y Variable Relative, logical range -127..127 Input id=2 size=8 count=1 page=Consumer usage=AC_Pan Variable Relative, logical range -127..127 Input id=2 size=8 count=1 page=Generic_Desktop usage=Wheel Variable Relative, logical range -127..127 End collection Input id=2 size=8 count=1 page=0x00ff usage=0x00c0 Variable, logical range -127..127 Feature id=71 size=8 count=1 page=0x0006 usage=0x0020 Variable NoPref Volatile, logical range 0..100 End collection
This tells you that the mouse has responded to an SDP query, and the device capabilities are shown. Note that authentication is enabled by default for Bluetooth mice. You may now attach to the system:
#
btdevctl -d ubt0 -a mouse -s HID -A
which should generate some messages on the system console:
bthidev0 at bthub0 remote-bdaddr 00:14:51:c1:b9:2d link-mode auth btms0 at bthidev1 reportid 2: 4 buttons, W and Z dirs. wsmouse1 at btms0 mux 0 bthidev1: reportid 71 not configured bthidev1: connected
and the mouse should work.
The device capabilities are cached by btdevctl(8), and
to reattach the mouse at system startup, place an entry in
/etc/bluetooth/btdevctl.conf
and ensure
that /etc/rc.conf
contains
btdevctl=YES
. The bthidev(4) driver
will attempt to connect once, though mice will usually be
sleeping and may require a tap on the shoulder to awake,
in which case they should initiate the connection to the
host computer.
Bluetooth Keyboards can be attached to the system with the btkbd(4) driver, using btdevctl(8).
First, you must discover the BDADDR of the device. This may be printed on the box, but the easiest way is to place the device into discoverable mode and perform a device inquiry with the appropriate controller:
%
btconfig ubt0 inquiry
Device Discovery on ubt0 .... 1 response 1: bdaddr 00:0a:95:45:a4:a0 (unknown) : name "Apple Wireless Keyboard" : class: [0x002540] Peripheral Keyboard <Limited Discoverable> : page scan rep mode 0x01 : page scan period mode 0x00 : page scan mode 0x00 : clock offset 18604
For ease of use, you may want to add the address to the
/etc/bluetooth/hosts
file, so that
you can refer to the keyboard by alias:
#
echo "00:0a:95:45:a4:a0 keyboard" >>/etc/bluetooth/hosts
Now, you can query the keyboard, which will likely request authentication before it accepts connections. The PIN will need to be entered on the keyboard, and we can generate a random PIN, using the btpin(1) program.
%
btpin -d ubt0 -a keyboard -r -l 8
PIN: 18799632#
btdevctl -d ubt0 -a keyboard -s HID
< ENTER PIN ON BLUETOOTH KEYBOARD NOW > local bdaddr: 00:08:1b:8d:ba:6d remote bdaddr: 00:0a:95:45:a4:a0 link mode: encrypt device type: bthidev control psm: 0x0011 interrupt psm: 0x0013 Collection page=Generic_Desktop usage=Keyboard Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_LeftControl Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_LeftShift Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_LeftAlt Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_Left_GUI Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_RightControl Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_RightShift Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_RightAlt Variable, logical range 0..1 Input id=1 size=1 count=1 page=Keyboard usage=Keyboard_Right_GUI Variable, logical range 0..1 Input id=1 size=8 count=1 page=0x0000 usage=0x0000 Const, logical range 0..1 Output id=1 size=1 count=1 page=LEDs usage=Num_Lock Variable, logical range 0..1 Output id=1 size=1 count=1 page=LEDs usage=Caps_Lock Variable, logical range 0..1 Output id=1 size=1 count=1 page=LEDs usage=Scroll_Lock Variable, logical range 0..1 Output id=1 size=1 count=1 page=LEDs usage=Compose Variable, logical range 0..1 Output id=1 size=1 count=1 page=LEDs usage=Kana Variable, logical range 0..1 Output id=1 size=3 count=1 page=0x0000 usage=0x0000 Const, logical range 0..1 Input id=1 size=8 count=6 page=Keyboard usage=No_Event, logical range 0..255 Input id=1 size=1 count=1 page=Consumer usage=Eject Variable Relative, logical range 0..1 Input id=1 size=1 count=1 page=Consumer usage=Mute Variable Relative, logical range 0..1 Input id=1 size=1 count=1 page=Consumer usage=Volume_Up Variable, logical range 0..1 Input id=1 size=1 count=1 page=Consumer usage=Volume_Down Variable, logical range 0..1 Input id=1 size=1 count=4 page=0x0000 usage=0x0000 Const, logical range 0..1 End collection
This tells you that the keyboard has responded to an SDP query, and the device capabilities are shown. Note that encryption is enabled by default, since encrypted connection support is mandatory for Bluetooth keyboards. You may now attach to the system:
#
btdevctl -d ubt0 -a keyboard -s HID -A
which should generate some messages on the system console:
bthidev1 at bthub0 remote-bdaddr 00:0a:95:45:a4:a0 link-mode encrypt btkbd0 at bthidev0 reportid 1 wskbd1 at btkbd0 mux 1 wskbd1: connecting to wsdisplay0 bthidev1: connected
and the keyboard should work.
The device capabilities are cached by btdevctl(8), and
to reattach the keyboard at system startup, place an entry in
/etc/bluetooth/btdevctl.conf
and ensure
that /etc/rc.conf
contains
btdevctl=YES
. The bthidev(4) driver
will attempt to connect once when attached, but if the
keyboard is not available at that time, you may find that
pressing a key will cause it to wake up and initiate a
connection to the last paired host.
Serial connections over Bluetooth are provided for by the RFCOMM protocol, which provides up to 30 channels multiplexed over a single L2CAP channel. This streamed data protocol can be accessed using the BTPROTO_RFCOMM socket interface, or via the rfcomm_sppd(1) program.
For instance, you can make a serial connection to the
“Dial Up Networking” (DUN) service of a mobile
phone in order to connect to the Internet with PPP. First you
should discover the BDADDR of the phone, and add this to your
/etc/bluetooth/hosts
for ease of use.
Place the phone into Discoverable mode, and perform an inquiry
from the appropriate controller:
%
btconfig ubt0 inquiry
Device Discovery from device: ubt0 ..... 1 response 1: bdaddr 00:16:bc:00:e8:48 (unknown) : name "Nokia 6103" : class: [0x520204] Cellular Phone <Networking> <Object Transfer> <Telephony> : page scan rep mode 0x01 : page scan period mode 0x02 : page scan mode 0x00 : clock offset 30269#
echo "00:16:bc:00:e8:48 phone" >>/etc/bluetooth/hosts
Now, you can query the phone to confirm that it supports the DUN profile:
%
sdpquery -d ubt0 -a phone search DUN
Record Handle: 0x00010000 Service Class ID List: Dial-Up Networking (0x1103) Generic Networking (0x1201) Protocol Descriptor List: L2CAP (0x0100) RFCOMM (0x0003) Protocol specific parameter #1: u/int8/bool 1 Bluetooth Profile Descriptor List: Dial-Up Networking (0x1103) ver. 1.0
Most likely, the phone will request authentication before
it allows connections to the DUN service, so before you
make the first connection you may need to provide a PIN,
which can be randomly generated. You can use
rfcomm_sppd in stdio mode to check that
the connection is working ok, press ^C
to disconnect and return to the shell, for example:
%
btpin -d ubt0 -a phone -r -l 6
PIN: 904046%
rfcomm_sppd -d ubt0 -a phone -s DUN
< ENTER PIN ON PHONE NOW > rfcomm_sppd[24635]: Starting on stdio...at
OKati
Nokia OKati3
Nokia 6103 OKat&v
ACTIVE PROFILE: E1 Q0 V1 X5 &C1 &D2 &S0 &Y0 +CMEE=0 +CSTA=129 +CBST=0,0,1 +CRLP=61,61,48,6 +CR=0 +CRC=0 +CLIP=0,2 +CLIR=0,2 +CSNS=0 +CVHU=1 +DS=0,0,2048,32 +DR=0 +ILRR=0 +CHSN=0,0,0,0 +CHSR=0 +CPBS="SM" S00:000 S01:000 S02:043 S03:013 S04:010 S05:008 S07:060 S08:002 S10:100 S12:050 S25:000 OK^C
rfcomm_sppd[24635]: Completed on stdio
To have pppd(8) connect to the DUN service of your
phone automatically when making outbound connections, add the
following line to the /etc/ppp/options
file in place of the normal tty declaration:
pty "rfcomm_sppd -d ubt0 -a phone -s DUN -m encrypt"
Isochronous (SCO) Audio connections may be created on a baseband radio link using either the BTPROTO_SCO socket interface, or the btsco(4) audio device driver. While the specification says that up to three such links can be made between devices, the current Bluetooth stack can only handle one with any dignity.
When using SCO Audio with USB Bluetooth controllers, you will need to enable isochronous data, and calculate the MTU that the device will use, see ubt(4) and btconfig(8).
SCO Audio does not work properly with the bt3c(4) driver, use a USB controller for best results.
SCO Audio will not work with ehci(4) USB controllers, since support for Isochronous data over EHCI is missing in NetBSD.
Audio connections to Bluetooth Headsets are possible
using the btsco(4) audio driver, and the bthset(1)
program. First, you need to discover the BDADDR of the
headset, and will probably wish to make an alias in your
/etc/bluetooth/hosts
file for ease
of use. Place the headset into discoverable mode and
perform an inquiry with the appropriate controller:
%
btconfig ubt0 inquiry
Device Discovery from device: ubt0 ..... 1 response 1: bdaddr 00:07:a4:23:10:83 (unknown) : name "JABRA 250" : class: [0x200404] Wearable Headset <Audio> : page scan rep mode 0x01 : page scan period mode 0x00 : page scan mode 0x00 : clock offset 147#
echo "00:07:a4:23:10:83 headset" >>/etc/bluetooth/hosts
You will need to pair with the headset the first time you connect, the fixed PIN should be listed in the manual (often, “0000” is used). btdevctl(8) will query the device and attach the btsco(4) audio driver.
%
btpin -d ubt0 -a headset -p 0000
#
btdevctl -d ubt0 -a headset -s HSET -A
local bdaddr: 00:08:1b:8d:ba:6d remote bdaddr: 00:07:a4:23:10:83 link mode: none device type: btsco mode: connect channel: 1
which should generate some messages on the system console:
btsco0 at bthub0 remote-bdaddr 00:07:a4:23:10:83 channel 1 audio1 at btsco0: full duplex
In order to use the audio device, you will need to open a control connection with bthset(1) which conveys volume information to the mixer device.
%
bthset -d /dev/mixer1 -v
Headset Info: mixer: /dev/mixer1 laddr: 00:08:1b:8d:ba:6d raddr: 00:07:a4:23:10:83 channel: 1 vgs.dev: 0, vgm.dev: 1
and you should now be able to transfer 8khz samples to
and from /dev/audio1
using any program
that supports audio, such as audioplay(1) or
audiorecord(1). Adjusting the mixer values should work
when playing though you may find that when opening a
connection, the headset will reset the volume to the last
known settings.
%
audiorecord -d /dev/audio1 voice.au
< TALK NONSENSE NOW >^C
%
audioplay -d /dev/audio voice.au
< THATS REALLY WHAT YOU SOUND LIKE >%
audioplay -d /dev/audio1 voice.au
< IN THE HEADSET >
The device capabilities are cached by btdevctl(8), and
to reattach the btsco(4) driver at system startup, add
an entry to /etc/bluetooth/btdevctl.conf
and ensure that /etc/rc.conf
contains btdevctl=YES
.
Audio connections to Bluetooth mobile phones using the Handsfree profile are possible with the “comms/bthfp” program from the NetBSD Package Collection.
First, you need to discover the BDADDR of the phone,
and will probably wish to make an alias in your
/etc/bluetooth/hosts
file for ease of
use. Place the phone into discoverable mode and perform
an inquiry with the appropriate controller:
%
btconfig ubt0 inquiry
Device Discovery from device: ubt0 ..... 1 response 1: bdaddr 00:16:bc:00:e8:48 (unknown) : name "Nokia 6103" : class: [0x520204] Cellular Phone <Networking;gt; <Object Transfer;gt; <Telephony;gt; : page scan rep mode 0x01 : page scan period mode 0x02 : page scan mode 0x00 : clock offset 10131#
echo "00:16:bc:00:e8:48 phone" >>/etc/bluetooth/hosts
Now, you should be able to query the phone to confirm that it supports the Handsfree profile:
%
sdpquery -d ubt0 -a phone search HF
Record Handle: 0x00010003 Service Class ID List: Handsfree Audio Gateway (0x111f) Generic Audio (0x1203) Protocol Descriptor List: L2CAP (0x0100) RFCOMM (0x0003) Protocol specific parameter #1: u/int8/bool 13 Bluetooth Profile Descriptor List: Handsfree (0x111e) ver. 1.1
and you will be able to use the bthfp program to access the Handsfree profile. The first time you connect, you may need to use a PIN to pair with the phone, which can be generated randomly by btpin(1):
%
btpin -d ubt0 -a phone -r -l 6
PIN: 349163%
bthfp -d ubt0 -a phone -v
< ENTER PIN ON PHONE NOW > Handsfree channel: 13 Press ? for commands Connecting.. ok < AT+BRSF=20 > +BRSF: 47 Features: [0x002f] <3 way calling> <EC/NR> <Voice Recognition> <In-band ringtone> <reject ability> > OK < AT+CIND=? > +CIND: ("call",(0,1)),("service",(0,1)),("call_setup",(0-3)),("callsetup",(0-3)) > OK < AT+CIND? > +CIND: 0,1,0,0 > OK < AT+CMER=3,0,0,1 > OK < AT+CLIP=1 > OK Service Level established
When the phone rings, just press a
to answer, and audio should be routed through the
/dev/audio
device. Note that you will
need a microphone connected in order to speak to the remote
party.
NetBSD does not currently have any native OBEX capability, see the “comms/obexapp” or “comms/obexftp” packages from the NetBSD Package Collection.
When nothing seems to be happening, it may be useful to try the hcidump program from the “sysutils/hcidump” package in the NetBSD Package Collection. This has the capability to dump packets entering and leaving Bluetooth controllers on NetBSD, which is greatly helpful in pinpointing problems.