xref: /aosp_15_r20/tools/netsim/rust/daemon/src/wireless/packet.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2023 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker 
15*cf78ab8cSAndroid Build Coastguard Worker use std::collections::HashMap;
16*cf78ab8cSAndroid Build Coastguard Worker use std::sync::mpsc::{channel, Sender};
17*cf78ab8cSAndroid Build Coastguard Worker use std::sync::{OnceLock, RwLock};
18*cf78ab8cSAndroid Build Coastguard Worker use std::thread;
19*cf78ab8cSAndroid Build Coastguard Worker 
20*cf78ab8cSAndroid Build Coastguard Worker use crate::captures;
21*cf78ab8cSAndroid Build Coastguard Worker use crate::devices::{chip, chip::ChipIdentifier};
22*cf78ab8cSAndroid Build Coastguard Worker 
23*cf78ab8cSAndroid Build Coastguard Worker use bytes::Bytes;
24*cf78ab8cSAndroid Build Coastguard Worker use log::{error, info, warn};
25*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::hci_packet::hcipacket::PacketType;
26*cf78ab8cSAndroid Build Coastguard Worker use protobuf::Enum;
27*cf78ab8cSAndroid Build Coastguard Worker 
28*cf78ab8cSAndroid Build Coastguard Worker /// The Packet module routes packets from a chip controller instance to
29*cf78ab8cSAndroid Build Coastguard Worker /// different transport managers. Currently transport managers include
30*cf78ab8cSAndroid Build Coastguard Worker ///
31*cf78ab8cSAndroid Build Coastguard Worker /// - GRPC is a PacketStreamer
32*cf78ab8cSAndroid Build Coastguard Worker /// - FD is a file descriptor to a pair of Unix Fifos used by "-s" startup
33*cf78ab8cSAndroid Build Coastguard Worker /// - SOCKET is a TCP stream
34*cf78ab8cSAndroid Build Coastguard Worker 
35*cf78ab8cSAndroid Build Coastguard Worker // When a connection arrives, the transport registers a responder
36*cf78ab8cSAndroid Build Coastguard Worker // implementing Response trait for the packet stream.
37*cf78ab8cSAndroid Build Coastguard Worker pub trait Response {
response(&mut self, packet: Bytes, packet_type: u8)38*cf78ab8cSAndroid Build Coastguard Worker     fn response(&mut self, packet: Bytes, packet_type: u8);
39*cf78ab8cSAndroid Build Coastguard Worker }
40*cf78ab8cSAndroid Build Coastguard Worker 
41*cf78ab8cSAndroid Build Coastguard Worker // When a responder is registered a responder thread is created to
42*cf78ab8cSAndroid Build Coastguard Worker // decouple the chip controller from the network. The thread reads
43*cf78ab8cSAndroid Build Coastguard Worker // ResponsePacket from a queue and sends to responder.
44*cf78ab8cSAndroid Build Coastguard Worker struct ResponsePacket {
45*cf78ab8cSAndroid Build Coastguard Worker     packet: Bytes,
46*cf78ab8cSAndroid Build Coastguard Worker     packet_type: u8,
47*cf78ab8cSAndroid Build Coastguard Worker }
48*cf78ab8cSAndroid Build Coastguard Worker 
49*cf78ab8cSAndroid Build Coastguard Worker // A hash map from chip_id to response channel.
50*cf78ab8cSAndroid Build Coastguard Worker 
51*cf78ab8cSAndroid Build Coastguard Worker struct PacketManager {
52*cf78ab8cSAndroid Build Coastguard Worker     transports: RwLock<HashMap<ChipIdentifier, Sender<ResponsePacket>>>,
53*cf78ab8cSAndroid Build Coastguard Worker }
54*cf78ab8cSAndroid Build Coastguard Worker 
55*cf78ab8cSAndroid Build Coastguard Worker static MANAGER: OnceLock<PacketManager> = OnceLock::new();
56*cf78ab8cSAndroid Build Coastguard Worker 
get_manager() -> &'static PacketManager57*cf78ab8cSAndroid Build Coastguard Worker fn get_manager() -> &'static PacketManager {
58*cf78ab8cSAndroid Build Coastguard Worker     MANAGER.get_or_init(PacketManager::new)
59*cf78ab8cSAndroid Build Coastguard Worker }
60*cf78ab8cSAndroid Build Coastguard Worker 
61*cf78ab8cSAndroid Build Coastguard Worker /// Register a chip controller instance to a transport manager.
register_transport(chip_id: ChipIdentifier, responder: Box<dyn Response + Send>)62*cf78ab8cSAndroid Build Coastguard Worker pub fn register_transport(chip_id: ChipIdentifier, responder: Box<dyn Response + Send>) {
63*cf78ab8cSAndroid Build Coastguard Worker     get_manager().register_transport(chip_id, responder);
64*cf78ab8cSAndroid Build Coastguard Worker }
65*cf78ab8cSAndroid Build Coastguard Worker 
66*cf78ab8cSAndroid Build Coastguard Worker /// Unregister a chip controller instance.
unregister_transport(chip_id: ChipIdentifier)67*cf78ab8cSAndroid Build Coastguard Worker pub fn unregister_transport(chip_id: ChipIdentifier) {
68*cf78ab8cSAndroid Build Coastguard Worker     get_manager().unregister_transport(chip_id);
69*cf78ab8cSAndroid Build Coastguard Worker }
70*cf78ab8cSAndroid Build Coastguard Worker 
71*cf78ab8cSAndroid Build Coastguard Worker impl PacketManager {
new() -> Self72*cf78ab8cSAndroid Build Coastguard Worker     fn new() -> Self {
73*cf78ab8cSAndroid Build Coastguard Worker         PacketManager { transports: RwLock::new(HashMap::new()) }
74*cf78ab8cSAndroid Build Coastguard Worker     }
75*cf78ab8cSAndroid Build Coastguard Worker     /// Register a transport stream for handle_response calls.
register_transport( &self, chip_id: ChipIdentifier, mut transport: Box<dyn Response + Send>, )76*cf78ab8cSAndroid Build Coastguard Worker     pub fn register_transport(
77*cf78ab8cSAndroid Build Coastguard Worker         &self,
78*cf78ab8cSAndroid Build Coastguard Worker         chip_id: ChipIdentifier,
79*cf78ab8cSAndroid Build Coastguard Worker         mut transport: Box<dyn Response + Send>,
80*cf78ab8cSAndroid Build Coastguard Worker     ) {
81*cf78ab8cSAndroid Build Coastguard Worker         let (tx, rx) = channel::<ResponsePacket>();
82*cf78ab8cSAndroid Build Coastguard Worker         if self.transports.write().unwrap().insert(chip_id, tx).is_some() {
83*cf78ab8cSAndroid Build Coastguard Worker             error!("register_transport: key already present for chip_id: {chip_id}");
84*cf78ab8cSAndroid Build Coastguard Worker         }
85*cf78ab8cSAndroid Build Coastguard Worker         let _ = thread::Builder::new().name(format!("transport_responder_{chip_id}")).spawn(
86*cf78ab8cSAndroid Build Coastguard Worker             move || {
87*cf78ab8cSAndroid Build Coastguard Worker                 info!("register_transport: started thread chip_id: {chip_id}");
88*cf78ab8cSAndroid Build Coastguard Worker                 while let Ok(ResponsePacket { packet, packet_type }) = rx.recv() {
89*cf78ab8cSAndroid Build Coastguard Worker                     transport.response(packet, packet_type);
90*cf78ab8cSAndroid Build Coastguard Worker                 }
91*cf78ab8cSAndroid Build Coastguard Worker                 info!("register_transport: finished thread chip_id: {chip_id}");
92*cf78ab8cSAndroid Build Coastguard Worker             },
93*cf78ab8cSAndroid Build Coastguard Worker         );
94*cf78ab8cSAndroid Build Coastguard Worker     }
95*cf78ab8cSAndroid Build Coastguard Worker 
96*cf78ab8cSAndroid Build Coastguard Worker     /// Unregister a chip controller instance.
unregister_transport(&self, chip_id: ChipIdentifier)97*cf78ab8cSAndroid Build Coastguard Worker     pub fn unregister_transport(&self, chip_id: ChipIdentifier) {
98*cf78ab8cSAndroid Build Coastguard Worker         // Shuts down the responder thread, because sender is dropped.
99*cf78ab8cSAndroid Build Coastguard Worker         self.transports.write().unwrap().remove(&chip_id);
100*cf78ab8cSAndroid Build Coastguard Worker     }
101*cf78ab8cSAndroid Build Coastguard Worker }
102*cf78ab8cSAndroid Build Coastguard Worker 
103*cf78ab8cSAndroid Build Coastguard Worker /// Handle requests from gRPC transport in C++.
handle_response_cxx(chip_id: u32, packet: &cxx::CxxVector<u8>, packet_type: u8)104*cf78ab8cSAndroid Build Coastguard Worker pub fn handle_response_cxx(chip_id: u32, packet: &cxx::CxxVector<u8>, packet_type: u8) {
105*cf78ab8cSAndroid Build Coastguard Worker     // TODO(b/314840701):
106*cf78ab8cSAndroid Build Coastguard Worker     // 1. Per EChip Struct should contain private field of channel & facade_id
107*cf78ab8cSAndroid Build Coastguard Worker     // 2. Lookup from ECHIPS with given chip_id
108*cf78ab8cSAndroid Build Coastguard Worker     // 3. Call adaptor.handle_response
109*cf78ab8cSAndroid Build Coastguard Worker     let packet = Bytes::from(packet.as_slice().to_vec());
110*cf78ab8cSAndroid Build Coastguard Worker     let chip_id = ChipIdentifier(chip_id);
111*cf78ab8cSAndroid Build Coastguard Worker     captures::controller_to_host(chip_id, &packet, packet_type.into());
112*cf78ab8cSAndroid Build Coastguard Worker 
113*cf78ab8cSAndroid Build Coastguard Worker     let result = if let Some(transport) = get_manager().transports.read().unwrap().get(&chip_id) {
114*cf78ab8cSAndroid Build Coastguard Worker         transport.send(ResponsePacket { packet, packet_type })
115*cf78ab8cSAndroid Build Coastguard Worker     } else {
116*cf78ab8cSAndroid Build Coastguard Worker         warn!("handle_response: chip {chip_id} not found");
117*cf78ab8cSAndroid Build Coastguard Worker         Ok(())
118*cf78ab8cSAndroid Build Coastguard Worker     };
119*cf78ab8cSAndroid Build Coastguard Worker     // transports lock is now released
120*cf78ab8cSAndroid Build Coastguard Worker     if let Err(e) = result {
121*cf78ab8cSAndroid Build Coastguard Worker         warn!("handle_response: error {:?}", e);
122*cf78ab8cSAndroid Build Coastguard Worker         unregister_transport(chip_id);
123*cf78ab8cSAndroid Build Coastguard Worker     }
124*cf78ab8cSAndroid Build Coastguard Worker }
125*cf78ab8cSAndroid Build Coastguard Worker 
126*cf78ab8cSAndroid Build Coastguard Worker // Handle response from rust libraries
handle_response(chip_id: ChipIdentifier, packet: &Bytes)127*cf78ab8cSAndroid Build Coastguard Worker pub fn handle_response(chip_id: ChipIdentifier, packet: &Bytes) {
128*cf78ab8cSAndroid Build Coastguard Worker     let packet_type = PacketType::HCI_PACKET_UNSPECIFIED.value() as u8;
129*cf78ab8cSAndroid Build Coastguard Worker     captures::controller_to_host(chip_id, packet, packet_type.into());
130*cf78ab8cSAndroid Build Coastguard Worker 
131*cf78ab8cSAndroid Build Coastguard Worker     let result = if let Some(transport) = get_manager().transports.read().unwrap().get(&chip_id) {
132*cf78ab8cSAndroid Build Coastguard Worker         transport.send(ResponsePacket { packet: packet.clone(), packet_type })
133*cf78ab8cSAndroid Build Coastguard Worker     } else {
134*cf78ab8cSAndroid Build Coastguard Worker         warn!("handle_response: chip {chip_id} not found");
135*cf78ab8cSAndroid Build Coastguard Worker         Ok(())
136*cf78ab8cSAndroid Build Coastguard Worker     };
137*cf78ab8cSAndroid Build Coastguard Worker     // transports lock is now released
138*cf78ab8cSAndroid Build Coastguard Worker     if let Err(e) = result {
139*cf78ab8cSAndroid Build Coastguard Worker         warn!("handle_response: error {:?}", e);
140*cf78ab8cSAndroid Build Coastguard Worker         unregister_transport(chip_id);
141*cf78ab8cSAndroid Build Coastguard Worker     }
142*cf78ab8cSAndroid Build Coastguard Worker }
143*cf78ab8cSAndroid Build Coastguard Worker 
144*cf78ab8cSAndroid Build Coastguard Worker /// Handle requests from transports.
handle_request(chip_id: ChipIdentifier, packet: &Bytes, packet_type: u8)145*cf78ab8cSAndroid Build Coastguard Worker pub fn handle_request(chip_id: ChipIdentifier, packet: &Bytes, packet_type: u8) {
146*cf78ab8cSAndroid Build Coastguard Worker     captures::host_to_controller(chip_id, packet, packet_type.into());
147*cf78ab8cSAndroid Build Coastguard Worker 
148*cf78ab8cSAndroid Build Coastguard Worker     let mut packet_vec = packet.to_vec();
149*cf78ab8cSAndroid Build Coastguard Worker     // Prepend packet_type to packet if specified
150*cf78ab8cSAndroid Build Coastguard Worker     if PacketType::HCI_PACKET_UNSPECIFIED.value()
151*cf78ab8cSAndroid Build Coastguard Worker         != <u8 as std::convert::Into<i32>>::into(packet_type)
152*cf78ab8cSAndroid Build Coastguard Worker     {
153*cf78ab8cSAndroid Build Coastguard Worker         packet_vec.insert(0, packet_type);
154*cf78ab8cSAndroid Build Coastguard Worker     }
155*cf78ab8cSAndroid Build Coastguard Worker 
156*cf78ab8cSAndroid Build Coastguard Worker     // Perform handle_request
157*cf78ab8cSAndroid Build Coastguard Worker     match chip::get_chip(&chip_id) {
158*cf78ab8cSAndroid Build Coastguard Worker         Some(c) => c.wireless_adaptor.handle_request(&Bytes::from(packet_vec)),
159*cf78ab8cSAndroid Build Coastguard Worker         None => warn!("SharedWirelessAdaptor doesn't exist for chip_id: {chip_id}"),
160*cf78ab8cSAndroid Build Coastguard Worker     }
161*cf78ab8cSAndroid Build Coastguard Worker }
162*cf78ab8cSAndroid Build Coastguard Worker 
163*cf78ab8cSAndroid Build Coastguard Worker /// Handle requests from gRPC transport in C++.
handle_request_cxx(chip_id: u32, packet: &cxx::CxxVector<u8>, packet_type: u8)164*cf78ab8cSAndroid Build Coastguard Worker pub fn handle_request_cxx(chip_id: u32, packet: &cxx::CxxVector<u8>, packet_type: u8) {
165*cf78ab8cSAndroid Build Coastguard Worker     let packet_bytes = Bytes::from(packet.as_slice().to_vec());
166*cf78ab8cSAndroid Build Coastguard Worker     handle_request(ChipIdentifier(chip_id), &packet_bytes, packet_type);
167*cf78ab8cSAndroid Build Coastguard Worker }
168*cf78ab8cSAndroid Build Coastguard Worker 
169*cf78ab8cSAndroid Build Coastguard Worker #[cfg(test)]
170*cf78ab8cSAndroid Build Coastguard Worker mod tests {
171*cf78ab8cSAndroid Build Coastguard Worker     use super::*;
172*cf78ab8cSAndroid Build Coastguard Worker 
173*cf78ab8cSAndroid Build Coastguard Worker     struct TestTransport {}
174*cf78ab8cSAndroid Build Coastguard Worker     impl Response for TestTransport {
response(&mut self, _packet: Bytes, _packet_type: u8)175*cf78ab8cSAndroid Build Coastguard Worker         fn response(&mut self, _packet: Bytes, _packet_type: u8) {}
176*cf78ab8cSAndroid Build Coastguard Worker     }
177*cf78ab8cSAndroid Build Coastguard Worker 
178*cf78ab8cSAndroid Build Coastguard Worker     #[test]
test_register_transport()179*cf78ab8cSAndroid Build Coastguard Worker     fn test_register_transport() {
180*cf78ab8cSAndroid Build Coastguard Worker         let val: Box<dyn Response + Send> = Box::new(TestTransport {});
181*cf78ab8cSAndroid Build Coastguard Worker         let manager = PacketManager::new();
182*cf78ab8cSAndroid Build Coastguard Worker         let chip_id = ChipIdentifier(0);
183*cf78ab8cSAndroid Build Coastguard Worker         manager.register_transport(chip_id, val);
184*cf78ab8cSAndroid Build Coastguard Worker         {
185*cf78ab8cSAndroid Build Coastguard Worker             assert!(manager.transports.read().unwrap().contains_key(&chip_id));
186*cf78ab8cSAndroid Build Coastguard Worker         }
187*cf78ab8cSAndroid Build Coastguard Worker     }
188*cf78ab8cSAndroid Build Coastguard Worker 
189*cf78ab8cSAndroid Build Coastguard Worker     #[test]
test_unregister_transport()190*cf78ab8cSAndroid Build Coastguard Worker     fn test_unregister_transport() {
191*cf78ab8cSAndroid Build Coastguard Worker         let manager = PacketManager::new();
192*cf78ab8cSAndroid Build Coastguard Worker         let chip_id = ChipIdentifier(1);
193*cf78ab8cSAndroid Build Coastguard Worker         manager.register_transport(chip_id, Box::new(TestTransport {}));
194*cf78ab8cSAndroid Build Coastguard Worker         manager.unregister_transport(chip_id);
195*cf78ab8cSAndroid Build Coastguard Worker         assert!(manager.transports.read().unwrap().get(&chip_id).is_none());
196*cf78ab8cSAndroid Build Coastguard Worker     }
197*cf78ab8cSAndroid Build Coastguard Worker }
198