34.7.蓝牙

蓝牙是一种无线技术,用于在 2.4 GHz 非授权频段内创建个人网络,通常覆盖 10 米的范围。网络通常由便携设备(如手机、手持设备和笔记本电脑)按需形成。与 Wi-Fi 无线技术不同,蓝牙提供更高级别的服务协议,例如 FTP 类文件服务器、文件推送、语音传输、串行线路仿真等。

本节介绍了如何在 FreeBSD 系统上使用 USB 蓝牙适配器,并介绍了各种蓝牙协议和实用程序。

34.7.1. 加载蓝牙支持

FreeBSD 中的蓝牙栈是使用 netgraph(4) 框架实现的。广泛支持各种蓝牙 USB 适配器,使用 ng_ubt(4) 驱动程序。基于 Broadcom BCM2033 的蓝牙设备由 ubtbcmfw(4)ng_ubt(4) 驱动程序支持。3Com 蓝牙 PC 卡 3CRWB60-A 由 ng_bt3c(4) 驱动程序支持。基于串行和 UART 的蓝牙设备由 sio(4)ng_h4(4)hcseriald(8) 驱动程序支持。

在连接设备之前,确定它使用的是上述哪个驱动程序,然后加载该驱动程序。例如,如果设备使用 ng_ubt(4) 驱动程序:

# kldload ng_ubt

如果蓝牙设备将在系统启动时连接,可以通过将驱动程序添加到 /boot/loader.conf 来配置系统在启动时加载模块:

ng_ubt_load="YES"

加载了驱动程序以后,插入 USB 蓝牙适配器。如果驱动程序加载成功,控制台和 /var/log/messages 中应该会显示类似如下的输出:

ubt0: vendor 0x0a12 product 0x0001, rev 1.10/5.25, addr 2
ubt0: Interface 0 endpoints: interrupt=0x81, bulk-in=0x82, bulk-out=0x2
ubt0: Interface 1 (alt.config 5) endpoints: isoc-in=0x83, isoc-out=0x3,
      wMaxPacketSize=49, nframes=6, buffer size=294

要启动和停止蓝牙栈,请使用其启动脚本。在拔出设备之前,最好停止栈。启动蓝牙栈时,可能需要启动 hcsecd(8)。启动蓝牙栈时,输出应该类似如下:

# service bluetooth start ubt0
BD_ADDR: 00:02:72:00:d4:1a
Features: 0xff 0xff 0xf 00 00 00 00 00
<3-Slot> <5-Slot> <Encryption> <Slot offset>
<Timing accuracy> <Switch> <Hold mode> <Sniff mode>
<Park mode> <RSSI> <Channel quality> <SCO link>
<HV2 packets> <HV3 packets> <u-law log> <A-law log> <CVSD>
<Paging scheme> <Power control> <Transparent SCO data>
Max. ACL packet size: 192 bytes
Number of ACL packets: 8
Max. SCO packet size: 64 bytes
Number of SCO packets: 8

34.7.2. 查找其他蓝牙设备

主机控制器接口(HCI)提供了一种统一的方法来访问蓝牙基带功能。在 FreeBSD 中,为每个蓝牙设备创建一个 netgraph HCI 节点。有关更多详细信息,请参阅 ng_hci(4)

最常见的任务之一是查找 RF 范围内的蓝牙设备。此操作称为 查询。查询和其他 HCI 相关操作是通过 hccontrol(8) 完成的。下面的示例演示了如何查找哪些蓝牙设备在范围内。设备列表应在几秒钟内显示。请注意,远程设备只有在设置为 可发现 模式时才会响应查询。

% hccontrol -n ubt0hci inquiry
Inquiry result, num_responses=1
Inquiry result #0
       BD_ADDR: 00:80:37:29:19:a4
       Page Scan Rep. Mode: 0x1
       Page Scan Period Mode: 00
       Page Scan Mode: 00
       Class: 52:02:04
       Clock offset: 0x78ef
Inquiry complete. Status: No error [00]

BD_ADDR 是蓝牙设备的唯一地址,类似于网络卡的 MAC 地址。需要此地址来与设备进行进一步通信,并且可以为 BD_ADDR 分配一个人类可读的名称。有关已知蓝牙主机的信息包含在 /etc/bluetooth/hosts 文件中。以下示例演示了如何获取分配给远程设备的人类可读名称:

