diff options
3 files changed, 97 insertions, 9 deletions
diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseHelper.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseHelper.java index 5f48a07657..90a52bf2aa 100644 --- a/android/app/src/com/android/bluetooth/gatt/AdvertiseHelper.java +++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseHelper.java @@ -71,6 +71,7 @@ class AdvertiseHelper { type = COMPLETE_LOCAL_NAME; } + check_length(type, nameLength + 1); ret.write(nameLength + 1); ret.write(type); ret.write(nameBytes, 0, nameLength); @@ -92,6 +93,7 @@ class AdvertiseHelper { System.arraycopy(manufacturerData, 0, concated, 2, manufacturerData.length); } + check_length(MANUFACTURER_SPECIFIC_DATA, concated.length + 1); ret.write(concated.length + 1); ret.write(MANUFACTURER_SPECIFIC_DATA); ret.write(concated, 0, concated.length); @@ -121,18 +123,21 @@ class AdvertiseHelper { } if (serviceUuids16.size() != 0) { + check_length(COMPLETE_LIST_16_BIT_SERVICE_UUIDS, serviceUuids16.size() + 1); ret.write(serviceUuids16.size() + 1); ret.write(COMPLETE_LIST_16_BIT_SERVICE_UUIDS); ret.write(serviceUuids16.toByteArray(), 0, serviceUuids16.size()); } if (serviceUuids32.size() != 0) { + check_length(COMPLETE_LIST_32_BIT_SERVICE_UUIDS, serviceUuids32.size() + 1); ret.write(serviceUuids32.size() + 1); ret.write(COMPLETE_LIST_32_BIT_SERVICE_UUIDS); ret.write(serviceUuids32.toByteArray(), 0, serviceUuids32.size()); } if (serviceUuids128.size() != 0) { + check_length(COMPLETE_LIST_128_BIT_SERVICE_UUIDS, serviceUuids32.size() + 1); ret.write(serviceUuids128.size() + 1); ret.write(COMPLETE_LIST_128_BIT_SERVICE_UUIDS); ret.write(serviceUuids128.toByteArray(), 0, serviceUuids128.size()); @@ -156,14 +161,17 @@ class AdvertiseHelper { } if (uuid.length == BluetoothUuid.UUID_BYTES_16_BIT) { + check_length(SERVICE_DATA_16_BIT_UUID, concated.length + 1); ret.write(concated.length + 1); ret.write(SERVICE_DATA_16_BIT_UUID); ret.write(concated, 0, concated.length); } else if (uuid.length == BluetoothUuid.UUID_BYTES_32_BIT) { + check_length(SERVICE_DATA_32_BIT_UUID, concated.length + 1); ret.write(concated.length + 1); ret.write(SERVICE_DATA_32_BIT_UUID); ret.write(concated, 0, concated.length); } else /*if (uuid.length == BluetoothUuid.UUID_BYTES_128_BIT)*/ { + check_length(SERVICE_DATA_128_BIT_UUID, concated.length + 1); ret.write(concated.length + 1); ret.write(SERVICE_DATA_128_BIT_UUID); ret.write(concated, 0, concated.length); @@ -190,18 +198,21 @@ class AdvertiseHelper { } if (serviceUuids16.size() != 0) { + check_length(LIST_16_BIT_SERVICE_SOLICITATION_UUIDS, serviceUuids16.size() + 1); ret.write(serviceUuids16.size() + 1); ret.write(LIST_16_BIT_SERVICE_SOLICITATION_UUIDS); ret.write(serviceUuids16.toByteArray(), 0, serviceUuids16.size()); } if (serviceUuids32.size() != 0) { + check_length(LIST_32_BIT_SERVICE_SOLICITATION_UUIDS, serviceUuids32.size() + 1); ret.write(serviceUuids32.size() + 1); ret.write(LIST_32_BIT_SERVICE_SOLICITATION_UUIDS); ret.write(serviceUuids32.toByteArray(), 0, serviceUuids32.size()); } if (serviceUuids128.size() != 0) { + check_length(LIST_128_BIT_SERVICE_SOLICITATION_UUIDS, serviceUuids128.size() + 1); ret.write(serviceUuids128.size() + 1); ret.write(LIST_128_BIT_SERVICE_SOLICITATION_UUIDS); ret.write(serviceUuids128.toByteArray(), 0, serviceUuids128.size()); @@ -209,6 +220,7 @@ class AdvertiseHelper { } for (TransportDiscoveryData transportDiscoveryData : data.getTransportDiscoveryData()) { + check_length(TRANSPORT_DISCOVERY_DATA, transportDiscoveryData.totalBytes() + 1); ret.write(transportDiscoveryData.totalBytes() + 1); ret.write(TRANSPORT_DISCOVERY_DATA); ret.write(transportDiscoveryData.toByteArray(), @@ -216,4 +228,12 @@ class AdvertiseHelper { } return ret.toByteArray(); } + + static void check_length(int type, int length) { + if (length > 255) { + Log.w(TAG, "Length of data with type " + Integer.toString(type, 16) + + " is grater than 255"); + throw new IllegalArgumentException("Length of data is grater than 255"); + } + } } diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java index b76d8619d8..e02fd6f73f 100644 --- a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java +++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java @@ -16,6 +16,7 @@ package com.android.bluetooth.gatt; +import android.bluetooth.le.AdvertiseCallback; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertisingSetParameters; import android.bluetooth.le.IAdvertisingSetCallback; @@ -195,9 +196,12 @@ class AdvertiseManager { } String deviceName = AdapterService.getAdapterService().getName(); - byte[] advDataBytes = AdvertiseHelper.advertiseDataToBytes(advertiseData, deviceName); - byte[] scanResponseBytes = AdvertiseHelper.advertiseDataToBytes(scanResponse, deviceName); - byte[] periodicDataBytes = AdvertiseHelper.advertiseDataToBytes(periodicData, deviceName); + try { + byte[] advDataBytes = AdvertiseHelper.advertiseDataToBytes(advertiseData, deviceName); + byte[] scanResponseBytes = + AdvertiseHelper.advertiseDataToBytes(scanResponse, deviceName); + byte[] periodicDataBytes = + AdvertiseHelper.advertiseDataToBytes(periodicData, deviceName); int cbId = --sTempRegistrationId; mAdvertisers.put(binder, new AdvertiserInfo(cbId, deathRecipient, callback)); @@ -207,6 +211,16 @@ class AdvertiseManager { } startAdvertisingSetNative(parameters, advDataBytes, scanResponseBytes, periodicParameters, periodicDataBytes, duration, maxExtAdvEvents, cbId); + + } catch (IllegalArgumentException e) { + try { + binder.unlinkToDeath(deathRecipient, 0); + callback.onAdvertisingSetStarted(0x00, 0x00, + AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); + } catch (RemoteException exception) { + Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); + } + } } void onOwnAddressRead(int advertiserId, int addressType, String address) @@ -280,8 +294,17 @@ class AdvertiseManager { return; } String deviceName = AdapterService.getAdapterService().getName(); - setAdvertisingDataNative(advertiserId, - AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + try { + setAdvertisingDataNative(advertiserId, + AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + } catch (IllegalArgumentException e) { + try { + onAdvertisingDataSet(advertiserId, + AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); + } catch (Exception exception) { + Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); + } + } } void setScanResponseData(int advertiserId, AdvertiseData data) { @@ -291,8 +314,17 @@ class AdvertiseManager { return; } String deviceName = AdapterService.getAdapterService().getName(); - setScanResponseDataNative(advertiserId, - AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + try { + setScanResponseDataNative(advertiserId, + AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + } catch (IllegalArgumentException e) { + try { + onScanResponseDataSet(advertiserId, + AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); + } catch (Exception exception) { + Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); + } + } } void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) { @@ -321,8 +353,17 @@ class AdvertiseManager { return; } String deviceName = AdapterService.getAdapterService().getName(); - setPeriodicAdvertisingDataNative(advertiserId, - AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + try { + setPeriodicAdvertisingDataNative(advertiserId, + AdvertiseHelper.advertiseDataToBytes(data, deviceName)); + } catch (IllegalArgumentException e) { + try { + onPeriodicAdvertisingDataSet(advertiserId, + AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); + } catch (Exception exception) { + Log.e(TAG, "Failed to callback:" + Log.getStackTraceString(exception)); + } + } } void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) { diff --git a/system/gd/hci/le_advertising_manager.cc b/system/gd/hci/le_advertising_manager.cc index c43eee9ff6..a64666b86b 100644 --- a/system/gd/hci/le_advertising_manager.cc +++ b/system/gd/hci/le_advertising_manager.cc @@ -351,6 +351,14 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb return; } + // check extended advertising data is valid before start advertising + if (!check_extended_advertising_data(config.advertisement) || + !check_extended_advertising_data(config.scan_response)) { + advertising_callbacks_->OnAdvertisingSetStarted( + reg_id, id, le_physical_channel_tx_power_, AdvertisingCallback::AdvertisingStatus::DATA_TOO_LARGE); + return; + } + if (!address_manager_registered) { le_address_manager_->Register(this); address_manager_registered = true; @@ -629,6 +637,25 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb } } + bool check_extended_advertising_data(std::vector<GapData> data) { + uint16_t data_len = 0; + // check data size + for (size_t i = 0; i < data.size(); i++) { + if (data[i].size() > kLeMaximumFragmentLength) { + LOG_WARN("AD data len shall not greater than %d", kLeMaximumFragmentLength); + return false; + } + data_len += data[i].size(); + } + + if (data_len > le_maximum_advertising_data_length_) { + LOG_WARN( + "advertising data len exceeds le_maximum_advertising_data_length_ %d", le_maximum_advertising_data_length_); + return false; + } + return true; + }; + void set_data(AdvertiserId advertiser_id, bool set_scan_rsp, std::vector<GapData> data) { if (!set_scan_rsp && advertising_sets_[advertiser_id].connectable) { GapData gap_data; |