1 // Copyright 2023 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::ChipIdentifier;
16 use crate::ffi::ffi_wifi;
17 use crate::wifi::medium::Medium;
18 use crate::wireless::{packet::handle_response, WirelessAdaptor, WirelessAdaptorImpl};
19 use bytes::Bytes;
20 use lazy_static::lazy_static;
21 use log::info;
22 use netsim_proto::config::WiFi as WiFiConfig;
23 use netsim_proto::model::Chip as ProtoChip;
24 use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats};
25 use protobuf::{Message, MessageField};
26 use std::sync::atomic::Ordering;
27 use std::thread;
28 use std::time::{Duration, Instant};
29
30 /// Parameters for creating Wifi chips
31 /// allow(dead_code) due to not being used in unit tests
32 #[allow(dead_code)]
33 pub struct CreateParams {}
34
35 /// Wifi struct will keep track of chip_id
36 pub struct Wifi {
37 chip_id: ChipIdentifier,
38 }
39
40 pub struct WifiManager {
41 medium: Medium,
42 request_sender: std::sync::mpsc::Sender<(u32, Bytes)>,
43 response_sender: std::sync::mpsc::Sender<Bytes>,
44 }
45
46 impl WifiManager {
new() -> WifiManager47 pub fn new() -> WifiManager {
48 let (request_sender, rx) = std::sync::mpsc::channel::<(u32, Bytes)>();
49
50 thread::spawn(move || {
51 const POLL_INTERVAL: Duration = Duration::from_millis(1);
52 let mut next_instant = Instant::now() + POLL_INTERVAL;
53
54 loop {
55 let this_instant = Instant::now();
56 let timeout = if next_instant > this_instant {
57 next_instant - this_instant
58 } else {
59 Duration::ZERO
60 };
61 match rx.recv_timeout(timeout) {
62 Ok((chip_id, packet)) => {
63 // When Wi-Fi P2P is disabled, send all packets to WifiService.
64 if crate::config::get_disable_wifi_p2p()
65 || !WIFI_MANAGER.medium.process(chip_id, &packet)
66 {
67 // TODO: Replace with libslirp_send() and hostapd_send()
68 ffi_wifi::handle_wifi_request(chip_id, &packet.to_vec());
69 ffi_wifi::libslirp_main_loop_wait();
70 }
71 }
72 _ => {
73 ffi_wifi::libslirp_main_loop_wait();
74 next_instant = Instant::now() + POLL_INTERVAL;
75 }
76 };
77 }
78 });
79
80 let (response_sender, rx) = std::sync::mpsc::channel::<Bytes>();
81 thread::spawn(move || loop {
82 let packet = rx.recv().unwrap();
83 WIFI_MANAGER.medium.process_response(&packet);
84 });
85 WifiManager { medium: Medium::new(medium_callback), request_sender, response_sender }
86 }
87 }
88
89 // Allocator for chip identifiers.
90 lazy_static! {
91 static ref WIFI_MANAGER: WifiManager = WifiManager::new();
92 }
93
94 impl Drop for Wifi {
drop(&mut self)95 fn drop(&mut self) {
96 WIFI_MANAGER.medium.remove(self.chip_id.0);
97 }
98 }
99
100 impl WirelessAdaptor for Wifi {
handle_request(&self, packet: &Bytes)101 fn handle_request(&self, packet: &Bytes) {
102 WIFI_MANAGER.request_sender.send((self.chip_id.0, packet.clone())).unwrap();
103 }
104
reset(&self)105 fn reset(&self) {
106 WIFI_MANAGER.medium.reset(self.chip_id.0);
107 }
108
get(&self) -> ProtoChip109 fn get(&self) -> ProtoChip {
110 let mut chip_proto = ProtoChip::new();
111 if let Some(client) = WIFI_MANAGER.medium.get(self.chip_id.0) {
112 chip_proto.mut_wifi().state = Some(client.enabled.load(Ordering::Relaxed));
113 chip_proto.mut_wifi().tx_count = client.tx_count.load(Ordering::Relaxed) as i32;
114 chip_proto.mut_wifi().rx_count = client.rx_count.load(Ordering::Relaxed) as i32;
115 }
116 chip_proto
117 }
118
patch(&self, patch: &ProtoChip)119 fn patch(&self, patch: &ProtoChip) {
120 if patch.wifi().state.is_some() {
121 WIFI_MANAGER.medium.set_enabled(self.chip_id.0, patch.wifi().state.unwrap());
122 }
123 }
124
get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats>125 fn get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats> {
126 let mut stats_proto = ProtoRadioStats::new();
127 stats_proto.set_duration_secs(duration_secs);
128 stats_proto.set_kind(netsim_radio_stats::Kind::WIFI);
129 let chip_proto = self.get();
130 if chip_proto.has_wifi() {
131 stats_proto.set_tx_count(chip_proto.wifi().tx_count);
132 stats_proto.set_rx_count(chip_proto.wifi().rx_count);
133 }
134 vec![stats_proto]
135 }
136 }
137
medium_callback(id: u32, packet: &Bytes)138 fn medium_callback(id: u32, packet: &Bytes) {
139 handle_response(ChipIdentifier(id), packet);
140 }
141
handle_wifi_response(packet: &[u8])142 pub fn handle_wifi_response(packet: &[u8]) {
143 let bytes = Bytes::copy_from_slice(packet);
144 WIFI_MANAGER.response_sender.send(bytes).unwrap();
145 }
146
147 /// Create a new Emulated Wifi Chip
148 /// allow(dead_code) due to not being used in unit tests
149 #[allow(dead_code)]
new(_params: &CreateParams, chip_id: ChipIdentifier) -> WirelessAdaptorImpl150 pub fn new(_params: &CreateParams, chip_id: ChipIdentifier) -> WirelessAdaptorImpl {
151 WIFI_MANAGER.medium.add(chip_id.0);
152 info!("WiFi WirelessAdaptor created chip_id: {chip_id}");
153 let wifi = Wifi { chip_id };
154 Box::new(wifi)
155 }
156
157 /// Starts the WiFi service.
wifi_start(config: &MessageField<WiFiConfig>)158 pub fn wifi_start(config: &MessageField<WiFiConfig>) {
159 let proto_bytes = config.as_ref().unwrap_or_default().write_to_bytes().unwrap();
160 ffi_wifi::wifi_start(&proto_bytes);
161 }
162
163 /// Stops the WiFi service.
wifi_stop()164 pub fn wifi_stop() {
165 ffi_wifi::wifi_stop();
166 }
167