Android上的蓝牙低能耗的私人与公共地址

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

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

随机地址可以是静态随机的,不可parsing的私有的或可parsing的私有的,这些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位数据,并且没有办法告诉它地址是公有的还是私有的。 这意味着设备不是唯一标识的。

Solutions Collecting From Web of "Android上的蓝牙低能耗的私人与公共地址"

由于没有人似乎有答案提供我开始自己testing。

我试图创build一个应用程序,从一个地址的string表示forms创build一个设备,并试图设置我的设备与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说:“GAT连接”,但这是不正确的。 而且我永远不能断开。

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

我也发现,如果我先做一个扫描,以便我试图连接到的设备最近已经看到, 然后做一个完全基于设备的MAC地址连接,然后我能够连接到随机和公共地址没有任何问题。

所以这似乎是Android API中的一个缺陷/和缺less的function。 它不允许你连接到一个公共地址没有先扫描它。 但是它的确适用于随机地址。

有可能猜测地址是公开的还是随机的,尽pipe它在任何情况下都不起作用。

正如你上面所说,如果是随机地址,两个MSB都是00xx,01xx或11xx …所以如果是10xx,那么它是一个公共地址(从OUI以8,9开始的公司B)

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

注册的OUI计数:约为20500,在2 ^ 24位中为0.12%,在2 ^ 22位中为0.48%。

如果没有IEEE数据库,可以依靠OUI的第一个LSB​​始终为0,而​​第二个LSB几乎总是为0(实际上,这些地址是通用pipe理的,它应该始终为0)。

此外,还可以使用其他统计分析:例如,OUI的60%以00开始。另一方面,不可parsing的专用地址,以00开头(具有统一随机生成器)的概率仅为1.66%。

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

您可以通过查看2个最重要的位来区分公共和私人地址。 地址长度是48位,而不是49.参见Core Bluetooth Specification v4.2,第6卷,B部分,1.3节。

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

因此,唯一可以使用的是外设通告中的“随机地址”位或中央连接启动数据包中的相应位设置。 如果这些位未被设置,则所述端点公开的地址是公开的。

我将添加:从核心规范卷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的地址之一。 因此需要“第49”位(额外的标志)。 地址本身并没有做到这一点!