% hccontrol -n ubt0hci remote_name_request 00:80:37:29:19:a4
BD_ADDR: 00:80:37:29:19:a4
Name: Pav's T39

如果在远程蓝牙设备上执行查询,它将找到计算机并显示为“your.host.name (ubt0)”。本地设备的名称可以随时更改。

远程设备可以在 /etc/bluetooth/hosts 文件中分配别名。有关 /etc/bluetooth/hosts 文件的更多信息,请参阅 bluetooth.hosts(5)

蓝牙系统提供了一个点对点连接,或一个点对多点连接,可供多个蓝牙设备共享。以下示例演示了如何与远程设备创建连接:

% hccontrol -n ubt0hci create_connection BT_ADDR

create_connection 接受 BT_ADDR 以及 /etc/bluetooth/hosts 中的主机别名。

以下示例演示了如何获取本地设备的活动基带连接列表:

% hccontrol -n ubt0hci read_connection_list
Remote BD_ADDR    Handle Type Mode Role Encrypt Pending Queue State
00:80:37:29:19:a4     41  ACL    0 MAST    NONE       0     0 OPEN

连接句柄 在终止基带连接时非常有用,尽管通常不需要手动执行此操作。栈会自动终止不活跃的基带连接。

# hccontrol -n ubt0hci disconnect 41
Connection handle: 41
Reason: Connection terminated by local host [0x16]

键入 hccontrol help 获取完整的 HCI 命令列表。大多数 HCI 命令不需要超级用户权限。

34.7.3. 设备配对

默认情况下,蓝牙通信不进行身份验证,任何设备都可以与任何其他设备通信。蓝牙设备(如手机)可能选择要求身份验证才能提供特定的服务。蓝牙身份验证通常通过 PIN 码 完成,PIN 码是一个长度最多为 16 个字符的 ASCII 字符串。用户需要在两个设备上输入相同的 PIN 码。输入 PIN 码后,两个设备将生成一个 链接密钥。之后,链接密钥可以存储在设备中或持久化存储中。下次使用时,两个设备将使用先前生成的链接密钥。此过程称为 配对。请注意,如果任一设备丢失了链接密钥,必须重新进行配对。

hcsecd(8) 守护进程负责处理蓝牙身份验证请求。默认的配置文件是 /etc/bluetooth/hcsecd.conf。以下是为手机设置 PIN 码 1234 的示例配置:

device {
        bdaddr  00:80:37:29:19:a4;
        name    "Pav's T39";
        key     nokey;
        pin     "1234";
      }

PIN 码的唯一限制是长度。有些设备(如蓝牙耳机)可能有固定的内置 PIN 码。-d 选项强制 hcsecd(8) 在前台运行,这样可以方便地查看发生了什么。将远程设备设置为接收配对请求,并启动与远程设备的蓝牙连接。远程设备应指示配对已被接受并请求输入 PIN 码。输入 hcsecd.conf 中列出的相同 PIN 码。现在,计算机和远程设备已经配对。或者,也可以在远程设备上发起配对。

可以将以下行添加到 /etc/rc.conf,以便在系统启动时自动启动 hcsecd(8)

hcsecd_enable="YES"

以下是 hcsecd(8) 守护进程的示例输出:

hcsecd[16484]: Got Link_Key_Request event from 'ubt0hci', remote bdaddr 0:80:37:29:19:a4
hcsecd[16484]: Found matching entry, remote bdaddr 0:80:37:29:19:a4, name 'Pav's T39', link key doesn't exist
hcsecd[16484]: Sending Link_Key_Negative_Reply to 'ubt0hci' for remote bdaddr 0:80:37:29:19:a4
hcsecd[16484]: Got PIN_Code_Request event from 'ubt0hci', remote bdaddr 0:80:37:29:19:a4
hcsecd[16484]: Found matching entry, remote bdaddr 0:80:37:29:19:a4, name 'Pav's T39', PIN code exists
hcsecd[16484]: Sending PIN_Code_Reply to 'ubt0hci' for remote bdaddr 0:80:37:29:19:a4

34.7.4. 使用 PPP 配置文件进行网络访问

拨号联网(DUN)配置文件可用于将手机配置为无线调制解调器,以连接到拨号上网服务器。它还可以用于将计算机配置为接收来自手机的数据调用。

