diff --git a/android/app/src/main/java/nl/eddydevink/sylda/BleRelayManager.kt b/android/app/src/main/java/nl/eddydevink/sylda/BleRelayManager.kt index c0259bb..d1a6826 100644 --- a/android/app/src/main/java/nl/eddydevink/sylda/BleRelayManager.kt +++ b/android/app/src/main/java/nl/eddydevink/sylda/BleRelayManager.kt @@ -81,6 +81,7 @@ class BleRelayManager( private var ecdhDone = false @Volatile private var ecdhDeferred: CompletableDeferred? = null private var ecdhNotifyBuf: ByteArray = ByteArray(0) + private var ecdhCccdPending = false private class CompletableDeferred { private var result: T? = null @@ -314,6 +315,7 @@ class BleRelayManager( ecdhCharacteristic = null aesKey = null ecdhDone = false + ecdhCccdPending = false seq = 1 triedAddresses.clear() handler.postDelayed(scanRunnable, RECONNECT_DELAY_MS) @@ -413,6 +415,19 @@ class BleRelayManager( Log.d(TAG, "ECDH notify received (${value.size} bytes)") } } + + @SuppressLint("MissingPermission") + override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { + if (ecdhCccdPending && descriptor.characteristic.uuid == ECDH_UUID) { + ecdhCccdPending = false + if (status == BluetoothGatt.GATT_SUCCESS) { + sendEcdhHandshake(gatt) + } else { + Log.w(TAG, "ECDH: CCCD write failed (status=$status)") + gatt.disconnect() + } + } + } } @SuppressLint("MissingPermission") @@ -425,18 +440,30 @@ class BleRelayManager( return } + val cccd = char.getDescriptor(OTA_CCCD_UUID) + if (cccd == null) { + Log.w(TAG, "ECDH: no CCCD descriptor") + gatt.disconnect() + return + } + if (!gatt.setCharacteristicNotification(char, true)) { Log.w(TAG, "ECDH: setCharacteristicNotification failed") gatt.disconnect() return } - val cccd = char.getDescriptor(OTA_CCCD_UUID) - if (cccd != null) { - cccd.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE - gatt.writeDescriptor(cccd) + ecdhCccdPending = true + cccd.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE + if (!gatt.writeDescriptor(cccd)) { + ecdhCccdPending = false + Log.w(TAG, "ECDH: writeDescriptor for CCCD returned false") + gatt.disconnect() } + } + @SuppressLint("MissingPermission") + private fun sendEcdhHandshake(gatt: BluetoothGatt) { val myPsk = psk ?: run { Log.w(TAG, "ECDH: no PSK") gatt.disconnect() @@ -462,9 +489,9 @@ class BleRelayManager( System.arraycopy(sig, 0, handshake, ECDH_PUBKEY_LEN, 32) ecdhDeferred = CompletableDeferred() - char.value = handshake - char.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE - if (!gatt.writeCharacteristic(char)) { + ecdhCharacteristic!!.value = handshake + ecdhCharacteristic!!.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE + if (!gatt.writeCharacteristic(ecdhCharacteristic!!)) { Log.w(TAG, "ECDH: write pubkey failed") gatt.disconnect() return diff --git a/src/main.cpp b/src/main.cpp index cb79cf7..17f7848 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -617,6 +617,15 @@ void loop() { preferences.end(); uuidProvisioned = true; pUuidChar->setValue(deviceUuid, ESP_UUID_LEN); + + uint8_t mfgPayload[6]; + mfgPayload[0] = 0xFF; + mfgPayload[1] = 0xFF; + memcpy(mfgPayload + 2, deviceUuid, 4); + NimBLEAdvertisementData scanResp; + scanResp.setCompleteServices(NimBLEUUID(SERVICE_UUID)); + scanResp.setManufacturerData(std::string((char*)mfgPayload, 6)); + NimBLEDevice::getAdvertising()->setScanResponseData(scanResp); Serial.println("OK"); Serial.println("UUID stored in NVS"); } else {