diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt index ad09b225ff..16da6382ea 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/OmnipodDashBleManagerImpl.kt @@ -137,6 +137,7 @@ class OmnipodDashBleManagerImpl @Inject constructor( private fun establishSession(msgSeq: Byte) { val conn = connection ?: throw FailedToConnectException("connection lost") val ltk: ByteArray = podState.ltk ?: throw FailedToConnectException("Missing LTK, activate the pod first") + val uniqueId = podState.uniqueId val podId = uniqueId?.let { Id.fromLong(uniqueId) } ?: myId.increment() // pod not activated diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt index db0682e568..79513c759e 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/io/BleIO.kt @@ -97,20 +97,18 @@ open class BleIO( * @return */ fun readyToRead(): BleSendResult { - val notificationSet = gatt.setCharacteristicNotification(characteristic, true) - if (!notificationSet) { - throw ConnectException("Could not enable notifications") - } + gatt.setCharacteristicNotification(characteristic, true) + .assertTrue("enable notifications") + val descriptors = characteristic.descriptors if (descriptors.size != 1) { throw ConnectException("Expecting one descriptor, found: ${descriptors.size}") } val descriptor = descriptors[0] descriptor.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE - val wrote = gatt.writeDescriptor(descriptor) - if (!wrote) { - throw ConnectException("Could not enable indications on descriptor") - } + gatt.writeDescriptor(descriptor) + .assertTrue("enable indications on descriptor") + aapsLogger.debug(LTag.PUMPBTCOMM, "Enabling indications for $type") val confirmation = bleCommCallbacks.confirmWrite( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE, @@ -130,3 +128,9 @@ open class BleIO( const val DEFAULT_IO_TIMEOUT_MS = 1000.toLong() } } + +private fun Boolean.assertTrue(operation: String) { + if (!this) { + throw ConnectException("Could not $operation") + } +} \ No newline at end of file diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt index edee7fcdd3..730680cbfc 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/EapMessage.kt @@ -62,13 +62,11 @@ data class EapMessage( private const val AKA_PACKET_TYPE = 0x17.toByte() fun parse(aapsLogger: AAPSLogger, payload: ByteArray): EapMessage { - if (payload.size < 4) { - throw MessageIOException("Invalid eap payload: ${payload.toHex()}") - } + payload.assertSizeAtLeast(4) + val totalSize = (payload[2].toInt() shl 8) or payload[3].toInt() - if (totalSize > payload.size) { - throw MessageIOException("Invalid eap payload. Too short: ${payload.toHex()}") - } + payload.assertSizeAtLeast(totalSize) + if (payload.size == 4) { // SUCCESS/FAILURE return EapMessage( code = EapCode.byValue(payload[0]), @@ -90,3 +88,9 @@ data class EapMessage( } } } + +private fun ByteArray.assertSizeAtLeast(size: Int) { + if (this.size < size) { + throw MessageIOException("Payload too short: ${this.toHex()}") + } +} diff --git a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt index bf5b78c316..d24e8520ee 100644 --- a/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt +++ b/omnipod-dash/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/dash/driver/comm/session/SessionEstablisher.kt @@ -90,65 +90,35 @@ class SessionEstablisher( ) } - private fun processChallengeResponse(challengeResponse: MessagePacket): EapSqn? { - val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload) - if (eapMsg.identifier != identifier) { + private fun assertIdentifier(msg: EapMessage) { + if (msg.identifier != identifier) { aapsLogger.debug( LTag.PUMPBTCOMM, - "EAP-AKA: got incorrect identifier ${eapMsg.identifier} expected: $identifier" + "EAP-AKA: got incorrect identifier ${msg.identifier} expected: $identifier" ) - throw SessionEstablishmentException("Received incorrect EAP identifier: ${eapMsg.identifier}") + throw SessionEstablishmentException("Received incorrect EAP identifier: ${msg.identifier}") + } + } + + private fun processChallengeResponse(challengeResponse: MessagePacket): EapSqn? { + val eapMsg = EapMessage.parse(aapsLogger, challengeResponse.payload) + + assertIdentifier(eapMsg) + + val eapSqn = isResynchronization(eapMsg) + if (eapSqn != null) { + return eapSqn } - if (eapMsg.subType == EapMessage.SUBTYPE_SYNCRONIZATION_FAILURE && - eapMsg.attributes.size == 1 && - eapMsg.attributes[0] is EapAkaAttributeAuts - ) { - val auts = eapMsg.attributes[0] as EapAkaAttributeAuts - val autsMilenage = Milenage( - aapsLogger = aapsLogger, - k = ltk, - sqn = eapSqn, - randParam = milenage.rand, - auts = auts.payload - ) - - val newSqnMilenage = Milenage( - aapsLogger = aapsLogger, - k = ltk, - sqn = autsMilenage.synchronizationSqn, - randParam = milenage.rand, - auts = auts.payload, - amf = Milenage.RESYNC_AMF, - ) - - if (!newSqnMilenage.macS.contentEquals(newSqnMilenage.receivedMacS)) { - throw SessionEstablishmentException( - "MacS mismatch. " + - "Expected: ${newSqnMilenage.macS.toHex()}. " + - "Received: ${newSqnMilenage.receivedMacS.toHex()}" - ) - } - return EapSqn(autsMilenage.synchronizationSqn) - } - - if (eapMsg.attributes.size != 2) { - aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got message: $eapMsg") - if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) { - throw SessionEstablishmentException( - "Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${ - eapMsg.attributes[0].toByteArray().toHex() - }" - ) - } - throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}") - } + assertValidAkaMessage(eapMsg) for (attr in eapMsg.attributes) { when (attr) { is EapAkaAttributeRes -> if (!milenage.res.contentEquals(attr.payload)) { - throw SessionEstablishmentException("RES mismatch. Expected: ${milenage.res.toHex()} Actual: ${attr.payload.toHex()} ") + throw SessionEstablishmentException("RES mismatch." + + "Expected: ${milenage.res.toHex()}." + + "Actual: ${attr.payload.toHex()}.") } is EapAkaAttributeCustomIV -> nodeIV = attr.payload.copyOfRange(0, IV_SIZE) @@ -159,6 +129,55 @@ class SessionEstablisher( return null } + private fun assertValidAkaMessage(eapMsg: EapMessage) { + if (eapMsg.attributes.size != 2) { + aapsLogger.debug(LTag.PUMPBTCOMM, "EAP-AKA: got incorrect: $eapMsg") + if (eapMsg.attributes.size == 1 && eapMsg.attributes[0] is EapAkaAttributeClientErrorCode) { + throw SessionEstablishmentException( + "Received CLIENT_ERROR_CODE for EAP-AKA challenge: ${ + eapMsg.attributes[0].toByteArray().toHex() + }" + ) + } + throw SessionEstablishmentException("Expecting two attributes, got: ${eapMsg.attributes.size}") + } + } + + private fun isResynchronization(eapMsg: EapMessage): EapSqn? { + if (eapMsg.subType != EapMessage.SUBTYPE_SYNCRONIZATION_FAILURE || + eapMsg.attributes.size != 1 || + eapMsg.attributes[0] !is EapAkaAttributeAuts) + return null + + val auts = eapMsg.attributes[0] as EapAkaAttributeAuts + val autsMilenage = Milenage( + aapsLogger = aapsLogger, + k = ltk, + sqn = eapSqn, + randParam = milenage.rand, + auts = auts.payload + ) + + val newSqnMilenage = Milenage( + aapsLogger = aapsLogger, + k = ltk, + sqn = autsMilenage.synchronizationSqn, + randParam = milenage.rand, + auts = auts.payload, + amf = Milenage.RESYNC_AMF, + ) + + if (!newSqnMilenage.macS.contentEquals(newSqnMilenage.receivedMacS)) { + throw SessionEstablishmentException( + "MacS mismatch. " + + "Expected: ${newSqnMilenage.macS.toHex()}. " + + "Received: ${newSqnMilenage.receivedMacS.toHex()}" + ) + } + return EapSqn(autsMilenage.synchronizationSqn) + + } + private fun eapSuccess(): MessagePacket { val eapMsg = EapMessage( code = EapCode.SUCCESS,