34.7.蓝牙

蓝牙是一种无线技术,用于在 2.4 GHz 无许可频段中创建个人网络,覆盖范围为 10 米。网络通常是由可携设备(如手机、掌上电脑和笔记本电脑)临时组成的。与 Wi-Fi 无线技术不同,蓝牙提供更高级的服务配置文件,如类似 FTP 的文件服务器、文件传输、语音传输、串行线路仿真等。

本节描述了在 FreeBSD 系统上使用 USB 蓝牙适配器。然后描述了各种蓝牙协议和工具。

34.7.1. 加载蓝牙支持

FreeBSD 中的蓝牙栈是使用 netgraph(4) 框架实现的。ng_ubt(4) 支持各种蓝牙 USB 适配器。基于 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 码进行,这是一个最多 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 档案进行网络访问可用于为单个蓝牙设备或多个蓝牙设备提供局域网访问。它还可以通过串行电缆仿真使用 PPP 网络连接 PC。

在 FreeBSD 中,这些配置文件通过 ppp(8) 和 rfcomm_pppd(8) Wrapper 实现,它将 Bluetooth 连接转换为 PPP 可用的形式。在使用配置文件之前,必须在 /etc/ppp/ppp.conf 中创建一个新的 PPP 标签。请参考 rfcomm_pppd(8) 了解示例。

在这个示例中,rfcomm_pppd(8) 用于在 DUNRFCOMM 频道上以 BD_ADDR 的 00: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 能让更高级别的协议和应用程序传输和接收长达 64 千字节的 L2CAP 数据包。

L2CAP 围绕通道的概念构建。通道是在基带连接之上的逻辑连接,其中每个通道以一对多的方式绑定到单个协议。多个通道可以绑定到同一协议,但一个通道不能绑定到多个协议。在通道上接收的每个 L2CAP 数据包都会定向到适当的更高级别协议。多个通道可以共享同一基带连接。

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

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

# 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),但用于蓝牙网络相关数据结构。下面的示例显示与上面的 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 协议模拟串行ports。RFCOMM 是一个简单的传输协议,另有用于模拟 RS-232(EIATIA-232-E)串行ports的附加规定。它支持两个蓝牙设备之间的最多 60 个同时连接(RFCOMM 通道)。

就 RFCOMM 而言,完整的通信路径包括在通信端点上运行的两个应用程序及其之间的通信段。RFCOMM 旨在涉及使用其所在设备串行ports的应用程序。通信段是从一个设备到另一个设备的直接连接的蓝牙链路。

RFCOMM 仅关心设备之间在直接连接情况下的连接,或者在网络情况下设备与调制解调器之间的连接。RFCOMM 可以支持其他配置,例如在一侧通过蓝牙无线技术通信并在另一侧提供有线接口的模块。

在 FreeBSD 中,RFCOMM 在蓝牙套接字层实现。

34.7.5.3. 服务发现协议(SDP)

服务发现协议(SDP)提供了一种方法,供客户端应用程序发现由服务器应用程序提供的服务的存在,以及这些服务的属性。服务的属性包括提供的服务类型或类别以及利用服务所需的机制或协议信息。

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

通常,SDP 客户端根据服务的某些期望特征搜索服务。然而,有时希望在没有关于服务的任何先前信息的情况下发现 SDP 服务器服务记录描述的服务类型。这种寻找任何提供的服务的过程称为浏览。

标准 FreeBSD 安装包含蓝牙 SDP 服务器 sdpd(8)和命令行客户端 sdpcontrol(8)。以下示例显示了如何执行 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 通道。根据服务的不同,用户可能需要注意一些属性。某些蓝牙实现不支持服务浏览,可能返回空列表。在这种情况下,可以搜索特定的服务。下面的示例显示了如何搜索 OBEX 对象推送(OPUSH)服务:

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

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

sdpd_enable="YES"

然后可以使用 sdpd(8)守护程序启动:

# service sdpd start

想要向远程客户端提供蓝牙服务的本地服务器应用程序将在本地 SDP 守护程序中注册该服务。这样的应用程序示例是 rfcomm_pppd(8)。若启动,它将在本地 SDP 守护程序中注册蓝牙局域网服务。

通过在本地控制信道发出 SDP 浏览查询,可以获取注册到本地 SDP 服务器的服务列表:

# sdpcontrol -l browse

34.7.5.4. OBEX Object Push(OPUSH)

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

OBEX 服务器和客户端由 obexapp 实现,可以使用 comms/obexapp 软件包或port进行安装。

OBEX 客户端用于从 OBEX 服务器推送和/或拉取对象。一个示例对象是名片或约会。OBEX 客户端可以通过 SDP 从远程设备获得 RFCOMM 信道号。这可以通过指定服务名称而不是 RFCOMM 信道号来实现。支持的服务名称有: IrMC,FTRN 和 OPUSH。也可以将 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 服务器将自动使用本地 SDP 守护程序注册 OPUSH 服务。下面的示例显示了如何启动 OBEX 服务器。

# obexapp -s -C 10

34.7.5.5。串行Port配置文件(SPP)

串行Port配置文件(SPP)能让蓝牙设备执行串行电缆模拟。该配置文件能让传统应用程序使用蓝牙作为电缆替代,通过虚拟串行port抽象化。

在 FreeBSD 中,rfcomm_sppd(1)实现了 SPP,并使用伪终端作为虚拟串行port抽象化。下面的示例显示了如何连接到远程设备的串行port服务。RFCOMM 通道无需在命令中指定,因为 rfcomm_sppd(1)可以通过 SDP 从远程设备获取它。要覆盖这一点,请在命令行上指定 RFCOMM 通道。

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

若连接,伪终端可以用作串行port:

# cu -l /dev/pts/6

伪终端被打印在标准输出上,可以被包装脚本读取:

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

34.7.6. 故障排除

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

# hccontrol -n ubt0hci write_node_role_switch 0

要显示蓝牙数据包,请使用第三方软件包 hcidump,可以通过 comms/hcidump 软件包或 port 安装。这个工具类似于 tcpdump(1),可以用来在终端上显示蓝牙数据包的内容,并将蓝牙数据包转储到文件。

最后更新于

FreeBSD 中文社区