使用 PPP 配置文件的网络访问可为单个蓝牙设备或多个蓝牙设备提供 LAN 访问。它还可以提供通过串行电缆仿真进行的 PC 到 PC 连接。

在 FreeBSD 中,这些配置文件通过 ppp(8)rfcomm_pppd(8) 包装程序实现,该包装程序将蓝牙连接转换为 PPP 可以使用的格式。使用配置文件之前,必须在 /etc/ppp/ppp.conf 中创建一个新的 PPP 标签。有关示例,请参考 rfcomm_pppd(8)

以下示例使用 rfcomm_pppd(8) 通过 DUNRFCOMM 通道与远程设备(BD_ADDR00:80:37:29:19:a4)建立连接:

# rfcomm_pppd -a 00:80:37:29:19:a4 -c -C dun -l rfcomm-dialup

实际的通道号将通过 SDP 协议从远程设备获取。也可以手动指定 RFCOMM 通道,在这种情况下 rfcomm_pppd(8) 将不会执行 SDP 查询。使用 sdpcontrol(8) 查找远程设备上的 RFCOMM 通道。

为了通过 PPPLAN 服务提供网络访问,必须运行 sdpd(8),并在 /etc/ppp/ppp.conf 中为 LAN 客户端创建新条目。有关示例,请参考 rfcomm_pppd(8)。最后,在有效的 RFCOMM 通道号上启动 RFCOMMPPP 服务器。RFCOMMPPP 服务器将自动向本地 SDP 守护进程注册蓝牙 LAN 服务。以下是如何启动 RFCOMMPPP 服务器的示例:

# rfcomm_pppd -s -C 7 -l rfcomm-server

34.7.5. 蓝牙协议

本节提供了各种蓝牙协议、它们的功能以及相关实用程序的概述。

34.7.5.1. 逻辑链路控制和适配协议 (L2CAP)

逻辑链路控制和适配协议 (L2CAP) 为上层协议提供面向连接和无连接的数据服务。L2CAP 允许较高层协议和应用程序传输和接收最大为 64KB 的 L2CAP 数据包。

L2CAP 的核心概念是通道。通道是基带连接上的逻辑连接,每个通道绑定到一个单独的协议,采用一对多的方式。多个通道可以绑定到同一协议,但一个通道不能绑定到多个协议。每个通过通道接收到的 L2CAP 数据包会被定向到适当的上层协议。多个通道可以共享同一基带连接。

在 FreeBSD 中,每个 Bluetooth 设备会创建一个 netgraph L2CAP 节点。这个节点通常连接到下游的 Bluetooth HCI 节点和上游的 Bluetooth 套接字节点。L2CAP 节点的默认名称为 "devicel2cap"。更多细节请参考 ng_l2cap(4)

一个有用的命令是 l2ping(8),它可以用来 ping 其他设备。某些 Bluetooth 实现可能不会返回发送给它们的所有数据,因此以下示例中显示 0 字节 是正常的。

# l2ping -a 00:80:37:29:19:a4
0 bytes from 0:80:37:29:19:a4 seq_no=0 time=48.633 ms result=0
0 bytes from 0:80:37:29:19:a4 seq_no=1 time=37.551 ms result=0
0 bytes from 0:80:37:29:19:a4 seq_no=2 time=28.324 ms result=0
0 bytes from 0:80:37:29:19:a4 seq_no=3 time=46.150 ms result=0

l2control(8) 工具用于执行 L2CAP 节点上的各种操作。以下示例展示了如何获取本地设备的逻辑连接(通道)列表和基带连接列表:

% l2control -a 00:02:72:00:d4:1a read_channel_list
L2CAP channels:
Remote BD_ADDR     SCID/ DCID   PSM  IMTU/ OMTU State
00:07:e0:00:0b:ca    66/   64     3   132/  672 OPEN
% l2control -a 00:02:72:00:d4:1a read_connection_list
L2CAP connections:
Remote BD_ADDR    Handle Flags Pending State
00:07:e0:00:0b:ca     41 O           0 OPEN

另一个诊断工具是 btsockstat(1),它类似于 netstat(1),但用于 Bluetooth 网络相关的数据结构。以下示例展示了与 l2control(8) 相同的逻辑连接。

