The Complete Magazine on Open Source

Linux Without Wires The Basics of Bluetooth

SHARE
/ 482 0

bluetooth

Bluetooth technology is used for short range (1 metre to 100 metres) communication. It is the most widespread wireless technology, and is divided into classes according to the power and communication range

Bluetooth is a packet based protocol and has a master-slave structure. It works between the 2400MHz and the 2483.5MHz frequency range, and uses the frequency-hopping spread spectrum. Bluetooth divides data into packets and transmits them on one of the 79 designated channels. Each channel has a 1MHz bandwidth. Version 4.0 of Bluetooth has 40 channels, and each channel uses a 2MHz bandwidth.

Figure 1

Figure 2

Bluetooth stack
A Bluetooth stack is software used to implement the Bluetooth host protocol stack. Bluetooth stack implementation can be of two types:

  • The first is a general-purpose implementation that is usually for desktop computers, and it is flexible because additional Bluetooth profiles can be added through drivers.
  • The second is an embedded system implementation, which is for devices where resources are limited, like peripheral devices.

There are various types of Bluetooth stacks in the market like BlueZ, Bluedroid, Widcomm, Bluecode+, BlueLet, BlueMagic, etc (see Figure 2).

Figure 3

BlueZ
BlueZ is a general-purpose Bluetooth stack that is used to implement the Bluetooth host protocol stack for Linux. It is open source software and the official Linux Bluetooth stack. You can download this software from http://www.bluez.org/ in the development section.
BlueZ maps Bluetooth protocol layers to kernel modules, kernel threads, user space daemons, configuration tools, utilities and libraries (see Figure 3). The main components of BlueZ are:

  • bluetooth.ko, which contains core infrastructure of BlueZ. It exports sockets of the Bluetooth family – AF_BLUETOOTH. All BlueZ modules utilise its services.
  • Bluetooth HCI packets are transported over UART or USB. The corresponding BlueZ HCI implementation is hci_uart.ko and hci_usb.ko.
  • The L2CAP layer of Bluetooth, which is responsible for segmentation, reassembly and protocol multiplexing, is implemented by l2cap.ko.
  • With the help of bnep.ko, TCP/IP applications can run over Bluetooth. This emulates an Ethernet port over the L2CAP layer. The kernel thread named kbnepd is responsible for BNEP connections.
  • rfcomm.ko is responsible for running serial port applications like the terminal. This emulates serial ports over the L2CAP layer. The kernel thread named krfcommd is responsible for RFCOMM connections.
  • hidp.ko implements the HID (human interface device) layer. The user mode daemon hidd allows BlueZ to handle input devices like Bluetooth mice.
  • sco.ko implements the synchronous connection oriented (SCO) layer to handle audio. SCO connections do not specify a channel to connect to a remote host; only the host address is specified.

The Bluetooth protocol stack vs the OSI model
The reason for comparing the Bluetooth protocol stack with the Open Systems Interconnection (OSI) model is to understand the former, better. Knowledge of the OSI model is assumed.
The radio, baseband and link manager layer are the hardware part of the Bluetooth architecture which is implemented on the Bluetooth chipset. These layers roughly map to the physical, data link and network layers in the OSI model. The host control interface (HCI) maps to the transport layer, and transports data between the L2CAP layer and the Bluetooth chipset. The Logical Link Control and Adaptation Protocol (L2CAP) maps to the session layer. Serial port emulation using radio frequency communication (RFCOMM), Ethernet emulation using Bluetooth Network Encapsulation Protocol (BNEP) and the Service Discovery Protocol (SDP) are part of the feature-rich presentation layer. At the top of the stack reside various application environments called profiles. Since the radio, baseband and link manager are usually part of Bluetooth hardware, operating system support starts at the HCI layer (see Figure 4).

Figure 4

Figure 5

A closer look at the Bluetooth protocol stack
The Bluetooth protocol stack is divided into two parts – the host and controller, and interfaced by the host controller interface (HCI) layer (see Figure 5).

Bluetooth host
The host consists of the software part of the stack. Hence, it is implemented at the operating system level. It includes implementations of the core Bluetooth protocols: the Bluetooth stack (or host protocol stack) and the high-level layers of the Bluetooth architecture, such as APIs and profiles. It has various layers and protocols like L2CAP, RFCOMM, SDP, etc, which are explained below.

L2CAP(Logical Link Control and Adaptation Protocol) L2CAP has the following features:

  • The capability to multiplex data between different higher layer protocols; hence, various protocols like RFCOM, SDP, etc, can operate over it
  • Segmentation and reassembly
  • Quality of service
  • It supports a group abstraction, enabling implementation for mapping a group on to a piconet

