summaryrefslogtreecommitdiffstats log msg author committer range
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425  .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */\documentclass[11pt]{article} \usepackage[utf8]{inputenc} \usepackage{graphicx} \usepackage{fancyhdr} \usepackage{url} \pagestyle{fancy} \lhead{} \chead{} \rhead{} \fancyfoot[C] {This document is confidential} \fancyfoot[R] {\thepage} \fancyhead[C] {BlueZ Architecture} \fancyhead[R] {\thepage} \setlength{\parskip}{10pt} \title{BlueZ Architecture} \author{João Paulo Rechi Vita \\ jprvita@openbossa.org \and Claudio Takahasi \\ claudio.takahasi@openbossa.org} \begin{document} \maketitle \newpage \tableofcontents \newpage \section{Introduction} This document describes the BlueZ architecture. BlueZ is the official Linux Bluetooth protocol stack. It is an Open Source project distributed under GNU General Public License (GPL). \section{Overview} \begin{figure}[h!] \begin{center} \includegraphics[scale=0.53]{BlueZ-Architecture.png} \caption{BlueZ Architecture} \label{fig:bluez-architecture} \end{center} \end{figure} BlueZ has three major components: kernel-level routines, bluetoothd daemon and user-level tools. The kernel is responsible for managing the Bluetooth hardware resources attached to the system handling manufacturer hooks, and providing an interface to the userspace. bluetoothd is a root level daemon responsible for providing a D-Bus interface to allow user applications to manage adapters, devices, and services. An overview of how these pieces fit together is depicted on Figure \ref{fig:bluez-architecture} \section{Linux Bluetooth kernel architecture} Linux Bluetooth kernel subsystem consist of several layers: \begin{enumerate} \item Bluetooth Core \subitem HCI device and connection manager, scheduler \subitem SCO audio links \subitem L2CAP (Logical Link Control and Adaptation Protocol) \subitem SMP (Security Manager Protocol) on LE (Low Energy) links \item HCI Device drivers (Interface to the hardware) \item RFCOMM Module (RFCOMM Protocol) \item BNEP Module (Bluetooth Network Encapsulation Protocol) \item CMTP Module (CAPI Message Transport Protocol) \item HIDP Module (Human Interface Device Protocol) \end{enumerate} Low Energy support changed the Bluetooth Core layer only. SMP and Signaling L2CAP fixed channels are not exposed to the userspace. Connection Parameter Update Procedure is handled completely inside the kernel. Acting as a master, BlueZ kernel accepts all valid parameters. At the moment, there isn't API to allow the userspace to initiate or reject the procedure. Security Manager is exposed to the userspace through the Management Interface. Pairing procedure can be triggered from the userspace by changing socket security level, sending HCI commands, or sending Pair Management Command. However, the exchanged keys are available through the Management events only, making this new Bluetooth kernel interface mandatory if security is required. \section{Linux Bluetooth userspace architecture} BlueZ userspace is composed by {\em bluetoothd}, libbluetooth, and command line tools. {\em bluetoothd} is the daemon responsible for the configuration of the Bluetooth modules in the kernel, and for providing user level APIs to manage local adapters and control device creation procedure. \subsection{core} BlueZ core provides the abstraction to manage adapters, devices, services discovery, and security. Service (Profiles) plugins are implemented on the top of it. The major entities of the core are: adapter, device, sdp, agent for authorization and pairing, and GAttrib. In BlueZ, create a device means to get from the remote the services information, and to pair with it (CreatePairedDevice). BR/EDR and Bluetooth Low Energy uses the same API to discover devices and to manage pairing, the user does not need to know the adapters capabilities. The abstraction is implemented in the kernel and {\em bluetoothd} daemon. Service plugins are in general device driver(s) for a specific Bluetooth service. The design is based on the kernel device drivers: when the device is created, plugins are probed based on the supported UUIDs. It is analogous to kernel device driver ids. When a remote device exposes more than one service, each plugin gets a reference to the device {\em object}. Standard device discovery takes 10.12 seconds (defined in the Bluetooth GAP specification). For dual mode controllers, the GAP specification recomends a Interleaved Discovery Procedure: 5.12s inquiring followed by 5.12s scanning. In BlueZ, the discovery procedure works over both interfaces: Management, and standard HCI command interface. The abstraction is implemented by the {\em adapter\_ops} plugin, which hides from the {\em bluetoothd} upper layer the kernel interface in use. Management Interface has higer priority: if it is enabled in the kernel the default interface will be set to Management. Name resolution is part of the device discovery procedure for BlueZ. Since there aren't restrictions prohibiting to switch the order of the Interleave Discovery, BlueZ executes LE scanning before inquiry to reduce the discovery state machine complexity. Bonding for BLE works only over Management Interface. Pairing can be started increasing the socket security level, however the link keys, and authentication method setup requires Management Interface. \subsection{libs} BlueZ libs (a.k.a libbluetooth) is a development library which provides common functions and structures that can be used by Linux C programmers. libbluetooth usage is not encouraged, nowadays bluetoothd exposes friendly IPC methods (over D-Bus) which covers the most common operations. Usage of libbluetooth can be also introduce potential race conditions with bluetoothd operations. The common functions declarations related to adapter setup, device and service discovery can be found in BlueZ headers: {\em lib} directory of the userspace source code repository. %\subsection{Standard Bluetooth Services} % %\subsubsection{audio} %\subsubsection{input} %\subsubsection{network} \subsection{Management Interface} The Management Interface ({\em mgmtops} plugin) is a new interface for the userspace to communicate with the kernel. Its purpose is to remove the raw HCI sockets from userspace and replace the deprecated {\em hciops} plugin (old interface). Some advantages of {\em mgmtops} plugin in comparison with {\em hciops} plugin: \begin{itemize} \item Command queues and synchronization: All HCI traffic is handled by the kernel, so the risk of conflicts between kernel and userspace is avoided. \item Blocking operations: No need to use the blocking ioctl interface to e.g. power on/off adapters. Asynchronous messages are used, so blocking issues are solved as well. \item Distributed security policy and logic: user interaction and link key storage is handled in userpace and kernel handles link key requests. \item Early-tracing capability: special tracing socket will permit userspace catch all HCI traffic since first moment which adapter is plugged. \end{itemize} There is a layer called {\em adapter operations} (\verb|src/adapter.c|) that describes how to communicate with kernel side. For the management interface, this layer is implemented in \verb|plugins/mgmtops.c|. The MGMT interface is enabled by default on recent Linux kernel tree. It is still necessary to enable the LE support, so it can be used with LE devices. There are two ways to enable LE support: \begin{enumerate} \item If the Bluetooth subsystem is compiled as module, it can be enabled while loading the {\em bluetooth} module: \begin{verbatim} $sudo modprobe bluetooth enable_le \end{verbatim} \item Otherwise, if it is built-in, or the module is already loaded, enable it at runtime with: \begin{verbatim}$ echo 1 | sudo tee /sys/module/bluetooth/parameters/enable_le \end{verbatim} \end{enumerate} To verify that LE support is enabled, use: \begin{verbatim} \$ cat /sys/module/bluetooth/parameters/enable_le \end{verbatim} It will show \verb|Y| if LE support is enabled. BlueZ will use mgmtops automatically instead of hciops if it detects that the kernel has support for mgmt. Note that all LE development is being implemented only for the management interface. No support or updates to hciops will be provided. Detailed information regarding management interface is available at {\em doc/mgmt-api.txt}. For a technical introduction and rationale, see at BlueZ homepage \cite{bzhp}. \subsection{Security Manager} The Security Manager (SM) defines the protocol and behavior to manage pairing and key distribution, authentication and encryption between LE devices. The device in the master role shall initiate the Security procedures and the device in the slave role shall respond. The slave will send to the master a Security Request command and it may encrypt the link or reject de request. In the BlueZ, only the minimum from Security Manager was implemented. Currently, only the method {\em Just Works} is supported (method provides no protection against eavesdroppers or man in the middle attacks during the pairing process). In BlueZ API, there are two methods to connect and/or pair with devices, {\em CreateDevice} and {\em CreatePairedDevice}. {\em CreateDevice} creates a new object path for a remote device and connects to the device. It will retrieve all SDP records. Note that this method will fail if a path for the remote device already exists. {\em CreatePairedDevice} shares some characteristics with {\em CreateDevice}. It creates object path (if not exists), connects to the remote device and then initiates the pairing. It will fail if the pairing already exists. Consequently there is the option of create a device connection with {\em CreateDevice} and pair after with {\em CreatePairedDevice}. Additionally, we can increase the connection security with the \verb|bt_io_set()| function, setting the level to \verb|BT_IO_OPT_SEC_LEVEL|. After that, a security request is sent to the master and the security process is initiated. \subsection{Services over GATT} The Generic Attribute Profile (GATT) defines a service framework for discovering services, and reading and writing characteristics using Attribute Protocol. A service is composed by service declaration and characteristic definitions. Attribute is the basic element used to describe services and characteristics. Currently, the adopted GATT based services run over Low Energy transport only. However, BlueZ architecture supports to run GATT services over both transports: BR/EDR and Low Energy. For BR/EDR, L2CAP PSM 0x001F is reserved for ATT. For Low Energy, the fixed L2CAP channel ID 0x0004 is reserved for ATT protocol. ATT is a sequential request-response protocol. A client shall not send a second request before receiving the response of the first request. In order to manage the restrictions imposed by the protocol, an abstraction called GAttrib has been created, allowing to share the same socket between multiple services. Roughly speaking, GAttrib is a command/response queue shared between multiple local GATT profiles (server and/or client roles). BlueZ exposes a Generic Attribute API \footnote{doc/attribute-api.txt} and Profile specific APIs. Generic Attribute API is suitable for proprietary services and services that doesn't require to access low level platform services. Proximity Path Loss is an example, RSSI needs to be monitored on regular intervals to calculate the path loss. It is not related to GATT/ATT and read the RSSI requires permission to send a HCI command. The reason behind GATT Profile specific API hide from the user GATT/ATT internals and move the qualification for the stack instead of the upper layer GATT applications. \subsubsection{GAttrib and ATT connection callbacks} Usually, there is only one GAttrib instance for each device connection, which is destroyed when the connection is terminated. In order to support a multiple profile scenario, GAttrib instances are reference counted. Therefore, profiles need to hold at least one reference to a GAttrib for as long as the connection is necessary, and drop this reference when the connection is no longer needed. It is possible to run custom code when a connection is established or terminated by using {\em ATT connection callbacks} (or attio callbacks, for short). These callbacks should be registered whenever the GATT profile has intent to communicate with a remote device. When implementing attio callbacks, it is important to make sure there is a valid reference to the current GAttrib as long as there is a need to use the active connection. \subsubsection{Generic Attribute API} Generic Attribute is a GATT client API based on concept of characteristics. At the moment BlueZ supports dual mode adapters only, due the GAP restrictions dual mode controllers should not send connectable advertise events. Meaning the LE connection should be always started by the BlueZ host. ATT channel is shared between several modules in BlueZ. Upper layer applications using this API should register a watcher to control connections, and to receive notifications/indications. \subsubsection{Proximity} The Proximity profile specification defines the behavior related to the spatial relationship between devices (how the device will act when the connection is lost or the path loss increases, etc.). It includes two roles: the Proximity Reporter (GATT server) and the Proximity Monitor (GATT client). A device that supports the Proximity Reporter role shall implement the Link Loss service \cite{lls}, and optionally the Immediate Alert \cite{ias} and TX Power \cite{txp} services. A device that supports the Proximity Monitor role should contain an application that interacts with the Link Loss service and optionally the Immediate Alert and TX Power services. This application should allow the user to set the alert levels. This profile is implemented in BlueZ and has a specific D-Bus API (described in {\em doc/proximity-api.txt} located on BlueZ source code) for both roles. For Monitor role there is: \begin{enumerate} \item Methods: GetProperties(), SetProperty() \item Signals: PropertyChanged() \item Properties: SignalLevel, LinkLossAlertLevel, ImmediateAlertLevel \end{enumerate} For Reporter role: \begin{enumerate} \item Methods: GetProperties() \item Signals: PropertyChanged() \item Properties: ImmediateAlertLevel, LinkLossAlertLevel \end{enumerate} The upper layer application defines business logic. In the case of the Monitor {\em ImmediateAlertLevel} property is exported to allow the application to select the alert level for a given device. For Proximity Reporter, this API design allows to trigger actions or play distinct alerts/sound per device. \subsubsection{Find Me} The Find Me profile \cite{fdmp} defines the behavior related to pressing a button on one device causing an alert or similar behavior on the peer device. It includes two roles: Find Me target role (GATT server) and the Find Me Locator role (GATT client). The Find Me Target shall have only one instance of the Immediate Alert Service (IAS). In BlueZ, the service implementation is shared with the Proximity profile (Reporter role), because it also uses the same IAS instance. The same applies to the client side: Find Me Locator and Proximity Monitor share the same D-Bus interface. Note that even if a peer device only supports one profile (either Proximity or Find Me), the API will still work at least for the shared {\em Immediate Alert} functionality. \subsubsection{Thermometer} This profile is used to interact with data gathered from temperature sensors. There are two roles in this profile: {\em Thermometer} and {\em Collector}. For devices that support {\em Thermometer Role}, thermal data is stored and exposed to {\em Collector}. It is mandatory to have {\em Device Information} \cite{dis} service (general device characteristics) and {\em Health Thermometer} \cite{hts} service (temperature measurements). The {\em Collector Role} connects to {\em Thermometer} to obtain health temperatures. {\em Device Information} \cite{dis} service is optional, but {\em Health Thermometer} \cite{hts} service is mandatory. {\em Thermometer} \cite{htp} profile is implemented in BlueZ and accessible via D-Bus (described in {\em doc/thermometer-api.txt}). Under \verb|org.bluez.Thermometer| interface, there is: \begin{enumerate} \item Methods: SetProperty(), GetProperties(), RegisterWatcher(), UnregisterWatcher(), EnableIntermediateMeasurement(), DisableIntermediateMeaturement() \item Signals: PropertyChanged() \item Properties: Intermediate, Interval, Maximum, Minimum \end{enumerate} The method \verb|RegisterWatcher| receives a Watcher. That object should implement the \verb|MeasurementReceived| method with a dict parameter: \begin{verbatim} { "Exponent" : int8, "Mantissa" : int32, "Unit" : ("Celsius" or "Fahrenheit"), "Time" : uint64, "Type" : ("Armpit", "Body", "Ear", "Finger", "Intestines", "Mouth", "Rectum", "Toe", "Tympanum"), "Measurement" : ("Final" or "Intermediate") } \end{verbatim} The \verb|Time| value is expressed in seconds since epoch. The temperature value is represented by \verb|(mantissa) x (10**exponent)|. %\subsubsection{Time} \section{Contact channels} \begin{thebibliography}{9} \bibitem{bzhp}The upcoming Management Interface. \url{www.bluez.org/the-management-interface} \bibitem{lls}Link Loss service. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=239391} \bibitem{ias}Immediate Alert service. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=239390} \bibitem{txp}TX Power service. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=239393} \bibitem{fdmp}Find Me profile. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=239389} \bibitem{htp}Health Thermometer profile. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=238687} \bibitem{hts}Health Thermometer service. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=238688} \bibitem{dis}Device Information service. \url{https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=244369} \end{thebibliography} \end{document}