Loading framework/tests/bumble/src/android/bluetooth/PandoraDevice.java +6 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import pandora.HostGrpc; import pandora.HostProto; import pandora.HostProto.AdvertiseRequest; import pandora.HostProto.OwnAddressType; import pandora.OOBGrpc; import pandora.RFCOMMGrpc; import pandora.SecurityGrpc; import pandora.l2cap.L2CAPGrpc; Loading Loading @@ -198,6 +199,11 @@ public final class PandoraDevice extends ExternalResource { return SecurityGrpc.newStub(mChannel); } /** Get Pandora OOB blocking service */ public OOBGrpc.OOBBlockingStub oobBlocking() { return OOBGrpc.newBlockingStub(mChannel); } /** Get Pandora GATT service */ public GATTGrpc.GATTStub gatt() { return GATTGrpc.newStub(mChannel); Loading framework/tests/bumble/src/bumble_server.py +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ from bumble_experimental.gatt import GATTService from bumble_experimental.rfcomm import RFCOMMService from bumble_experimental.avrcp import AvrcpService from bumble_experimental.hid import HIDService from bumble_experimental.oob import OOBService from pandora_experimental.asha_grpc_aio import add_AshaServicer_to_server from pandora_experimental.dck_grpc_aio import add_DckServicer_to_server Loading @@ -33,6 +34,7 @@ from pandora_experimental.gatt_grpc_aio import add_GATTServicer_to_server from pandora_experimental.rfcomm_grpc_aio import add_RFCOMMServicer_to_server from pandora_experimental.avrcp_grpc_aio import add_AVRCPServicer_to_server from pandora_experimental.hid_grpc_aio import add_HIDServicer_to_server from pandora_experimental.oob_grpc_aio import add_OOBServicer_to_server from typing import Any, Dict Loading Loading @@ -85,6 +87,8 @@ def register_experimental_services() -> None: lambda bumble, _, server: add_RFCOMMServicer_to_server(RFCOMMService(bumble.device), server)) bumble_server.register_servicer_hook( lambda bumble, _, server: add_HIDServicer_to_server(HIDService(bumble.device), server)) bumble_server.register_servicer_hook( lambda bumble, _, server: add_OOBServicer_to_server(OOBService(bumble.device), server)) def retrieve_config(config: str) -> Dict[str, Any]: Loading pandora/interfaces/pandora_experimental/oob.proto 0 → 100644 +24 −0 Original line number Diff line number Diff line syntax = "proto3"; package pandora; option java_outer_classname = "OobProto"; service OOB { // Share OOB data rpc ShareOobData(OobDataRequest) returns (OobDataResponse); } // Local Device OOB data. message OobDataRequest { // OOB data Pairing Hash and Randomizer - 32 bytes. bytes oob = 1; } // Remote Device OOB data. message OobDataResponse { // OOB data Pairing Hash and Randomizer - 32 bytes. bytes oob = 1; } pandora/interfaces/python/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,10 @@ genrule { "pandora_experimental/mediaplayer_grpc_aio.py", "pandora_experimental/mediaplayer_pb2.py", "pandora_experimental/mediaplayer_pb2.pyi", "pandora_experimental/oob_grpc.py", "pandora_experimental/oob_grpc_aio.py", "pandora_experimental/oob_pb2.py", "pandora_experimental/oob_pb2.pyi", "pandora_experimental/opp_grpc.py", "pandora_experimental/opp_grpc_aio.py", "pandora_experimental/opp_pb2.py", Loading Loading @@ -113,6 +117,7 @@ filegroup { ":pandora_experimental-python-gen-src{pandora_experimental/le_audio_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/map_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/mediaplayer_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/oob_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/opp_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/os_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/pan_pb2.pyi}", Loading pandora/server/bumble_experimental/oob.py 0 → 100644 +53 −0 Original line number Diff line number Diff line from __future__ import annotations import grpc import grpc.aio import logging from pandora_experimental.oob_grpc_aio import OOBServicer from pandora_experimental.oob_pb2 import ( OobDataRequest, OobDataResponse, ) from bumble.smp import OobContext, OobSharedData from bumble.pairing import PairingConfig, PairingDelegate from bumble.device import Device from bumble.pandora import utils # This class implements the Hid Pandora interface. class OOBService(OOBServicer): def __init__(self, device: Device) -> None: super().__init__() self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {'service_name': 'oob', 'device': device}) self.device = device def configure_oob_pairing(self, peer_oob: OobSharedData) -> str: our_oob_context = OobContext() share_oob = our_oob_context.share().__str__() self.log.debug(f"Local oob data: {share_oob}") oob_contexts = PairingConfig.OobConfig(our_context=our_oob_context, peer_data=peer_oob, legacy_context=None) self.device.pairing_config_factory = lambda connection: PairingConfig( sc=True, mitm=True, bonding=True, oob=oob_contexts, ) return share_oob @utils.rpc async def ShareOobData(self, request: OobDataRequest, context: grpc.ServicerContext) -> OobDataResponse: if request.oob: data = str(bytes(request.oob).hex()) oob_c, oob_r = data[:len(data) // 2], data[len(data) // 2:] peer_oob = OobSharedData(c=bytearray.fromhex(oob_c), r=bytearray.fromhex(oob_r)) self.log.debug(f'peer oob data {peer_oob}') else: peer_oob = None share_oob = self.configure_oob_pairing(peer_oob) # Extract data from string `OOB(C=XXXXXXXXXXXXXXXX, R=YYYYYYYYYYYYYYYY)` extracted_oob = share_oob.strip("OOB()C=").replace(", R=", "") return OobDataResponse(oob=bytes(bytearray.fromhex(extracted_oob))) Loading
framework/tests/bumble/src/android/bluetooth/PandoraDevice.java +6 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import pandora.HostGrpc; import pandora.HostProto; import pandora.HostProto.AdvertiseRequest; import pandora.HostProto.OwnAddressType; import pandora.OOBGrpc; import pandora.RFCOMMGrpc; import pandora.SecurityGrpc; import pandora.l2cap.L2CAPGrpc; Loading Loading @@ -198,6 +199,11 @@ public final class PandoraDevice extends ExternalResource { return SecurityGrpc.newStub(mChannel); } /** Get Pandora OOB blocking service */ public OOBGrpc.OOBBlockingStub oobBlocking() { return OOBGrpc.newBlockingStub(mChannel); } /** Get Pandora GATT service */ public GATTGrpc.GATTStub gatt() { return GATTGrpc.newStub(mChannel); Loading
framework/tests/bumble/src/bumble_server.py +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ from bumble_experimental.gatt import GATTService from bumble_experimental.rfcomm import RFCOMMService from bumble_experimental.avrcp import AvrcpService from bumble_experimental.hid import HIDService from bumble_experimental.oob import OOBService from pandora_experimental.asha_grpc_aio import add_AshaServicer_to_server from pandora_experimental.dck_grpc_aio import add_DckServicer_to_server Loading @@ -33,6 +34,7 @@ from pandora_experimental.gatt_grpc_aio import add_GATTServicer_to_server from pandora_experimental.rfcomm_grpc_aio import add_RFCOMMServicer_to_server from pandora_experimental.avrcp_grpc_aio import add_AVRCPServicer_to_server from pandora_experimental.hid_grpc_aio import add_HIDServicer_to_server from pandora_experimental.oob_grpc_aio import add_OOBServicer_to_server from typing import Any, Dict Loading Loading @@ -85,6 +87,8 @@ def register_experimental_services() -> None: lambda bumble, _, server: add_RFCOMMServicer_to_server(RFCOMMService(bumble.device), server)) bumble_server.register_servicer_hook( lambda bumble, _, server: add_HIDServicer_to_server(HIDService(bumble.device), server)) bumble_server.register_servicer_hook( lambda bumble, _, server: add_OOBServicer_to_server(OOBService(bumble.device), server)) def retrieve_config(config: str) -> Dict[str, Any]: Loading
pandora/interfaces/pandora_experimental/oob.proto 0 → 100644 +24 −0 Original line number Diff line number Diff line syntax = "proto3"; package pandora; option java_outer_classname = "OobProto"; service OOB { // Share OOB data rpc ShareOobData(OobDataRequest) returns (OobDataResponse); } // Local Device OOB data. message OobDataRequest { // OOB data Pairing Hash and Randomizer - 32 bytes. bytes oob = 1; } // Remote Device OOB data. message OobDataResponse { // OOB data Pairing Hash and Randomizer - 32 bytes. bytes oob = 1; }
pandora/interfaces/python/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -66,6 +66,10 @@ genrule { "pandora_experimental/mediaplayer_grpc_aio.py", "pandora_experimental/mediaplayer_pb2.py", "pandora_experimental/mediaplayer_pb2.pyi", "pandora_experimental/oob_grpc.py", "pandora_experimental/oob_grpc_aio.py", "pandora_experimental/oob_pb2.py", "pandora_experimental/oob_pb2.pyi", "pandora_experimental/opp_grpc.py", "pandora_experimental/opp_grpc_aio.py", "pandora_experimental/opp_pb2.py", Loading Loading @@ -113,6 +117,7 @@ filegroup { ":pandora_experimental-python-gen-src{pandora_experimental/le_audio_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/map_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/mediaplayer_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/oob_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/opp_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/os_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/pan_pb2.pyi}", Loading
pandora/server/bumble_experimental/oob.py 0 → 100644 +53 −0 Original line number Diff line number Diff line from __future__ import annotations import grpc import grpc.aio import logging from pandora_experimental.oob_grpc_aio import OOBServicer from pandora_experimental.oob_pb2 import ( OobDataRequest, OobDataResponse, ) from bumble.smp import OobContext, OobSharedData from bumble.pairing import PairingConfig, PairingDelegate from bumble.device import Device from bumble.pandora import utils # This class implements the Hid Pandora interface. class OOBService(OOBServicer): def __init__(self, device: Device) -> None: super().__init__() self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {'service_name': 'oob', 'device': device}) self.device = device def configure_oob_pairing(self, peer_oob: OobSharedData) -> str: our_oob_context = OobContext() share_oob = our_oob_context.share().__str__() self.log.debug(f"Local oob data: {share_oob}") oob_contexts = PairingConfig.OobConfig(our_context=our_oob_context, peer_data=peer_oob, legacy_context=None) self.device.pairing_config_factory = lambda connection: PairingConfig( sc=True, mitm=True, bonding=True, oob=oob_contexts, ) return share_oob @utils.rpc async def ShareOobData(self, request: OobDataRequest, context: grpc.ServicerContext) -> OobDataResponse: if request.oob: data = str(bytes(request.oob).hex()) oob_c, oob_r = data[:len(data) // 2], data[len(data) // 2:] peer_oob = OobSharedData(c=bytearray.fromhex(oob_c), r=bytearray.fromhex(oob_r)) self.log.debug(f'peer oob data {peer_oob}') else: peer_oob = None share_oob = self.configure_oob_pairing(peer_oob) # Extract data from string `OOB(C=XXXXXXXXXXXXXXXX, R=YYYYYYYYYYYYYYYY)` extracted_oob = share_oob.strip("OOB()C=").replace(", R=", "") return OobDataResponse(oob=bytes(bytearray.fromhex(extracted_oob)))