Loading framework/tests/bumble/src/bumble_server.py +12 −10 Original line number Diff line number Diff line Loading @@ -14,29 +14,29 @@ import argparse import asyncio import logging import json import logging from typing import Any, Dict from bumble import pandora as bumble_server from bumble.pandora import PandoraDevice, Config, serve from bumble.pandora import Config, PandoraDevice, serve from bumble_experimental.asha import AshaService from bumble_experimental.avrcp import AvrcpService from bumble_experimental.bumble_config import BumbleConfigService from bumble_experimental.dck import DckService 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 bumble_experimental.rfcomm import RFCOMMService from pandora_experimental.asha_grpc_aio import add_AshaServicer_to_server from pandora_experimental.avrcp_grpc_aio import add_AVRCPServicer_to_server from pandora_experimental.bumble_config_grpc_aio import \ add_BumbleConfigServicer_to_server from pandora_experimental.dck_grpc_aio import add_DckServicer_to_server 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 from pandora_experimental.rfcomm_grpc_aio import add_RFCOMMServicer_to_server BUMBLE_SERVER_GRPC_PORT = 7999 ROOTCANAL_PORT_CUTTLEFISH = 7300 Loading Loading @@ -89,6 +89,8 @@ def register_experimental_services() -> None: 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)) bumble_server.register_servicer_hook( lambda bumble, config, server: add_BumbleConfigServicer_to_server(BumbleConfigService(bumble.device, config), server)) def retrieve_config(config: str) -> Dict[str, Any]: Loading pandora/interfaces/pandora_experimental/bumble_config.proto 0 → 100644 +60 −0 Original line number Diff line number Diff line // Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; option java_outer_classname = "BumbleConfigProto"; package pandora; import "google/protobuf/empty.proto"; import "pandora/host.proto"; // This service provides runtime configuration for the Bumble Bluetooth stack. // It allows overriding the initial configuration provided by the JSON file and // the Security Service. This service should only be used by BumbleBluetoothTests. service BumbleConfig { // Override the initial Bumble configuration. This will erase any // previous configuration set via JSON file or Security Service. rpc Override(OverrideRequest) returns (google.protobuf.Empty); } message PairingConfig { bool sc = 1; bool mitm = 2; bool bonding = 3; OwnAddressType identity_address_type = 4; } enum IoCapability { DISPLAY_ONLY = 0x00; DISPLAY_YES_NO = 0x01; KEYBOARD_ONLY = 0x02; NO_OUTPUT_NO_INPUT = 0x03; KEYBOARD_DISPLAY = 0x04; } enum KeyDistribution { ENCRYPTION_KEY = 0x00; IDENTITY_KEY = 0x01; SIGNING_KEY = 0x02; LINK_KEY = 0x03; } message OverrideRequest { IoCapability io_capability = 1; PairingConfig pairing_config = 2; KeyDistribution initiator_key_distribution = 3; KeyDistribution responder_key_distribution = 4; } pandora/interfaces/python/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,10 @@ genrule { "pandora_experimental/avrcp_grpc_aio.py", "pandora_experimental/avrcp_pb2.py", "pandora_experimental/avrcp_pb2.pyi", "pandora_experimental/bumble_config_grpc.py", "pandora_experimental/bumble_config_grpc_aio.py", "pandora_experimental/bumble_config_pb2.py", "pandora_experimental/bumble_config_pb2.pyi", "pandora_experimental/dck_grpc.py", "pandora_experimental/dck_grpc_aio.py", "pandora_experimental/dck_pb2.py", Loading Loading @@ -109,6 +113,7 @@ filegroup { srcs: [ ":pandora_experimental-python-gen-src{pandora_experimental/asha_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/avrcp_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/bumble_config_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/dck_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/gatt_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/hap_pb2.pyi}", Loading pandora/server/bumble_experimental/bumble_config.py 0 → 100644 +73 −0 Original line number Diff line number Diff line # Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import grpc from bumble.device import Connection as BumbleConnection from bumble.device import Device from bumble.pairing import PairingConfig from bumble.pairing import PairingDelegate as BasePairingDelegate from bumble.pandora import Config, utils from bumble.pandora.security import PairingDelegate from google.protobuf.empty_pb2 import Empty from pandora.host_pb2 import PUBLIC from pandora_experimental.bumble_config_grpc_aio import BumbleConfigServicer from pandora_experimental.bumble_config_pb2 import (KeyDistribution, OverrideRequest) class BumbleConfigService(BumbleConfigServicer): device: Device def __init__(self, device: Device, server_config: Config) -> None: self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {"service_name": "BumbleConfig", "device": device}) self.device = device self.server_config = server_config @utils.rpc async def Override(self, request: OverrideRequest, context: grpc.ServicerContext) -> Empty: def parseProtoKeyDistribution(key: KeyDistribution,) -> BasePairingDelegate.KeyDistribution: return [ BasePairingDelegate.KeyDistribution.DISTRIBUTE_ENCRYPTION_KEY, BasePairingDelegate.KeyDistribution.DISTRIBUTE_IDENTITY_KEY, BasePairingDelegate.KeyDistribution.DISTRIBUTE_SIGNING_KEY, BasePairingDelegate.KeyDistribution.DISTRIBUTE_LINK_KEY, ][key] # type: ignore def pairing_config_factory(connection: BumbleConnection) -> PairingConfig: pairing_delegate = PairingDelegate( connection=connection, io_capability=BasePairingDelegate.IoCapability(request.io_capability), local_initiator_key_distribution=parseProtoKeyDistribution(request.initiator_key_distribution), local_responder_key_distribution=parseProtoKeyDistribution(request.responder_key_distribution), ) pc_req = request.pairing_config pairing_config = PairingConfig( sc=pc_req.sc, mitm=pc_req.mitm, bonding=pc_req.bonding, identity_address_type=PairingConfig.AddressType.PUBLIC if request.identity_address_type == PUBLIC else PairingConfig.AddressType.RANDOM, delegate=pairing_delegate, ) self.log.debug(f"Override: {pairing_config}") return pairing_config self.device.pairing_config_factory = pairing_config_factory return Empty() Loading
framework/tests/bumble/src/bumble_server.py +12 −10 Original line number Diff line number Diff line Loading @@ -14,29 +14,29 @@ import argparse import asyncio import logging import json import logging from typing import Any, Dict from bumble import pandora as bumble_server from bumble.pandora import PandoraDevice, Config, serve from bumble.pandora import Config, PandoraDevice, serve from bumble_experimental.asha import AshaService from bumble_experimental.avrcp import AvrcpService from bumble_experimental.bumble_config import BumbleConfigService from bumble_experimental.dck import DckService 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 bumble_experimental.rfcomm import RFCOMMService from pandora_experimental.asha_grpc_aio import add_AshaServicer_to_server from pandora_experimental.avrcp_grpc_aio import add_AVRCPServicer_to_server from pandora_experimental.bumble_config_grpc_aio import \ add_BumbleConfigServicer_to_server from pandora_experimental.dck_grpc_aio import add_DckServicer_to_server 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 from pandora_experimental.rfcomm_grpc_aio import add_RFCOMMServicer_to_server BUMBLE_SERVER_GRPC_PORT = 7999 ROOTCANAL_PORT_CUTTLEFISH = 7300 Loading Loading @@ -89,6 +89,8 @@ def register_experimental_services() -> None: 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)) bumble_server.register_servicer_hook( lambda bumble, config, server: add_BumbleConfigServicer_to_server(BumbleConfigService(bumble.device, config), server)) def retrieve_config(config: str) -> Dict[str, Any]: Loading
pandora/interfaces/pandora_experimental/bumble_config.proto 0 → 100644 +60 −0 Original line number Diff line number Diff line // Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; option java_outer_classname = "BumbleConfigProto"; package pandora; import "google/protobuf/empty.proto"; import "pandora/host.proto"; // This service provides runtime configuration for the Bumble Bluetooth stack. // It allows overriding the initial configuration provided by the JSON file and // the Security Service. This service should only be used by BumbleBluetoothTests. service BumbleConfig { // Override the initial Bumble configuration. This will erase any // previous configuration set via JSON file or Security Service. rpc Override(OverrideRequest) returns (google.protobuf.Empty); } message PairingConfig { bool sc = 1; bool mitm = 2; bool bonding = 3; OwnAddressType identity_address_type = 4; } enum IoCapability { DISPLAY_ONLY = 0x00; DISPLAY_YES_NO = 0x01; KEYBOARD_ONLY = 0x02; NO_OUTPUT_NO_INPUT = 0x03; KEYBOARD_DISPLAY = 0x04; } enum KeyDistribution { ENCRYPTION_KEY = 0x00; IDENTITY_KEY = 0x01; SIGNING_KEY = 0x02; LINK_KEY = 0x03; } message OverrideRequest { IoCapability io_capability = 1; PairingConfig pairing_config = 2; KeyDistribution initiator_key_distribution = 3; KeyDistribution responder_key_distribution = 4; }
pandora/interfaces/python/Android.bp +5 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,10 @@ genrule { "pandora_experimental/avrcp_grpc_aio.py", "pandora_experimental/avrcp_pb2.py", "pandora_experimental/avrcp_pb2.pyi", "pandora_experimental/bumble_config_grpc.py", "pandora_experimental/bumble_config_grpc_aio.py", "pandora_experimental/bumble_config_pb2.py", "pandora_experimental/bumble_config_pb2.pyi", "pandora_experimental/dck_grpc.py", "pandora_experimental/dck_grpc_aio.py", "pandora_experimental/dck_pb2.py", Loading Loading @@ -109,6 +113,7 @@ filegroup { srcs: [ ":pandora_experimental-python-gen-src{pandora_experimental/asha_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/avrcp_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/bumble_config_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/dck_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/gatt_pb2.pyi}", ":pandora_experimental-python-gen-src{pandora_experimental/hap_pb2.pyi}", Loading
pandora/server/bumble_experimental/bumble_config.py 0 → 100644 +73 −0 Original line number Diff line number Diff line # Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import grpc from bumble.device import Connection as BumbleConnection from bumble.device import Device from bumble.pairing import PairingConfig from bumble.pairing import PairingDelegate as BasePairingDelegate from bumble.pandora import Config, utils from bumble.pandora.security import PairingDelegate from google.protobuf.empty_pb2 import Empty from pandora.host_pb2 import PUBLIC from pandora_experimental.bumble_config_grpc_aio import BumbleConfigServicer from pandora_experimental.bumble_config_pb2 import (KeyDistribution, OverrideRequest) class BumbleConfigService(BumbleConfigServicer): device: Device def __init__(self, device: Device, server_config: Config) -> None: self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {"service_name": "BumbleConfig", "device": device}) self.device = device self.server_config = server_config @utils.rpc async def Override(self, request: OverrideRequest, context: grpc.ServicerContext) -> Empty: def parseProtoKeyDistribution(key: KeyDistribution,) -> BasePairingDelegate.KeyDistribution: return [ BasePairingDelegate.KeyDistribution.DISTRIBUTE_ENCRYPTION_KEY, BasePairingDelegate.KeyDistribution.DISTRIBUTE_IDENTITY_KEY, BasePairingDelegate.KeyDistribution.DISTRIBUTE_SIGNING_KEY, BasePairingDelegate.KeyDistribution.DISTRIBUTE_LINK_KEY, ][key] # type: ignore def pairing_config_factory(connection: BumbleConnection) -> PairingConfig: pairing_delegate = PairingDelegate( connection=connection, io_capability=BasePairingDelegate.IoCapability(request.io_capability), local_initiator_key_distribution=parseProtoKeyDistribution(request.initiator_key_distribution), local_responder_key_distribution=parseProtoKeyDistribution(request.responder_key_distribution), ) pc_req = request.pairing_config pairing_config = PairingConfig( sc=pc_req.sc, mitm=pc_req.mitm, bonding=pc_req.bonding, identity_address_type=PairingConfig.AddressType.PUBLIC if request.identity_address_type == PUBLIC else PairingConfig.AddressType.RANDOM, delegate=pairing_delegate, ) self.log.debug(f"Override: {pairing_config}") return pairing_config self.device.pairing_config_factory = pairing_config_factory return Empty()