蓝牙地址的定义:
system/bt/types/raw_address.h
#pragma once
#include <string>
/** Bluetooth Address */
class RawAddress final {
public:
static constexpr unsigned int kLength = 6;
// 蓝牙地址必须比是6字节长
uint8_t address[kLength];
RawAddress() = default;
RawAddress(const uint8_t (&addr)[6]);
bool operator<(const RawAddress& rhs) const {
return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
}
bool operator==(const RawAddress& rhs) const {
return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
}
bool operator>(const RawAddress& rhs) const { return (rhs < *this); }
bool operator<=(const RawAddress& rhs) const { return !(*this > rhs); }
bool operator>=(const RawAddress& rhs) const { return !(*this < rhs); }
bool operator!=(const RawAddress& rhs) const { return !(*this == rhs); }
bool IsEmpty() const { return *this == kEmpty; }
std::string ToString() const;
// Converts |string| to RawAddress and places it in |to|. If |from| does
// not represent a Bluetooth address, |to| is not modified and this function
// returns false. Otherwise, it returns true.
static bool FromString(const std::string& from, RawAddress& to);
static bool IsValidAddress(const std::string& address);
static const RawAddress kEmpty; // 00:00:00:00:00:00
static const RawAddress kAny; // FF:FF:FF:FF:FF:FF
};
inline std::ostream& operator<<(std::ostream& os, const RawAddress& a) {
os << a.ToString();
return os;
}
在system/bt/types/raw_address.cc中
#include "raw_address.h"
#include <base/strings/string_split.h>
#include <base/strings/stringprintf.h>
#include <stdint.h>
#include <algorithm>
#include <vector>
// 静态断言,不满足6字节大小,编译直接给你抛一个失败
static_assert(sizeof(RawAddress) == 6, "RawAddress must be 6 bytes long!");
const RawAddress RawAddress::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
const RawAddress RawAddress::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
RawAddress::RawAddress(const uint8_t (&addr)[6]) {
std::copy(addr, addr + kLength, address);
};
std::string RawAddress::ToString() const {
return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", address[0],
address[1], address[2], address[3], address[4],
address[5]);
}
bool RawAddress::FromString(const std::string& from, RawAddress& to) {
RawAddress new_addr;
if (from.length() != 17) return false;
std::vector<std::string> byte_tokens =
base::SplitString(from, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (byte_tokens.size() != 6) return false;
for (int i = 0; i < 6; i++) {
const auto& token = byte_tokens[i];
if (token.length() != 2) return false;
char* temp = nullptr;
new_addr.address[i] = strtol(token.c_str(), &temp, 16);
if (*temp != '\0') return false;
}
to = new_addr;
return true;
}
bool RawAddress::IsValidAddress(const std::string& address) {
RawAddress tmp;
return RawAddress::FromString(address, tmp);
}
没什么深奥的内容,保证6个字节大小,格式为"%02x:%02x:%02x:%02x:%02x:%02x"。
上面是代码侧关于蓝牙地址格式的定义。下面将关于蓝牙地址的分配。
关于蓝牙地址,以BLUETOOTH CORE SPECIFICATION Version 5.2为例,可以参考Vol 2 Part B 1.2和Vol 6 Part B 1.3部分。
对于同时支持经典蓝牙和低功耗蓝牙的双模设备,是有两个蓝牙地址的。
1. BD_ADDR
每个蓝牙设备都应分配一个唯一的 48 位蓝牙设备地址 (BD_ADDR)。
地址应是根据 IEEE 802-2014 标准第 8.2 节(“通用地址”)创建的 48 位扩展唯一标识符 (EUI-48) 。
创建有效的 EUI-48 需要从 IEEE 注册机构获得以下 MAC 地址块类型之一:
• MAC Address Block Large (MA-L)
• MAC Address Block Medium (MA-M)
• MAC Address Block Small (MA-S)
网站IEEE SA - Registration Authority上可以获取上述MAC地址块信息。如下为EUI-48的结构(见文档)。
下图为BD_ADDR的格式,由LAP+UAP+NAP三部分组成,箭头所指方向从高位到低位。对应上图中的EUI-48的结构,NAP+UAP组成24-bit的OUI,即MAC地址块类型为MA-L;LAP为24-bit的扩展。
BD_ADDR 可以取任何值,除了那些将具有 64 个保留的 LAP 值中的任何一个用于一般和专用查询的值。 保留的 LAP 地址为 0x9E8B00-0x9E8B3F。一般查询LAP为0x9E8B33。只要使用其中一个保留的 LAP 地址,默认检查初始化 (DCI) 就用作 UAP,DCI 定义为 0x00(十六进制),即UAP写0x00。
NAP(Non-significant Address Part)非重要地址部分,是IEEE分配的OUI的一部分。
UAP(Upper Address Part)高位地址部分,也是IEEE分配的OUI的一部分。
LAP(Lower Address Part)低位地址部分,由vendor厂商分配。
以我手上的某台小米设备中的蓝牙地址"94:d3:31:f6:01:46"为例,在Welcome to The Public Listing For IEEE Standards Registration Authority中输入检索,可以发现是小米公司申请注册的。
如果想通过adb的方式获取手机的蓝牙地址,可以通过如下的方式:
adb shell settings get secure bluetooth_address
另外,UAP和LAP这两部分与蓝牙跳频序列有关,如下所示:
2. LE Address
使用设备地址和地址类型来标识设备。
地址类型指示公共设备地址或随机设备地址。公共设备地址和随机设备地址的长度均为 48 位。
设备应至少使用一种类型的设备地址,也可以包含两种类型。
设备的身份地址是它在传输的数据包中使用的公共设备地址或随机静态设备地址。如果一个设备使用可解析的私有地址,它也应该有一个身份地址。
每当比较两个设备地址时,比较应包括设备地址类型(即如果两个地址具有不同类型,即使两个 48 位地址相同,它们也不同)。
2.1 LE 公共设备地址
公共设备地址应根据Core Spec [Vol 2] B 部分第 1.2 节创建,如上文所述。但对 LAP 值的限制不适用,除非公共设备地址也将用作 BR/EDR 控制器的 BD_ADDR。
2.2 LE 随机设备地址
随机设备地址可以是以下之一:
- 静态地址
- 私有地址
具体子类型由随机设备地址的两个最高有效位指示,如表1.2所示。
2.2.1 静态设备地址
静态地址是随机生成的 48 位地址,应满足以下要求:(也就是随机部分不能全0或者全1)
- 地址的随机部分至少有一位为 0 ;
- 地址的随机部分至少有一位为 1;
高位两位0b11由上表1.2规定。
设备在初始化后不得更改其静态地址值,直到设备重新上电 。
如果更改设备的静态地址,则存储在对等设备中的地址将无效,并且将失去使用旧地址重新连接的能力。
2.2.2 私有设备地址生成
私有地址可以是以下两种子类型之一:
- 不可解析的私有地址(Non-resolvable private address)
- 可解析的私有地址( Resolvable private address)
要生成不可解析的地址,设备应生成具有以下要求的 48 位地址:
- 至少地址的随机部分的一位应为 1
- 地址的随机部分的至少一位应为 0
- 地址不应等于公共地址
不可解析私有地址的格式如图1.3所示。
要生成可解析的私有地址,设备必须具有本地身份解析密钥 (IRK) 或对等身份解析密钥 (IRK)。可解析的私有地址应使用 IRK 和随机生成的 24 位数字生成。随机数称为 prand,应满足以下要求:
- prand 的随机部分至少有一位为 0
- prand 的随机部分至少有一位为 1