% btsockstat
Active L2CAP sockets
PCB      Recv-Q Send-Q Local address/PSM       Foreign address   CID   State
c2afe900      0      0 00:02:72:00:d4:1a/3     00:07:e0:00:0b:ca 66    OPEN
Active RFCOMM sessions
L2PCB    PCB      Flag MTU   Out-Q DLCs State
c2afe900 c2b53380 1    127   0     Yes  OPEN
Active RFCOMM sockets
PCB      Recv-Q Send-Q Local address     Foreign address   Chan DLCI State
c2e8bc80      0    250 00:02:72:00:d4:1a 00:07:e0:00:0b:ca 3    6    OPEN

34.7.5.2. 无线电频率通信 (RFCOMM)

RFCOMM 协议提供了通过 L2CAP 协议仿真串行端口的功能。RFCOMM 是一种简单的传输协议,额外提供了仿真 9 个 RS-232 (EIATIA-232-E) 串行端口电路的功能。它支持两个 Bluetooth 设备之间最多 60 个同时连接 (RFCOMM 通道)。

对于 RFCOMM 来说,一个完整的通信路径涉及在通信端点上运行的两个应用程序,它们之间有一个通信段。RFCOMM 旨在处理利用设备串行端口的应用程序。通信段是从一个设备到另一个设备的直接连接 Bluetooth 链接。

RFCOMM 仅关注设备之间的连接(在直接连接情况下)或设备和调制解调器之间的连接(在网络情况下)。RFCOMM 还可以支持其他配置,例如,一些模块通过 Bluetooth 无线技术与另一端进行通信,而另一端则提供有线接口。

在 FreeBSD 中,RFCOMM 是在 Bluetooth 套接字层实现的。

34.7.5.3. 服务发现协议 (SDP)

服务发现协议 (SDP) 为客户端应用程序提供了一种发现由服务器应用程序提供的服务及其属性的手段。服务的属性包括所提供的服务的类型或类别,以及利用该服务所需的机制或协议信息。

SDP 涉及 SDP 服务器和 SDP 客户端之间的通信。服务器维护着一个服务记录列表,描述了与服务器关联的服务的特性。每个服务记录包含有关单个服务的信息。客户端可以通过发出 SDP 请求,从 SDP 服务器维护的服务记录中检索信息。如果客户端或与客户端关联的应用程序决定使用某个服务,则必须打开与服务提供者的单独连接才能利用该服务。SDP 提供了发现服务及其属性的机制,但不提供利用这些服务的机制。

通常,SDP 客户端会根据某些期望的服务特性来搜索服务。然而,有时也希望在没有关于服务的先验信息的情况下,发现 SDP 服务器的服务记录中描述的服务类型。这种查找所有提供的服务的过程被称为浏览

Bluetooth SDP 服务器,sdpd(8),和命令行客户端,sdpcontrol(8),已包含在 FreeBSD 的标准安装中。以下示例展示了如何执行 SDP 浏览查询。

% sdpcontrol -a 00:01:03:fc:6e:ec browse
Record Handle: 00000000
Service Class ID List:
        Service Discovery Server (0x1000)
Protocol Descriptor List:
        L2CAP (0x0100)
                Protocol specific parameter #1: u/int/uuid16 1
                Protocol specific parameter #2: u/int/uuid16 1

Record Handle: 0x00000001
Service Class ID List:
        Browse Group Descriptor (0x1001)

Record Handle: 0x00000002
Service Class ID List:
        LAN Access Using PPP (0x1102)
Protocol Descriptor List:
        L2CAP (0x0100)
        RFCOMM (0x0003)
                Protocol specific parameter #1: u/int8/bool 1
Bluetooth Profile Descriptor List:
        LAN Access Using PPP (0x1102) ver. 1.0

请注意,每个服务都有一个属性列表,例如 RFCOMM 通道。根据服务的不同,用户可能需要注意其中一些属性。某些 Bluetooth 实现可能不支持服务浏览,并可能返回空列表。在这种情况下,可以尝试搜索特定的服务。以下示例展示了如何搜索 OBEX 对象推送 (OPUSH) 服务:

% sdpcontrol -a 00:01:03:fc:6e:ec search OPUSH