RFCOMM (Radio Frequency Communication): RFCOMM is situated over the L2CAP layer. It is a serial port emulation protocol. It emulates RS-232 control and data signals over the Bluetooth baseband.
It provides roughly the same service and reliability guarantees as TCP. The choice of port numbers is the biggest difference between TCP and RFCOMM from a network programmer’s perspective. Whereas TCP supports up to 65,535 open ports on a single machine, RFCOMM allows only 30. This has a significant impact on how to choose port numbers for server applications.
SDP (Service Discovery Protocol): This protocol is required by all Bluetooth applications and is an important part of the Bluetooth protocol stack. With the help of this protocol, devices can discover what services other nearby devices support and what parameters are required to connect with them. Each service is identified by a universally unique identifier (UUID).

Bluetooth profile
The Bluetooth profile is a specification that describes how devices must use Bluetooth protocols to implement a particular task, and this is the theoretical part of the Bluetooth architecture. Bluetooth services are the practical part of the Bluetooth protocol stack. There are various types of profiles available. Some are:

  • GAP (generic access profile): This defines generic requirements for detecting and establishing a connection to a Bluetooth device. It is a core profile that is available by default.
  • GOEP (generic object exchange profile): This defines the requirement of OBEX, a communication protocol used to exchange binary objects between devices while using minimal resources and usage models.
  • HSP (headset profile): This defines the procedure that supports the interoperability between a headset and a mobile device, like a cellular phone, that the headset controls through AT commands, and depends upon the serial port profile.
  • SPP (serial port profile): This defines the requirements for virtual serial port connections over the RFCOMM.

Note: To see the available Bluetooth profiles in your Linux system, run sdptool browse local.

HCI (Host Controller Interface)
The Bluetooth host and Bluetooth controller communicate with the help of the HCI. It contains drivers that abstract and transfer data between the Bluetooth host and the Bluetooth controller. These drivers implement communication between the Bluetooth host and the Bluetooth controller with a small set of functions that send and receive commands, data packets and events.
Communication between the host and the controller is done through HCI packets, of which there are four types.

  • Command packet: These packets are generated from the host and are sent to the controller or Bluetooth adapter to control the adapter. They can be used to start a device enquiry, connect to a remote device, etc.
  • Event packet: These packets are sent from the Bluetooth adapter to the host. These packets are sent whenever an event occurs such as sending information about a local Bluetooth adapter, connecting to a remote device, etc.
  • ACL data packet: ACL data packets are encapsulated by the HCI layer and transport to the Bluetooth adapter; however, the HCI headers are removed and the bare ACL packet is transmitted over the air and re-wrapped after being received.
  • Synchronous data packet: These packets are also encapsulated at the HCI layer and pass to the Bluetooth adapter. Then, after unwrapping the HCI header, they are sent out, but are also re-wrapped after being received.

Bluetooth controller
The Bluetooth controller is a Bluetooth device such as a USB dongle. It is a hardware and firmware part of the Bluetooth protocol stack. It implements the lowest level of Bluetooth architecture, including the physical layer and the radio transceiver. The Bluetooth controller receives commands from the Bluetooth host through the HCI. The Bluetooth controller has layers like the Link Manager Protocol (LMP), baseband and radio.
Link Manager Protocol (LMP): This is responsible for logical link establishment between Bluetooth devices. It does link authentication and encryption, and creates, updates and removes logical links and logical transports. It also updates parameters for a physical link to Bluetooth devices.
Baseband: This layer has a link controller, which is responsible for the physical layer of the Bluetooth architecture. It establishes and manages the physical radio frequency link between Bluetooth devices that forms a piconet.
Radio: This is a Bluetooth transceiver, which transmits data to and from the baseband. It is the lowest layer of the Bluetooth architecture. See Figure 6 for a complete view of the Bluetooth protocol stack.

Figure 6

Figure 7

Coding with Bluetooth
Before coding, you need the development files for linking to the BlueZ library. For this you have to install the libbluetooth-dev package:

sudo apt-get install libbluetooth-dev

Now, let’s do some basic programming with Bluetooth like searching for a Bluetooth device.

Searching Bluetooth devices
To search for Bluetooth devices, you need some APIs. BlueZ exposes socket APIs that are similar to network socket programming. If you are familiar with network programming in Linux, learning the BlueZ APIs will be simple.
The basic data structure used to specify a 6-byte Bluetooth device address is bdaddr_t. In BlueZ, every Bluetooth address is stored as the bdaddr_t structure (see Figure 7).
BlueZ provides two functions to convert between the string and the bdaddr_t structure:

int str2ba( const char *str , bdaddr_t *ba );
int ba2str( const bdaddr_t *ba, char *str );

The header files required
Before using these APIs, you need some header files:

#include <bluetooth/bluetooth.h>
#include<Bluetooth/hci.h>
#include<Bluetooth/hci_lib.h>

