Android上的蓝牙低功耗专用与公共地址

时间:2014-05-05 11:30:01

标签: android bluetooth-lowenergy android-bluetooth

蓝牙低功耗设备由其地址唯一标识(在Android API中,他们称之为MAC地址,并将其表示为冒号分隔的十六进制值,例如11:aa:22:bb:33:cc)

但要唯一识别BLE地址,您需要知道它是公共地址还是私人地址。实质上,识别地址需要49位,而不是48位。

随机地址可以是静态随机地址,不可解析私有地址或可解析私有地址,这些类型在两个最重要的字节(分别为11,00和10)中由位模式分隔。

但我没有看到只要查看地址中的48位即可将公共地址和随机地址分开的任何地方。

那么这在Android API中如何运作?当他们不知道您指定的地址是公开的还是随机的时,他们如何知道要连接的设备?

有问题的API例如是getRemoteDevice函数。它说:

Valid Bluetooth hardware addresses must be upper case, in a format such as
"00:11:22:33:AA:BB". The helper checkBluetoothAddress(String) is available
to validate a Bluetooth address.

A BluetoothDevice will always be returned for a valid hardware address,
even if this adapter has never seen that device.

因此,您为该函数提供48位数据,并且无法告知该地址是公共地址还是私有地址。这意味着设备唯一标识。

5 个答案:

答案 0 :(得分:9)

由于没有其他人似乎有答案,我开始自行测试。

我尝试制作一个应用程序,从地址的字符串表示创建设备,并尝试使用48位地址设置我的设备,交替使用公共或私有位来查看Android堆栈的功能。

private final BluetoothGattCallback leGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Log.i("Fisken", "Gatt connected " + gatt.getDevice().getAddress() + " status " + status);
            if (status != BluetoothGatt.GATT_SUCCESS) {
                Log.w("Fisken", "Disconnect and close");
                gatt.disconnect();
                gatt.close();
            }
        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.i("Fisken", "Gatt disconnected " + gatt.getDevice().getAddress() + " status " + status);
            if (status != BluetoothGatt.GATT_SUCCESS) {
                Log.w("Fisken", "Disconnect and close");
                gatt.disconnect();
            }
            gatt.close();
        }
    }
};

BluetoothAdapter mBluetoothAdapter = ((BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
BluetoothDevice d = mBluetoothAdapter.getRemoteDevice("FF:55:44:33:22:11");
d.connectGatt(this, false, leGattCallback);

使用此代码,如果我使用随机地址启动我的BLE外设,一切都按预期工作。但是,如果我尝试使用与公共位设置相同的地址运行它,则logcat会说" Gatt connected",但这不是真的。我永远无法断开连接。

更新:我做了一些测试来解决这个问题。我得到的onConnectionStateChange事件只是连接尝试超时。状态设置为133(如果我得到STATE_CONNECTED)或257(如果我得到STATE_DISCONNECTED)并且我已经看到了两者。在任何一种情况下,我都应该(现在在示例代码中)取消连接尝试并关闭客户端。

我还发现,如果我先进行扫描,那么我最近才会看到我尝试连接的设备,而然后只进行连接在设备mac地址上,我可以毫无困难地连接到随机和公共地址。

所以这似乎是Android API中的错误/缺失功能。它不允许您在未先扫描的情况下连接到公共地址。但它适用于随机地址。

答案 1 :(得分:1)

可以猜测地址是公开的还是随机的,尽管它不会在每种情况下都有效。

如上所述,在随机地址的情况下,两个MSB都是00xx,01xx或11xx ......所以如果它是10xx,那么它是一个公共地址(来自OUI以8,9开头的公司) ,A或B)

此外,与现有数量相比,注册的OUI数量非常有限,因此通过搜索IEEE数据库中的潜在OUI,匹配结果可能意味着公共地址。

注册的OUI计数:~20500,因此2 ^ 24位中的0.12%和2 ^ 22位中的0.48%。

如果没有IEEE数据库,可以依赖OUI的第一个LSB​​始终为0,第二个LSB几乎总是0的事实(实际上,它应该始终为0,因为这些地址是普遍管理的)

此外,可以使用其他统计分析:例如,60%的OUI以00开头。另一方面,不可解析的私有地址,以00开头的概率为1.66%(具有均匀的随机性)发生器)。

答案 2 :(得分:0)

我认为您的原始版本需要49位才能区分公共地址和随机地址'是正确的。我在IEEE公共地址的编码中找不到任何限制MSB为' 10'如果是真的,那将解决问题。

所以唯一可以使用的是随机地址'外围设备的广告中的位设置或中心的连接启动包中的等效位设置。如果未设置这些位,则所述端点公开的地址是公共的。

我会补充: 来自核心规范Vol 6 Part B section 1.3设备地址: 调用MS =最重要

Static random address:          two MB bits of MS byte are 1 1 such that the MS byte is 11xxxxxx & with 0xC0
Non-resolvable private address: two MB bits of MS byte are 0 0 such that the MS byte is 00xxxxxx & with 0x00
Resolvable private address:     two MB bits of MS byte are 0 1 such that the MS byte is 01xxxxxx & with 0x40

如果没有地址类型标志,则无法区分公共地址与上述类型的地址之一。因此需要第49个'位(额外标志)。仅凭地址不行!

答案 3 :(得分:0)

广告地址的标题中是否设置了广告地址是公共地址还是私人地址。将应用层中的地址类型设置为public意味着BLE链路层将传输实际的“MAC”地址。将地址类型设置为static / private resolvable,表示BLE链路层将使用身份解析密钥(IRK)对地址进行加扰。

答案 4 :(得分:0)

您可以通过查看2个最高有效位来区分公共和私有地址。地址长度为48位,而不是49位。请参阅Core Bluetooth Specification v4.2,Vol 6,Part B,Section 1.3。