• No results found

Character Byte Code

Chapter 11. Bluetooth in Linu

11.1 Host Controller Interface (HCI)

The Host Controller Interface (HCI) forms the interface between the software protocol stack and the Link Manager underneath it, which is implemented in the firmware of a Bluetooth device. Notice that this is a packet-oriented communication between HCI and the Link Manager rather than a device driver. The difference is that HCI does not access the register and the memory locations of a Bluetooth device directly. Instead, it sends command and data packets to the device and receives data packets and event-message packets from this device. This means that the Host Controller Interface offers a uniform interface for accessing the hardware.

11.1.1 Command Packets

There is a uniform packet format for command packets sent by HCI to the Link Manager. All packets are ordered in groups. In the command group (opcode group), we distinguish between individual commands (opcode commands). Each command packet consists of a 10-bit OCF (Opcode Command Field) and a 6-bit OGF (Opcode Group Field). There are the following command groups:

• Link control commands serve to establish a connection to other Bluetooth devices and to control the connection.

• Link policy commands serve to change parameters, which are used by the Link Manager to manage connections. For example, such commands can cause connections to switch into the hold mode.

• Host controller and baseband commands allow you to specify additional parameters for the behavior of the Link Manager (e.g., to filter event messages or to activate the flow control discussed further below).

• Information parameters offer a pure read access to values of a Bluetooth device, such as the size of the transmit buffer, the version number, and the 48-bit Bluetooth device address. In addition to these groups, there are the following groups: status parameters, testing commands, Bluetooth logo testing, and vendor-specific debug commands.

The following sections describe how command packets can be sent within the Bluetooth implementation in the Linux kernel.

hci_send_cnd() net/bluetooth/hci_core.c

This function is used to compose a command packet in the form of an sk_buff out of the passed

data, the OCF and OGF values, the length, and a pointer to parameters. The function

skb_queue_tail then appends this packet to the end of the command queue of the struct hci_dev of the Bluetooth device.

The structure hci_dev is defined in include/net/bluetooth/hci_core.h. In addition to the

command queue, it contains queues for transmit data. In addition to a number of other parameters, it includes four function pointers, to the functions open(), close(), flush(), and send() made

available by the Bluetooth device.

Finally, the function hci_send_cmd() invokes the function hci_sched_cmd(), which marks the hdev->cmd_task as ready to be executed. This tasklet was assigned to the device by the function tasklet_init() within the function call hci_register_init() (

net/bluetooth/hci_core.c) when the HCI support was initialized. In addition, there is a hdev->rx_task to receive data and another hdev->tx_task to send data. When the tasklet hdev->cmd_task runs, then the function hci_cmd_task() is invoked. This function invokes hci_send_frame().

hci_send_frame() net/bluetooth/hci_core.c

This function serves as a central transmit function for the HCI. This function serves not only to send command packets, but also to send data packets. It uses the entry int (*send) from the structure hci_dev to invoke the transmit function of the Bluetooth device, to which it passes the skb.

11.1.2 Event Packets

The time it takes to process different HCI commands can be different, Bluetooth implements

asynchronous communication. The results of a command are announced to HCI in the form of an event packet. In most cases, this is merely an event of the type Command Complete, which means that the command was successfully completed. A Bluetooth device can receive arbitrary packets by activating the tasklet hci_rx_task when the interrupt triggered by the incoming packet is handled. This tasklet

invokes the function hci_rx_task(). hci_rx_task() net/bluetooth/hci_core.c

This function is used to distinguish an incoming packet further by type. Incoming event packets are further processed by the function hci_event_packet(); accordingly, the functions

hci_acldata_packet() and hci_scodata_packet() are invoked for the ACL and SCO data

described further below.

Event packets are further distinguished by type of event in the function hci_event_packet(). For

example, the type Number of Completed Packets invokes the function hci_num_comp_pkts_evt().

This function evaluates the content of the event packet, which includes the number of packets actually sent per connection by the Bluetooth device. A handle negotiated between the Link Manager and HCI can be used to map the reported number of sent packets to a specific connection (an hci_conn

structure). This is done via a hash table in the HCI layer. The counter acl_cnt of struct hci_dev

is incremented by one for each acknowledged packet. Feedback on the number of packets sent serves the flow control described in the following section.

11.1.3 Data Packets

We distinguish between asynchronous connectionless (ACL) and synchronous connection-oriented (SCO) data packets. Both data types are sent when the tasklet hdev->tx_task becomes active, and

then the function hci_sched_acl() (net/bluetooth/hci_core.c) is executed. If flow

control for ACL data runs between HCI and the Link Manager, then we first have to check on whether ACL data may be sent.

Flow control is used to prevent the transmit buffer of the Bluetooth device from overflowing. This can happen, for example, when an application sends data faster than the Bluetooth device can transport it further? for instance, because the communication partner is temporarily not reachable. The initial size of the output buffer can be polled from HCI. The current size of the output buffer can be derived from event packets of the type Number of Completed Packets, described above. HCI assumes that the free output buffer becomes smaller with each packet it passes to the Link Manager. The actual current size can be learned only upon receipt of a new event packet.