Note: These headers files are available in the /usr/include/blutooth directory.

Getting the Bluetooth adapter ID
You can get a Bluetooth adapter resource number by using the following API:

int hci_get_route ( bdaddr_t *bdaddr );

Local Bluetooth adapters are assigned identifying numbers starting with 0, and a program must specify which adapter to use when allocating system resources. Usually, there is only one adapter or it does not matter which one is used, so passing NULL to hci_get_route will retrieve the ID of the first available Bluetooth adapter:

dev_id = hci_get_route (NULL);

Note: If multiple adapters are present, then choose the adapter by passing the char* representation of the address to hci_devid:

dev_id = hci_devid ( “01:43:24:9A:45:C3” );

Figure 8

Opening a file handle to the HCI
After getting the Bluetooth adapter ID, it’s time to open a file handle to the host controller interface so that we can pass commands to the Bluetooth controller.

int fh = hci_open_dev(dev_id);

Don’t hard code the device ID with 0, because zero is not always the ID of the first adapter. In case a system has two adapters and the first adapter (ID 0) is disabled, then the first available adapter is the one with ID 1.
inquiry_info structure is used to store the Bluetooth device type address (see Figure 8).
The first field of this structure, bdaddr_t, gives the address of the detected Bluetooth device. The dev_class field gives information about the type of detected device like whether it is a phone, printer or computer.

inquiry_info *ii = NULL;

You can get more information about dev_class from http://www.wensley.org.uk/c/inq/reporter.c

Getting Bluetooth addresses and the types of Bluetooth devices
After selecting the local Bluetooth adapter and file handle to the host controller interface, it’s time to scan for Bluetooth devices nearby. hci_inquiry discovers Bluetooth devices and stores basic information about them, like Bluetooth addresses,
type of device, etc, in the inquiry_info structure.

int hci_inquiry ( int dev_id , int time_len , int max_rsp , const uint8_t *lap , inquiry_info **ii, long flags );

Enquiry or discovery of devices lasts for at the most 1.28 * time_len seconds and, at the most, max_rsp devices will be returned in the output parameter ii.

Note: To get enough time for enquiry, use 8 for time_len, that is 10.24 seconds, and 255 for max_rsp. If you want to flush the cache of previously detected devices, set flags to IREQ_CACHE_FLUSH; otherwise, use 0 and hci_inquiry will also return those Bluetooth devices that are out of range, but still in cache.

Now we have the Bluetooth addresses of all available devices. With the help of these addresses, you can get the names of the devices.

int hci_read_remote_name ( int fh , const bdaddr_t *ba, int len, char *name, int timeout );

hci_read_remote_name tries timeout milliseconds to use the fh file handle for querying the user-friendly name of the device with the help of the Bluetooth address ba, and store len byte of friendly name into name.

After this, do not forget to free the inquiry_info structure and close the file handle to the host controller interface.

free ( ii );
close ( fh );

Figure 9

How to run the program and get an output
First, compile this program by invoking gcc and linking with libbluetooth:

# gcc scan_bt_devices.c -lbluetooth

See Figure 9 for the output. Though it need not be mentioned, before running this program, the Bluetooth of the device must be ON. You can switch ON your Bluetooth manually or you can switch it ON by using the rfkill command:

rfkill unblock bluetooth

You can switch it OFF similarly:

rfkill block bluetooth

RFCOMM and L2CAP sockets
L2CAP connections are like UDP protocol and both are packet based protocols, but there is a difference between them. In UDP, it is possible that the two packets, sent from a computer, may reach randomly, which means that the second packet may reach first. But in L2CAP, the first packet will always reach first.

RFCOMM connections are like TCP. But RFCOMM supports only 30 unreserved channels (known as ports in TCP) and no reserved channels in a single machine, while TCP supports 65,535 ports.

In L2CAP, ports are known as protocol service multiplexers (PSM) and take odd-numbered values between 1 to 32,767, where odd-numbered PSMs from 1 to 4,095 are reserved while odd-numbered PSMs from 4,097 to 32,765 are unreserved.

L2CAP connections are encapsulated within ACL (asynchronous connection oriented logic) connections and RFCOMM connections are transported within L2CAP connections, so RFCOMM connections are also encapsulated within ACL connections.

RFCOMM and L2CAP servers
RFCOMM and L2CAP have socket APIs to open socket descriptors like TCP/IP programming. But here we have the Bluetooth family’s AF_BLUETOOTH.

Note: For RFCOMM sockets, include the bluetooth/rfcomm.h header file and bluetooth/l2cap.h for L2CAP, as well as bluetooth/bluetooth.h and sys/socket.h in both.

RFCOMM has the SOCK_STREAM type and BTPROTO_RFCOMM protocol:

s = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) ;

