@@ -65,7 +65,7 @@ def __init__(self, database: DeviceDatabase):
6565 self ._ddb = database
6666 self ._queued : dict [int , Callable | None ] = {}
6767
68- def generate (self , command : int , args : bytes , auth : Auth , cb : Callable | None ):
68+ def generate (self , command : int , args : bytes , auth : Auth , cb : Callable | None ) -> PacketOutputRouted :
6969 """Generate RPC packet from arguments"""
7070 cmd_bytes = bytes (rpc .RequestHeader (self ._cnt , command )) + args
7171 cmd_pkt = PacketOutputRouted (
@@ -79,6 +79,23 @@ def generate(self, command: int, args: bytes, auth: Auth, cb: Callable | None):
7979 self ._cnt += 1
8080 return cmd_pkt
8181
82+ def generate_remote_bt (
83+ self , remote : int , command : int , args : bytes , auth : Auth , cb : Callable | None
84+ ) -> PacketOutputRouted :
85+ """Generate RPC packet for Bluetooth remote from arguments"""
86+ cmd_bytes = bytes (rpc .RequestHeader (self ._cnt , command )) + args
87+
88+ assert self ._ddb .gateway is not None
89+ serial = HopOutput (self ._ddb .gateway , interface .ID .SERIAL , Auth .DEVICE )
90+ bt = HopOutput (remote , interface .ID .BT_CENTRAL , auth )
91+ self ._queued [self ._cnt ] = cb
92+ self ._cnt += 1
93+ return PacketOutputRouted (
94+ [serial , bt ],
95+ InfuseType .RPC_CMD ,
96+ cmd_bytes ,
97+ )
98+
8299 def handle (self , pkt : PacketReceived ):
83100 """Handle received packets"""
84101 # Only care about RPC responses
@@ -149,7 +166,7 @@ def public_keys_done(pkt: PacketReceived, rc: int, response: bytes):
149166 infuse_id = pkt .route [0 ].infuse_id
150167 self .ddb .observe_secondary_remote_public_key (infuse_id , bytes (key .key ))
151168
152- def run_cmd_pkt (cmd : PacketOutputRouted ):
169+ def run_cmd_pkt (cmd_pkt : PacketOutputRouted ):
153170 encrypted = cmd_pkt .to_serial (self .ddb )
154171 # Write to serial port
155172 Console .log_tx (cmd_pkt .ptype , len (encrypted ))
@@ -327,6 +344,21 @@ def _handle_epacket_send(self, req: GatewayRequestEpacketSend):
327344 Console .log_tx (routed .ptype , len (encrypted ))
328345 self ._common .port .write (encrypted )
329346
347+ def _connected_notification (self , infuse_id : int ):
348+ rsp = ClientNotificationConnectionCreated (infuse_id , 244 - ctypes .sizeof (CtypeBtGattFrame ) - 16 )
349+ self ._common .notification_broadcast (rsp )
350+
351+ def _pub_keys_cb (self , pkt : PacketReceived , rc : int , response : bytes ):
352+ infuse_id = pkt .route [0 ].infuse_id
353+ if rc == 0 :
354+ decoded = defs .security_public_keys .response .vla_from_buffer_copy (response )
355+ for key in decoded .public_keys :
356+ if key .id == defs .rpc_enum_key_id .SECONDARY_REMOTE_PUBLIC_KEY :
357+ self ._common .ddb .observe_secondary_remote_public_key (infuse_id , bytes (key .key ))
358+
359+ # Notify connection success
360+ self ._connected_notification (infuse_id )
361+
330362 def _bt_connect_cb (self , pkt : PacketReceived , rc : int , response : bytes ):
331363 resp = defs .bt_connect_infuse .response .from_buffer_copy (pkt .payload [ctypes .sizeof (rpc .ResponseHeader ) :])
332364 if_addr = interface .Address .BluetoothLeAddr .from_rpc_struct (resp .peer )
@@ -335,16 +367,28 @@ def _bt_connect_cb(self, pkt: PacketReceived, rc: int, response: bytes):
335367 assert infuse_id is not None , "ID was required to initiate connection?"
336368 assert self ._common .server is not None
337369
338- rsp : ClientNotification
339370 if rc < 0 :
340371 rsp = ClientNotificationConnectionFailed (infuse_id )
372+ self ._common .notification_broadcast (rsp )
373+ return
374+
375+ if infuse_id in self ._connected :
376+ self ._connected [infuse_id ] += 1
341377 else :
342- if infuse_id in self ._connected :
343- self ._connected [infuse_id ] += 1
344- else :
345- self ._connected [infuse_id ] = 1
346- rsp = ClientNotificationConnectionCreated (infuse_id , 244 - ctypes .sizeof (CtypeBtGattFrame ) - 16 )
347- self ._common .notification_broadcast (rsp )
378+ self ._connected [infuse_id ] = 1
379+
380+ if self ._common .ddb .has_local_root :
381+ # Query public keys before running callback
382+ cmd = self ._common .rpc .generate_remote_bt (
383+ infuse_id , defs .security_public_keys .COMMAND_ID , b"\x00 " , Auth .NETWORK , self ._pub_keys_cb
384+ )
385+ encrypted = cmd .to_serial (self ._common .ddb )
386+ Console .log_tx (cmd .ptype , len (encrypted ))
387+ self ._common .port .write (encrypted )
388+ return
389+
390+ # Notify connection success
391+ self ._connected_notification (infuse_id )
348392
349393 def _handle_conn_request (self , req : GatewayRequestConnectionRequest ):
350394 assert self ._common .server is not None
0 commit comments