在 FreeBSD 上向 Bluetooth 客户端提供服务是通过 sdpd(8) 服务器完成的。可以在 /etc/rc.conf 中添加以下行:

sdpd_enable="YES"

然后,可以通过以下命令启动 sdpd(8) 守护进程:

# service sdpd start

希望向远程客户端提供 Bluetooth 服务的本地服务器应用程序将服务注册到本地 SDP 守护进程。一个这样的应用程序示例是 rfcomm_pppd(8)。待启动,它将与本地 SDP 守护进程注册 Bluetooth LAN 服务。

可以通过发出 SDP 浏览查询来获取本地 SDP 服务器注册的服务列表:

# sdpcontrol -l browse

34.7.5.4. OBEX 对象推送 (OPUSH)

对象交换 (OBEX) 是一种广泛使用的协议,用于移动设备之间的简单文件传输。其主要用途是在红外通信中,用于笔记本电脑或 PDA 之间的通用文件传输,以及用于在手机和其他具有个人信息管理器 (PIM) 应用程序的设备之间发送名片或日历条目。

OBEX 服务器和客户端由 obexapp 实现,可以通过 comms/obexapp 软件包和 Ports 进行安装。

OBEX 客户端用于从 OBEX 服务器推送和/或拉取对象。示例对象包括名片或约会。OBEX 客户端可以通过 SDP 从远程设备获取 RFCOMM 通道号。这可以通过指定服务名称而不是 RFCOMM 通道号来完成。支持的服务名称包括:IrMCFTRNOPUSH。也可以将 RFCOMM 通道作为数字指定。以下是一个 OBEX 会话的示例,其中从手机中拉取设备信息对象,并将一个新的对象(名片)推送到手机的目录中。

% obexapp -a 00:80:37:29:19:a4 -C IrMC
obex> get telecom/devinfo.txt devinfo-t39.txt
Success, response: OK, Success (0x20)
obex> put new.vcf
Success, response: OK, Success (0x20)
obex> di
Success, response: OK, Success (0x20)

为了提供 OPUSH 服务,必须运行 sdpd(8),并且必须创建一个根文件夹,所有传入的对象将存储在该文件夹中。根文件夹的默认路径是 /var/spool/obex。最后,在有效的 RFCOMM 通道号上启动 OBEX 服务器。OBEX 服务器将自动将 OPUSH 服务注册到本地 SDP 守护进程。以下是启动 OBEX 服务器的示例。

# obexapp -s -C 10

34.7.5.5. 串行端口配置文件 (SPP)

串行端口配置文件 (SPP) 允许 Bluetooth 设备执行串行电缆仿真。此配置文件允许传统应用程序通过虚拟串行端口抽象,使用 Bluetooth 替代电缆。

在 FreeBSD 中,rfcomm_sppd(1) 实现了 SPP,并且使用伪终端 (pseudo tty) 作为虚拟串行端口抽象。以下示例展示了如何连接到远程设备的串行端口服务。由于 rfcomm_sppd(1) 可以通过 SDP 从远程设备获取 RFCOMM 通道,因此不需要指定 RFCOMM 通道。若要覆盖此设置,可在命令行中指定 RFCOMM 通道。

# rfcomm_sppd -a 00:07:E0:00:0B:CA -t
rfcomm_sppd[94692]: Starting on /dev/pts/6...
/dev/pts/6

连接后,可以使用伪终端作为串行端口:

# cu -l /dev/pts/6

伪终端将输出到标准输出,并且可以通过包装脚本读取:

PTS=`rfcomm_sppd -a 00:07:E0:00:0B:CA -t`
cu -l $PTS

34.7.6. 故障排除

默认情况下,当 FreeBSD 接受新连接时,它会尝试执行角色切换并成为主设备。一些不支持角色切换的旧 Bluetooth 设备将无法连接。由于角色切换是在建立新连接时执行的,因此无法询问远程设备是否支持角色切换。然而,可以使用 HCI 选项在本地端禁用角色切换:

# hccontrol -n ubt0hci write_node_role_switch 0

要显示 Bluetooth 数据包,可以使用第三方软件包 hcidump,该软件包可以通过包或 Port comms/hcidump 安装。此工具类似于 tcpdump(1),可以用于显示 Bluetooth 数据包的内容到终端,并将 Bluetooth 数据包转储到文件中。

最后更新于