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

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

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

随机地址可以是静态随机地址,不可解析私有地址或可解析私有地址,这些types在两个最重要的字节(分别为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位数据,没有办法告诉它地址是公共的还是私有的。 这意味着设备未被唯一标识。

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

我尝试创建一个应用程序,从地址的字符串表示创建一个设备,并尝试使用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中的错误/和缺失function。 它不允许您在未先扫描的情况下连接到公共地址。 然而它确实适用于随机地址。

可以猜测地址是公共的还是随机的,尽管它并不适用于所有情况。

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

此外,与现有的OUI相比,注册的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%(具有均匀随机生成器)。

广告地址是公共地址还是私人地址被设置在广告消息的标题中。 将应用层中的地址types设置为public意味着BLE链路层将发送实际的“MAC”地址。 将地址types设置为static / private resolvable,表示BLE链路层将使用标识解析密钥(IRK)对地址进行加扰。

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

我认为你原来’需要49位来区分公共地址和随机地址’是正确的。 我无法在IEEE公共地址的编码中find任何限制MSB为“10”的内容,如果为真,则可以解决问题。

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

我将补充:来自核心规范第6卷第B部分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 

如果没有地址types标志,则无法将公共地址与上述types的地址之一区分开。 因此需要’49th’位(额外标志)。 仅凭地址不行!