Flow control in the Bluetooth protocol stack of the Linux kernel is handled by the function

hci_sched_acl(). In turn, this function invokes the function hci_low_acl_sent(): hci_low_acl_sent() net/bluetooth/hci_core.c

First, this function finds out the total number, num, of all connections known to the specified network

device. For each connection (represented by the structure hci_conn), the field acl_sent includes

the number of ACL data packets sent over this connection. This field is incremented during a

transmission, but decremented by the number of acknowledged packets over this connection when the described event packet Number of Completed Packets is received. In addition, the function

hci_low_acl_sent() identifies the connection with the smallest number of ACL packets sent,

which has to be smaller than 0xffff. If none of the existing connections meets these conditions, then

the function's return value is set to null. If there is such a connection, then the total number of acknowledged packets (acl_cnt entry in struct hci_dev) is divided by the number (num) of

connections. The result is returned by the parameter quote, and the identified connection is the

return value of the function. The number of acknowledged packets forms the transmit credit, which is distributed over all ready-to-send connections.

hci_sched_acl() net/bluetooth/hci_core.c

Using the quote calculated by the function hci_low_acl_sent(), this function tries to send ACL

data packets over the specified connection (by using the function hci_send_frame()). ACL data

packets may be sent as long as the queue is not empty, as long as the number of ACL packets to be formed from one skb does not exceed the transmit credit of the Bluetooth device, and as long as quote is not yet null. Both quote and the transmit credit stored in the hci_dev structure are

decremented by one for each packet sent. At the same time, the number of packets sent over this connection is incremented.

hci_sched_sco() net/bluetooth/hci_core.c

Only the transmit credit for SCO packets, included in the field sco_cnt of struct hci_dev, is

considered in the case of SCO data packets. There is no distribution over several connections for SCO connections. SCO data packets are simply sent until the transmit credit is used up.

11.1.4 Accessing the Host Controller Interface

The functionality of the Host Controller Interface (HCI) in Linux is available in different ways. Figure 11-1 shows that HCI can be accessed directly from the user space over a socket. This is normally a socket of the PF_BLUETOOTH socket family with protocol identifier BTPROTO_HCI und type SOCK_RAW. These sockets are created in the file net/bluetooth/hci_sock.c. The socket

interface is used to supply the usual BSD socket functions. An application can use these functions to send and receive data directly over HCI from and to the network.

Alternatively, an application can use ioctl() calls to access the Bluetooth device (e.g., to open, close,

or reset the device).

For higher protocol layers to be implemented in the Linux kernel, HCI functions are available over the macro EXPORT_SYMBOL. For example, the L2CAP protocol described in the next section accesses

these functions, including functions to register and deregister the HCI device (hci_register_dev()

and hci_unregister_dev()) and interfaces to higher protocols. For example, the functions hci_register_proto() and hci_unregister_proto() serve to register the higher-layer

protocol (e.g., L2CAP) that supplies a receive function or other functions to the HCI. The function

hci_register_notifier() is used by the higher-layer protocol to register itself with the notifier

chain of the device. (See Chapter 5.) The function hci_connect(), which sends a command

packet from HCI to the Link Manager (net/bluetooth/hci_core.c), is used to establish a

connection. The counterpart of this function is the function hci_disconnect(). The functions hci_send_acl(), hci_send_sco(), and hci_send_raw() are used to transmit, and the

function hci_recv_frame() is used to receive.

11.2 L2CAP

The Logical Link Control and Adaptation Protocol (L2CAP) handles tasks on the data-link layer in the Bluetooth protocol stack. It establishes ACL connections for the next lower layer, but does not transport pure audio data, which primarily is transported over SCO connections. In particular, the L2CAP

protocol is responsible for multiplexing data streams from higher layers to an ACL connection, because there must always be at most one ACL connection at a time between two Bluetooth devices. Other important tasks include the segmenting and reassembling of data packets to be able to send and receive the much larger packets of the higher-layer protocols despite the small packet sizes of the baseband layer. L2CAP supports packet sizes of up to 64 Kbytes.

To multiplex several data streams, L2CAP uses the abstraction of the channel. Each channel is allocated to one specific protocol. There are connection-oriented channels for point-to-point

communication and connectionless channels used for group communication. A simple signaling method is used to establish an L2CAP connection. The L2CAP protocol can also be accessed directly from the user space over a socket. This is normally a socket from the PF_BLUETOOTH socket family with

protocol identifier BTPROTO_L2CAP.

Now, when HCI receives an ACL packet, then it is passed to the receive function

l2cap_recv_frame(). If the channel identifier in the packet header is 0x0001, then it is a signaling

packet. Subsequently, the function l2cap_sig_channel() is invoked; otherwise, the function l2cap_data_channel() is invoked.

12cap_sig_channel() net/bluetooth/12cap_core.c

The type of signaling packet is recognized within this function and, depending on the type, an appropriate handling function is invoked:

switch (cmd.code) {

case L2CAP_CONN_REQ:

err = l2cap_connect_req(conn, &cmd, data); break;

case L2CAP_CONN_RSP:

err = l2cap_connect_rsp(conn, &cmd, data); break;

case L2CAP_CONF_REQ:

err = l2cap_config_req(conn, &cmd, data); break;

case L2CAP_CONF_RSP:

err = l2cap_config_rsp(conn, &cmd, data); break;

case L2CAP_DISCONN_REQ:

err = l2cap_disconnect_req(conn, &cmd, data); break;

case L2CAP_DISCONN_RSP:

err = l2cap_disconnect_rsp(conn, &cmd, data); break;

The following section uses the example of an incoming connection request from a remote

communication partner in the Bluetooth network to describe how the L2CAP protocol implementation works.

11.2.1 Connection Establishment Phase

When a request to establish a connection arrives from a remote communication partner, then the signaling code L2CAP_CONN_REQ is detected, and the function l2cap_connect_req() is invoked.

12cap_connect_req() net/bluetooth/12cap_core.c

This function first checks on whether there is a waiting socket for this connection request that matches exactly the source address of the Bluetooth device from which the connection request originates and which concurrently matches the PSM field. The PSM (Protocol/Service Multiplexer) field specifies the desired higher protocol (e.g., RFCOMM).

Such a socket has to have been previously created by an application with the command listen and the function l2cap_sock_listen(), and it has to be in blocking wait state after the function accept()

was invoked. This wait state is implemented in the function l2cap_sock_accept(), which uses the

function l2cap_accept_dequeue() to wait until the state sk->state switches from BT_LISTEN

to BT_CONNECTED.

The function l2cap_get_sock_listen(), which searches all sockets listening to the L2CAP

protocol, checks for a socket waiting for an incoming connection request. Subsequently, it ensures that there is not already a connection with the source address of the requesting Bluetooth device. Next, the pertinent sock structure is initialized. The state sk->state in BT_CONFIG and the new channel

with the function l2cap_chan_add() are added to the list of channels, conn->chan_list.

Subsequently, the function l2cap_send_rsp(), which, in turn, accesses the function

hci_send_acl() supplied by HCI, returns a L2CAP_CONN_RSP message to acknowledge the

connection request.

11.2.2 Configuration Phase

If there are no errors, then the next step walks through the configuration phase, before the connection can be used for data transmission. First, both ends send a configuration request (signaling code

L2CAP_CONF_REQ). The configuration phase can be completed successfully only if the configuration

request of the other end has been acknowledged and a positive acknowledgement of its own configuration request was made.

The end that received the connection request waits for a configuration request after successful completion of the connection establishment phase. When the connection request arrives, the function

l2cap_sig_channel() invokes the function l2cap_config_req(). 12cap_config_req() net/bluetooth/12cap.core.c

This function first uses l2cap_parse_conf_req() to evaluate the configuration options of the peer

and store them in the protinfo structure of the sock structure. However, the QoS option is

currently not evaluated. Next, the function l2cap_build_conf_rsp() is invoked. This function

uses l2cap_conf_output() to discover whether the peer's configuration options (currently only

the MTU) can be accepted. The function l2cap_send_rsp() is used to return a response.

Subsequently, the function l2cap_send_req() uses the function l2cap_build_conf_req() to

create and send a configuration request to the other end. Currently, only the MTU is considered.

12cap_config_rsq() net\bluetooth/12cap.core.c

This function handles the peer's response to the configuration request. If the peer sends a nonempty response, then the current implementation disconnects immediately. Otherwise, the configuration phase can be abandoned. The field sk->state is set to BT_CONNECTED and, starting with the

function call l2cap_chan_ready() (net/bluetooth/l2cap_core.c), the function pointer sk->state_change() is used to invoke the function sock_def_wakeup() (both in

net/core/sock.c), which eventually marks the process waiting at the socket as an executable

process.

11.2.3 Data Transmission Phase

This section describes the data transmission.

12cap_data_channel() net/bluetooth/12cap.core.c

The function l2cap_data_channel() is invoked when data packets are received. The first step is

to check for whether a connection is present in the list of channels, conn->chan_list, for the SCID

(Source Connection IDentification). This check is done by the function l2cap_get_chan_by_scid()

. After further checks, the data packet is put into the receive queue, and the function data_ready()

of the sock structure is invoked, which then informs the application that new data is ready.

Looking at things from the BSD socket interface, data is received at the socket interface over the socket call recvmsg, which is mapped to the function l2cap_sock_recvmsg(). In this respect,

there are no major differences from the implementations of other protocols that also use the function

skb_recv_datagram() (net/core/datagram.c). This function causes a blocking or

nonblocking wait for data in the input queue sk->receive_queue.

When sending, the socket call sendmsg() invokes the function l2cap_sock_sendmsg(), which uses

the function l2cap_chan_send() to prepare a packet and then uses hci_send_acl() to send it.