来自Wi-Fi专家的声音

 

蓝牙的话题(4)

撰写于:2012年12月26日
作者:silex Wi-Fi专家

BlueZ是一个在Linux和Android上运行的开源蓝牙协议栈。蓝牙的安装系统是最流行的之一,关于BlueZ的介绍中,日语和英语资料都非常有限。本期对这个BlueZ进行简单的解说。

关于BlueZ
BlueZ由BlueZ项目(http://www.bluez.org/)发布。但是BlueZ的软件包几乎不包含像文档一样的东西,BlueZ的网站也几乎没有解说一样的文档。关于BlueZ的技术解说网站也几乎没有。虽然是“最流行的安装系统”,但是文档实在是太少了,真是不可思议。

BlueZ大致可分为“内核驱动程序”、“守护程序”、“应用程序”三部分。


BlueZ的架构

内核驱动器以bluetooth.ko为中心,包括hci_uart.ko、hci_usb.ko等物理层驱动器和rfco .ko,包含scoo .ko等协议驱动器。虽然这些是通过BlueZ项目开发的,但并没有通过bluez.org发布。linux内核(除非是非常旧的东西)标准,包含着内核驱动程序单体作为LinuxWireless (http://www.linuxwireless.org)与WiFi驱动一起打包,以compat-wireless的形式发布。
bluetooth.ko通过名为HCI插座的API(通过socket(AF蓝牙,sock_raw, btproto_hci)制作)与用户空间通信。据插口接近于直接控制芯片操作的层级,可以进行精细的控制,但如果要做简单的事情(例如交换链接键以达成配对),就需要花费很多时间,所以不太推荐直接从应用程序操作。

daemon是bluetoothd,这包括在BlueZ的软件包里。bluetoothd负责每个适配器的设定保存、链接键的管理、服务搜索协议(SDP)的守护程序、与上层应用程序的通信等。应用程序通过名为D-BUS的API与bluetoothd通信,bluetoothd可以根据需要更新内部数据库,HCI使用插口向芯片发送指令。

应用程序用于从用户空间设定和控制BlueZ, hciconfig和hcitool是其中的代表。hciconfig类似于以太网和WiFi中的ifconfig和iwconfig,可以启动和停止蓝牙适配器,进行操作设置等。hcitool中有各种各样的功能,最常用的是用于搜索外围设备的inq和scan,这与WiFi中的iwlist功能很相似。

BlueZ包的test/目录下有很多文件(C的源代码和Python脚本),例如simple-agent (Python脚本)使用的话可以进行限定的PIN交换和扫描(注),使用test-input的话,虽然可以通过键盘进行输入(也不是不能,接近的水平)等操作,但是例子几乎没有文档,使用方法只能读源代码进行解读。
※注:旧版BlueZ的解说中也有写着“使用passkey-agent的话可以用PIN配对”,但那是BlueZ-3.x时代的事了,4.x中不存在passkey-agent。

虽然不知道详细情况,但是Linux上的蓝牙功能是为了在Gnome等GUI上使用而致力于开发的,角色控制台(CUI)中使用几乎都被放弃了。因此,“原始”BlueZ只提供了运行蓝牙堆栈的基础和API功能,几乎不包含用户操作使用的功能。D-BUS原本是作为窗口系统中的消息总线而准备的,当bluetoothd的API作为D-BUS而不是管道或ioctl时感觉偏重GUI。用Java和Python等面向对象的高级语言来描述D-BUS很简单,但是用C语言来描述D-BUS的API的话,为了完成一件简单的事情,必须要折腾构造体和指针,所以我觉得和嵌入式编程不太相配…

只要在GUI上使用,几乎不需要意识到BlueZ的存在。打开GUI附带的蓝牙管理器,它就会自动打开蓝牙适配器被初始化,单击按钮输入必要条件,设备配对,驱动程序被结合,键盘,鼠标,耳机等Linux作为系统的一部分运行。

Gnome Bluetooth GUI マネージャ(Ubuntu Linux)
Gnome 蓝牙 GUI管理器(Ubuntu Linux)

CUI中的BlueZ
为数不多的BlueZ标准功能中,比较普通地使用(但是不知道什么方便)的是串行端口仿真器rfcomm。它可以作为客户端或服务器使用,与udevd通信以创建虚拟串行端口/dev/rfcommX,并为其开放/read/write/close通过执行alu或stty等,就可以像串行端口一样使用。

作为客户端使用时
rfcomm connect 00:80:92:12:34:56 5

作为服务器使用时
rfcomm listen 7

自变量最后的数字5或7被称为“信道号”,类似TCP/IP中的端口号。但是rfcomm中的信道号仅限于1 ~ 30的范围。

rfcomm是串行端口配置文件(SPP)的基础功能,但是仅rfcomm不能称为SPP。SPP服务器在服务检索协议(SDP)中通知包含自己具有的rfcomm的信道号的服务,SPP客户端必须检测那个并自动设定信道号码,不过,因为“原本的”rfcomm是人为指定的信道

BlueZ的另一个标准是被称为pand的网络功能。但是下载BlueZ的软件包普通configure;仅仅make是不能构建的,在configure的时候必须——加上enable-pand选项。pand作为Linux软件包的标准取决于发行版。 pand也具有服务器和客户端的功能。服务器正式名称为GN:Group ad-hoc Network hub或NAP:Network Access Point。GN和NAP的区别在于,前者在蓝牙中形成“封闭”的网络,而后者具有向外部路由的功能。另一方面,客户端正式名称为PANU:Personal Area Network User。(注:※)
※注: 这一省略语的命名感觉让人联想到CCITT X.25和OSI的规格书,有点像电话店的感觉啊。

作为客户端使用时
pand --connect 00:80:92:12:34:56

作为服务器使用时
pand --listen --role GN (或 NAP)


连接成功后会生成一个名为bnepX的虚拟接口,对此可以通过ifconfig发送IP地址。理论上是同样的“PAN配置文件”,所以从Linux到pand应该可以参加Windows的蓝牙网络,相反也应该可以,但是没有成功的尝试。不仅如此,即使是Linux之间,也会因为发行版的组合而时而运行时而不运行,说实话,我实在搞不懂是什么。

蓝牙 LE 的辅助
新版的BlueZ包含了有限的Bluetooth LE支持,但这也让人很难在几乎没有解说的情况下使用。

hciconfig中有leadv / noleadv功能,可以使用这个功能来指示LE广播的开始或停止发信。但是,因为(目前)不能指定广播中包含的信息,所以即使挂上lescan也只能看到MAC地址(附加信息变成“(unknown)”)。

发起LE展示
hciconfig -i hci0 leadv

停止LE展示
hciconfig -i hci0 noleadv


hcitool 中也有叫做lescan 的功能,使用这个就可以检索并显示LE的展示了。

扫描LE设备(涉及数据包发送)
hcitool lescan

扫描LE设备(不涉及数据包发送)
hcitool --passive lescan


如果是传统蓝牙的hcitool scan命令,在一定时间后会超时并返回提示,但lescan会永久搜索显示,除非输入^C才停止。

hcotool lescan 的实例
root@emachine:hcitool lescan
LE scan ...
00:80:92:12:34:56 (unknown)
00:80:92:12:34:56 (unknown)


更先进的LE支持功能是被称为gatttool的用户界面。这是一种基于命令行的蓝牙LE(或者说是传统蓝牙)的写字工具,但是三个t重叠的拼写让人感觉很随意。

使用gatttool获取Buffalo公司的BSBT4PT02BK邻近检测卡(LE proximity配置文件)的主要服务信息,可以得到如下结果。

gatttool的实例(1)
root@emachine:/home/sasaki/bt# gatttool -b 00:1b:dc:44:08:bb --primary
attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle = 0x0008, end grp handle = 0x000a uuid: 00001803-0000-1000-8000-00805f9b34fb
attr handle = 0x000b, end grp handle = 0x000d uuid: 00001802-0000-1000-8000-00805f9b34fb
attr handle = 0x000e, end grp handle = 0x0010 uuid: 00001804-0000-1000-8000-00805f9b34fb
attr handle = 0x0011, end grp handle = 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb


uuid最低的16bit值是GATT规范中规定的规定值,

1800=Generic Access
1803=Link Loss
1802=Immediate Alert
1804=Tx Power
180F=Battery Service

显示了该设备拥有的主要服务一览。GATT中还有一个叫“角色切换”的信息,它的动作与SNMP中的MIB walk相近。

gatttool的实例(2)
root@emachine:/home/sasaki/bt# gatttool -b 00:1b:dc:44:08:bb --characteristics
handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb
handle = 0x0009, char properties = 0x0a, char value handle = 0x000a, uuid = 00002a06-0000-1000-8000-00805f9b34fb
handle = 0x000c, char properties = 0x04, char value handle = 0x000d, uuid = 00002a06-0000-1000-8000-00805f9b34fb
handle = 0x000f, char properties = 0x02, char value handle = 0x0010, uuid = 00002a07-0000-1000-8000-00805f9b34fb
handle = 0x0012, char properties = 0x02, char value handle = 0x0013, uuid = 00002a19-0000-1000-8000-00805f9b34fb
handle = 0x0014, char properties = 0x02, char value handle = 0x0015, uuid = 00002a1a-0000-1000-8000-00805f9b34fb
handle = 0x0016, char properties = 0x12, char value handle = 0x0017, uuid = 00002a1b-0000-1000-8000-00805f9b34fb
handle = 0x0019, char properties = 0x02, char value handle = 0x001a, uuid = 00002a3a-0000-1000-8000-00805f9b34fb


如果在这里读取句柄0x0003,就会发现这是字符串“BSBT4PT02BK”。16bit UUID值2a00在GATT规范中是DEVICE NAME CHARACTERISTIC,因此可知该装置的装置名是“BSBT4PT02BK”…就是这样的情况。

gatttool的实例(3)
root@emachine:/home/sasaki/bt# # gatttool -b 00:1b:dc:44:08:bb char-read --handle=0x0003
Characteristic value/descriptor: 42 53 42 54 34 50 54 30 32 42 4b
Device Name = "BSBT4PT02BK"


总结
以上关于BlueZ的解说有些仓促,但是,有很多人会有“不知道是什么”这样的想法吧。与作为IP网络的一种形态的WiFi不同,蓝牙与应用程序紧密相连,仅仅从无线技术的层次来看,也不知道是什么,相反,从应用程序(手机与耳机的无线连接等)来看,蓝牙(BlueZ)的存在就被遮蔽了。即使在广阔的互联网上,关于BlueZ的解说也少得惊人,也许这与BlueZ的微妙定位有关。