L2CAP has the SOCK_SEQPACKET type and BTPROTO_L2CAP protocol:

s = socket ( AF_BLUETOOTH , SOCK_SEQPACKET , BTPROTO_L2CAP ) ;

TCP/IP has the sockadd_in structure and similarly, L2CAP has the sockaddr_l2 structure while RFCOMM has the sockaddr_rc structure (see Figures 10 and 11).

Figure 10

Figure 11

Note: After kernel 2.4.37, the sockaddr_l2 structure has some extra fields like l2_cid and l2_bdaddr_type.

Use the BADDR_ANY macro so that the server can listen to all local Bluetooth adapters. Bluetooth uses htobs and btohs instead of htons and ntohs, which are used in TCP/IP.
For RFCOMM, type:

loc_addr . rc_family = AF_BLUETOOTH;
loc_addr . rc_bdaddr = BDADDR ANY;
loc_addr . rc_channel = 1 ;

For L2CAP, type:

loc_addr . l2_family = AF_BLUETOOTH ;
loc_addr . l2_bdaddr = BDADDR ANY ;
loc_addr . l2_psm = htobs(0x1001 ) ;

Since you know the TCP/IP concepts, you can easily understand the next APIs mentioned like bind, listen, accept, send and recv.
For RFCOMM and L2CAP, type:

bind ( s , ( struct sockaddr * )&loc_addr , sizeof ( loc_addr ) ) ;
listen ( s, 1 ); //for one connection
client = accept ( s , ( struct sockaddr * )&rem_addr , &(sizeof( rem_addr )) ) ;

Note: Before printing the received Bluetooth address, convert it to a string by using the ba2str API, which is described earlier in this article. You can also print the address by accessing the bdaddr_t structure.

Now receive data from the client:

b = recv ( client , buf , sizeof ( buf ) , 0 ) ;
if ( b > 0 ) {
printf ( “received [%s]\n “ , buf ) ;
}

And after reading the data, close the sockets.

close ( client );
close ( S );

RFCOMM and L2CAP client
For the client, first open the socket.

For RFCOMM, type:

s = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

For L2CAP, type:

s = socket ( AF_BLUETOOTH , SOCK_SEQPACKET , BTPROTO_L2CAP );

Now connect this socket with the existing server.
For RFCOMM, type:

struct sockaddr_rc addr;
char dest[18] = “<Bluetooth Address>” //put server’s bluetooth adapter address
addr . rc_family = AF_BLUETOOTH ;
addr . rc_psm = 1 ;
str2ba ( dest , &addr . rc_bdaddr ) ;
check = connect ( s , ( struct sockaddr * )&addr , sizeof ( addr ) ) ;

For L2CAP, type:

struct sockaddr_l2 addr;
char dest[18] = “<Bluetooth Address>” //put server’s bluetooth adapter address you can find address from command hciconfig -a.
addr . l2_family = AF_BLUETOOTH ;
addr . l2_psm = htobs(0x1001 ) ;
str2ba ( dest , &addr . l2_bdaddr ) ;
connect ( s , ( struct sockaddr * )&addr , sizeof ( addr ) ) ;

Now you can send data to the server:

if ( check == 0 ) {
status = send ( s , “Hi Subodh “ , 10 , 0 ) ;
}

Pairing with a Bluetooth-enabled mobile
Your mobile also has a server so that it can connect to a client, and send and receive files. For pairing your system with a mobile, first, you have to open a socket:

s = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

Now connect to the Bluetooth address of the mobile:

struct sockaddr_rc addr;
char dest[18] = “<Mobile Bluetooth Address>” ;
addr . rc_family = AF_BLUETOOTH ;
addr . rc_psm = 1 ;
str2ba ( dest , &addr . rc_bdaddr ) ;
connect ( s , ( struct sockaddr * )&addr , sizeof ( addr ) ) ;

As you run this program, your mobile server will receive a bounding accepting message.
Accept this connection and send the encryption key.
After sending the key from the mobile, your system will show a pairing confirmation window. Enter the same number that you entered in your mobile
You have now connected with the mobile’s server.
As an exercise, try to implement a Bluetooth headset profile (HSP).

References
[1] http://people.csail.mit.edu/albert/bluez-intro/c404.html#bzi-choosing
[2] http://en.wikipedia.org/wiki/Bluetooth_stack
[3] http://www.drdobbs.com/mobile/using-bluetooth/232500828?pgno=1
[4] http://en.wikipedia.org/wiki/List_of_Bluetooth_protocols
[5] http://www.eetimes.com/document.asp?doc_id=1275960
[6] http://en.wikipedia.org/wiki/Bluetooth
[7] https://wusewj-linux-books.googlecode.com/files/Essential%20Linux%20Device%20Drivers%5B2008,851p%5D.pdf