# Bluetooth on NetBSD ## Introduction 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)](http://netbsd.gw.com/cgi-bin/man-cgi?sdp+3+NetBSD-5.0.1+i386) library functions and the [sdpd(8)](http://netbsd.gw.com/cgi-bin/man-cgi?sdpd+8+NetBSD-5.0.1+i386) daemon, which keeps a database of locally registered services and makes the information available to remote devices performing queries. The [sdpquery(1)](http://netbsd.gw.com/cgi-bin/man-cgi?sdpquery+1+NetBSD-5.0.1+i386) tool can be used to query local and remote service databases. Security on Bluetooth links can be enabled by encryption and authentication options to [btconfig(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btconfig+8+NetBSD-5.0.1+i386) 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)](http://netbsd.gw.com/cgi-bin/man-cgi?bthcid+8+NetBSD-5.0.1+i386) 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)](http://netbsd.gw.com/cgi-bin/man-cgi?btpin+1+NetBSD-5.0.1+i386). ## Supported Hardware 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 5.0: * [bcsp(4)](http://netbsd.gw.com/cgi-bin/man-cgi?bcsp+4+NetBSD-5.0.1+i386) provides a [tty(4)](http://netbsd.gw.com/cgi-bin/man-cgi?tty+4+NetBSD-5.0.1+i386) line discipline to send and receive BlueCore Serial Protocol packets over a serial line as described in the *BlueCore Serial Protocol (BCSP)* specification. * [bt3c(4)](http://netbsd.gw.com/cgi-bin/man-cgi?bt3c+4+NetBSD-5.0.1+i386) provides an interface to the 3Com Bluetooth PC Card, model 3CRWB6096-A. * [btbc(4)](http://netbsd.gw.com/cgi-bin/man-cgi?btbc+4+NetBSD-5.0.1+i386) provides support for the AnyCom BlueCard (LSE041, LSE039, LSE139) PCMCIA devices. * [btuart(4)](http://netbsd.gw.com/cgi-bin/man-cgi?btuart+4+NetBSD-5.0.1+i386) provides a [tty(4)](http://netbsd.gw.com/cgi-bin/man-cgi?tty+4+NetBSD-5.0.1+i386) line discipline to send and receive Bluetooth packets over a serial line as described in the *Bluetooth Host Controller Interface [Transport Layer] specification, Vol 4 part A*. * [sbt(4)](http://netbsd.gw.com/cgi-bin/man-cgi?sbt+4+NetBSD-5.0.1+i386) provides support for Secure Digital IO Bluetooth adapters. * [ubt(4)](http://netbsd.gw.com/cgi-bin/man-cgi?ubt+4+NetBSD-5.0.1+i386) interfaces to all USB Bluetooth controllers conforming to the *HCI USB Transport Layer* specification. If support for the NetBSD Bluetooth stack is enabled in the kernel, autoconfiguration messages will show up in the [dmesg(8)](http://netbsd.gw.com/cgi-bin/man-cgi/man?dmesg+8+NetBSD-current) 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 [[Kernel Tuning|guide/tuning]]), using the following declarations, as required: # Bluetooth Controller and Device support pseudo-device bcsp # BlueCore Serial Protocol pseudo-device btuart # Bluetooth HCI UART # Bluetooth PCMCIA Controllers bt3c* at pcmcia? function ? # 3Com 3CRWB6096-A btbc* at pcmcia? function ? # AnyCom BlueCard LSE041/039/139 # Bluetooth SDIO Controllers sbt* at sdmmc? # Bluetooth USB Controllers ubt* at uhub? port ? # Bluetooth Device Hub bthub* at bcsp? bthub* at bt3c? bthub* at btbc? bthub* at btuart? bthub* at sbt? 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? 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)](http://netbsd.gw.com/cgi-bin/man-cgi?ugen+4+NetBSD-5.0.1+i386). Use the `sysutils/bcmfw` package from the NetBSD Package Collection, to load firmware and enable these. ## System Configuration To fully enable Bluetooth services on NetBSD, the following line should be added to the `/etc/rc.conf` file. bluetooth=YES and either reboot, or execute the following command: # /etc/rc.d/bluetooth start *Note*: Configuration of Bluetooth controllers is done with the [btconfig(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btconfig+8+NetBSD-5.0.1+i386) program, and the above argument enables only basic functionality, see the manual page for other useful options. **Important**: [bthcid(8)](http://netbsd.gw.com/cgi-bin/man-cgi?bthcid+8+NetBSD-5.0.1+i386) *must* be running in order to make authenticated connections with remote devices, and authentication may be requested by either device. ## Human Interface Devices 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)](http://netbsd.gw.com/cgi-bin/man-cgi?bthidev+4+NetBSD-5.0.1+i386) driver. Currently, keyboards and mice are catered for, and attach to [wscons(4)](http://netbsd.gw.com/cgi-bin/man-cgi?wscons+4+NetBSD-5.0.1+i386) as normal. ### Mice Bluetooth Mice can be attached to the system with the [btms(4)](http://netbsd.gw.com/cgi-bin/man-cgi?btms+4+NetBSD-5.0.1+i386) driver, using [btdevctl(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btdevctl+8+NetBSD-5.0.1+i386). 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 : 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)](http://netbsd.gw.com/cgi-bin/man-cgi?btpin+1+NetBSD-5.0.1+i386) 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)](http://netbsd.gw.com/cgi-bin/man-cgi?btdevctl+8+NetBSD-5.0.1+i386), and to reattach the mouse at system startup, place an entry in `/etc/bluetooth/btdevctl.conf`. The [bthidev(4)](http://netbsd.gw.com/cgi-bin/man-cgi?bthidev+4+NetBSD-5.0.1+i386) driver will attempt to connect once, though mice will usually be sleeping and may require a tap on the shoulder to awaken, in which case they should initiate the connection to the host computer. ### Keyboards Bluetooth Keyboards can be attached to the system with the [btkbd(4)](http://netbsd.gw.com/cgi-bin/man-cgi?btkbd+4+NetBSD-5.0.1+i386) driver, using [btdevctl(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btdevctl+8+NetBSD-5.0.1+i386). 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 : 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)](http://netbsd.gw.com/cgi-bin/man-cgi?btpin+1+NetBSD-5.0.1+i386) 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)](http://netbsd.gw.com/cgi-bin/man-cgi?btdevctl+8+NetBSD-5.0.1+i386), and to reattach the keyboard at system startup, place an entry in `/etc/bluetooth/btdevctl.conf`. The [bthidev(4)](http://netbsd.gw.com/cgi-bin/man-cgi?bthidev+4+NetBSD-5.0.1+i386) 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. ## Personal Area Networking Personal Area Networking services over Bluetooth are provided by the [btpand(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btpand+8+NetBSD-5.0.1+i386) daemon which can assume all roles from the PAN profile and connects remote devices to the system through a [tap(4)](http://netbsd.gw.com/cgi-bin/man-cgi?tap+4+NetBSD-5.0.1+i386) virtual Ethernet interface. ### Personal Area Networking User The "Personal Area Networking User" role is the client that accesses Network services on another device. For instance, in order to connect to the Internet via a smart phone with the NAP profile, make sure that the phone is discoverable, then: # btconfig ubt0 inquiry Device Discovery from device: ubt0 .... 1 response 1: bdaddr 00:17:83:30:bd:5e (unknown) : name "HTC Touch" : class: [0x5a020c] Smart Phone : page scan rep mode 0x01 : clock offset 9769 : rssi -42 # echo "00:17:83:30:bd:5e phone" >>/etc/bluetooth/hosts You will see that the phone should have the `` flag set in the Class of Device. Checking for the NAP service: # sdpquery -a phone search NAP ServiceRecordHandle: 0x00010000 ServiceClassIDList: Network Access Point ProtocolDescriptorList: L2CAP (PSM 0x000f) BNEP (v1.0; IPv4, ARP, IPv6) LanguageBaseAttributeIDList: en.UTF-8 base 0x0100 BluetoothProfileDescriptorList: Network Access Point, v1.0 ServiceName: "Network Access Point" ServiceDescription: "Bluetooth NAP Service" SecurityDescription: None NetAccessType: 100Mb Ethernet MaxNetAccessRate: 100000 reveals that the NAP service is available and that it provides IPv4, ARP and IPv6 protocols. Most likely, the phone will request authentication before it allows connections to the NAP service, so before you make the first connection you may need to provide a PIN, which can be randomly generated. Then start [btpand(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btpand+8+NetBSD-5.0.1+i386): # btpin -d ubt0 -a phone -r -l 6 PIN: 862048 # btpand -d ubt0 -a phone -s NAP < ENTER PIN ON PHONE NOW > Searching for NAP service at 00:17:83:30:bd:5e Found PSM 15 for service NAP Opening connection to service 0x1116 at 00:17:83:30:bd:5e Using interface tap0 with addr 00:10:60:e1:50:3d Finally, you will need to configure the [tap(4)](http://netbsd.gw.com/cgi-bin/man-cgi?tap+4+NetBSD-5.0.1+i386) interface, but the phone should have a DHCP server so [dhcpcd(8)](http://netbsd.gw.com/cgi-bin/man-cgi?dhcpcd+8+NetBSD-5.0.1+i386) will do that for you. # dhcpcd tap0 Now you can surf the World Wide Web, but watch your data usage unless you have a comprehensive data plan. ## Serial Connections 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)](http://netbsd.gw.com/cgi-bin/man-cgi?rfcomm_sppd+1+NetBSD-5.0.1+i386) 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 : 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 ServiceRecordHandle: 0x00010003 ServiceClassIDList: Dialup Networking Generic Networking ProtocolDescriptorList: L2CAP RFCOMM (channel 1) BrowseGroupList: Public Browse Root LanguageBaseAttributeIDList: en.UTF-8 base 0x0100 BluetoothProfileDescriptorList: Dialup Networking, v1.0 ServiceName: "Dial-up networking" 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 OK ati Nokia OK ati3 Nokia 6103 OK at&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)](http://netbsd.gw.com/cgi-bin/man-cgi?pppd+8+NetBSD-5.0.1+i386) 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" ## Audio Isochronous (SCO) Audio connections may be created on a baseband radio link using either the BTPROTO\_SCO socket interface, or the [btsco(4)](http://netbsd.gw.com/cgi-bin/man-cgi?btsco+4+NetBSD-5.0.1+i386) 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. **Important**: 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)](http://netbsd.gw.com/cgi-bin/man-cgi?ubt+4+NetBSD-5.0.1+i386) and [btconfig(8)](http://netbsd.gw.com/cgi-bin/man-cgi?btconfig+8+NetBSD-5.0.1+i386). *Note*: SCO Audio does not work properly with the [bt3c(4)](http://netbsd.gw.com/cgi-bin/man-cgi?bt3c+4+NetBSD-5.0.1+i386) driver, use a USB controller for best results. *Note*: SCO Audio will not work with [ehci(4)](http://netbsd.gw.com/cgi-bin/man-cgi?ehci+4+NetBSD-5.0.1+i386) USB controllers, since support for Isochronous data over EHCI is missing in NetBSD. ### SCO Audio Headsets Audio connections to Bluetooth Headsets are possible using the [btsco(4)](http://netbsd.gw.com/cgi-bin/man-cgi?btsco+4+NetBSD-5.0.1+i386) audio driver, and the [bthset(1)](http://netbsd.gw.com/cgi-bin/man-cgi?bthset+1+NetBSD-5.0.1+i386) 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