• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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