1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 use crate::devices::chip;
16 use crate::devices::device::AddChipResult;
17 use crate::devices::devices_handler;
18 use crate::transport::grpc::RustGrpcTransport;
19 use crate::wireless;
20 use crate::wireless::packet::{register_transport, unregister_transport};
21 use anyhow::{anyhow, Context};
22 use bytes::Bytes;
23 use futures_util::{FutureExt as _, TryFutureExt as _, TryStreamExt as _};
24 use log::{info, warn};
25 use netsim_proto::common::ChipKind as ProtoChipKind;
26 use netsim_proto::hci_packet::hcipacket::PacketType;
27 use netsim_proto::packet_streamer::{PacketRequest, PacketResponse};
28 use netsim_proto::packet_streamer_grpc::PacketStreamer;
29 use netsim_proto::startup::ChipInfo;
30 use protobuf::Enum;
31
add_chip(initial_info: &ChipInfo, device_guid: &str) -> anyhow::Result<AddChipResult>32 fn add_chip(initial_info: &ChipInfo, device_guid: &str) -> anyhow::Result<AddChipResult> {
33 let chip_kind =
34 initial_info.chip.kind.enum_value().map_err(|v| anyhow!("unknown chip kind {v}"))?;
35 let chip = &initial_info.chip;
36 // TODO(b/323899010): Avoid having cfg(test) in mainline code
37 #[cfg(not(test))]
38 let wireless_create_param = match &chip_kind {
39 ProtoChipKind::BLUETOOTH => {
40 wireless::CreateParam::Bluetooth(wireless::bluetooth::CreateParams {
41 address: chip.address.clone(),
42 bt_properties: Some(chip.bt_properties.clone()),
43 })
44 }
45 ProtoChipKind::WIFI => wireless::CreateParam::Wifi(wireless::wifi::CreateParams {}),
46 ProtoChipKind::UWB => wireless::CreateParam::Uwb(wireless::uwb::CreateParams {
47 address: chip.address.clone(),
48 }),
49 _ => return Err(anyhow!("The provided chip kind is unsupported: {:?}", chip.kind)),
50 };
51 #[cfg(test)]
52 let wireless_create_param =
53 wireless::CreateParam::Mock(wireless::mocked::CreateParams { chip_kind });
54
55 let chip_create_params = chip::CreateParams {
56 kind: chip_kind,
57 address: chip.address.clone(),
58 name: Some(chip.id.clone()),
59 manufacturer: chip.manufacturer.clone(),
60 product_name: chip.product_name.clone(),
61 };
62
63 devices_handler::add_chip(
64 device_guid,
65 &initial_info.name,
66 &chip_create_params,
67 &wireless_create_param,
68 initial_info.device_info.clone().unwrap_or_default(),
69 )
70 .map_err(|err| anyhow!(err))
71 }
72
73 #[derive(Clone)]
74 pub struct PacketStreamerService;
75 impl PacketStreamer for PacketStreamerService {
stream_packets( &mut self, ctx: ::grpcio::RpcContext, mut packet_request: ::grpcio::RequestStream<PacketRequest>, sink: ::grpcio::DuplexSink<PacketResponse>, )76 fn stream_packets(
77 &mut self,
78 ctx: ::grpcio::RpcContext,
79 mut packet_request: ::grpcio::RequestStream<PacketRequest>,
80 sink: ::grpcio::DuplexSink<PacketResponse>,
81 ) {
82 let peer = ctx.peer().clone();
83 let f = async move {
84 info!("grpc_server new packet_stream for peer {}", &peer);
85
86 let request = packet_request.try_next().await?.context("initial info")?;
87 let initial_info: &ChipInfo = request.initial_info();
88
89 let result = add_chip(initial_info, &peer)?;
90
91 register_transport(result.chip_id, Box::new(RustGrpcTransport { sink }));
92
93 while let Some(request) = packet_request.try_next().await? {
94 let chip_kind = &initial_info.chip.kind.unwrap();
95 match chip_kind {
96 ProtoChipKind::WIFI | ProtoChipKind::UWB => {
97 if !request.has_packet() {
98 warn!("unknown packet type from chip_id: {}", result.chip_id);
99 continue;
100 }
101 let packet: Bytes = request.packet().to_vec().into();
102 wireless::handle_request(
103 result.chip_id,
104 &packet,
105 PacketType::HCI_PACKET_UNSPECIFIED.value() as u8,
106 );
107 }
108 ProtoChipKind::BLUETOOTH => {
109 if !request.has_hci_packet() {
110 warn!("unknown packet type from chip_id: {}", result.chip_id);
111 continue;
112 }
113 let packet: Bytes = request.hci_packet().packet.to_vec().into();
114 wireless::handle_request(
115 result.chip_id,
116 &packet,
117 request.hci_packet().packet_type.unwrap().value() as u8,
118 );
119 }
120 _ => {
121 warn!("unknown control packet chip_kind: {:?}", chip_kind);
122 break;
123 }
124 };
125 }
126 unregister_transport(result.chip_id);
127 if let Err(e) = devices_handler::remove_chip(result.device_id, result.chip_id) {
128 warn!("failed to remove chip: {}", e);
129 }
130 Ok(())
131 }
132 .map_err(|e: anyhow::Error| warn!("failed to stream packets: {:?}", e))
133 .map(|_| ());
134 ctx.spawn(f)
135 }
136 }
137