xref: /aosp_15_r20/tools/netsim/rust/daemon/src/wifi/medium.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
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::wifi::frame::Frame;
16 use crate::wifi::hostapd::Hostapd;
17 use crate::wifi::hwsim_attr_set::HwsimAttrSet;
18 use anyhow::{anyhow, Context};
19 use bytes::Bytes;
20 use log::{debug, info, warn};
21 use netsim_packets::ieee80211::{DataSubType, Ieee80211, MacAddress};
22 use netsim_packets::mac80211_hwsim::{HwsimCmd, HwsimMsg, HwsimMsgHdr, NlMsgHdr};
23 use pdl_runtime::Packet;
24 use std::collections::HashMap;
25 use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
26 use std::sync::{Arc, RwLock};
27 
28 const NLMSG_MIN_TYPE: u16 = 0x10;
29 const NL_AUTO_SEQ: u16 = 0;
30 const NL_AUTO_PORT: u32 = 0;
31 // Default values for mac80211_hwsim.
32 const RX_RATE: u32 = 0;
33 const SIGNAL: u32 = 4294967246; // -50
34 const NL_MSG_HDR_LEN: usize = 16;
35 
36 pub struct Processor {
37     pub hostapd: bool,
38     pub network: bool,
39     pub wmedium: bool,
40     pub frame: Frame,
41     pub plaintext_ieee80211: Option<Ieee80211>,
42 }
43 
44 impl Processor {
45     /// Returns the decrypted IEEE 802.11 frame if available.
46     /// Otherwise, returns the original IEEE 80211 frame.
get_ieee80211(&self) -> &Ieee8021147     pub fn get_ieee80211(&self) -> &Ieee80211 {
48         self.plaintext_ieee80211.as_ref().unwrap_or(&self.frame.ieee80211)
49     }
50 
51     /// Returns the decrypted IEEE 802.11 frame as bytes if available.
52     /// Otherwise, returns the original IEEE 80211 frame as bytes.
get_ieee80211_bytes(&self) -> Bytes53     pub fn get_ieee80211_bytes(&self) -> Bytes {
54         if let Some(ieee80211) = self.plaintext_ieee80211.as_ref() {
55             ieee80211.encode_to_vec().unwrap().into()
56         } else {
57             self.frame.data.clone().into()
58         }
59     }
60 }
61 
62 #[allow(dead_code)]
63 #[derive(Debug)]
64 pub enum HwsimCmdEnum {
65     Unspec,
66     Register,
67     Frame(Box<Frame>),
68     TxInfoFrame,
69     NewRadio,
70     DelRadio,
71     GetRadio,
72     AddMacAddr,
73     DelMacAddr,
74 }
75 
76 #[derive(Clone)]
77 struct Station {
78     client_id: u32,
79     // Ieee80211 source address
80     addr: MacAddress,
81     // Hwsim virtual address from HWSIM_ATTR_ADDR_TRANSMITTER
82     // Used to create the HwsimMsg to stations.
83     hwsim_addr: MacAddress,
84     // Caches the frequency (HWSIM_ATTR_FREQ) from the latest HwsimMsg request.
85     // This value is used to populate the HWSIM_ATTR_FREQ field in HwsimMsg response.
86     freq: Arc<AtomicU32>,
87 }
88 
89 impl Station {
new(client_id: u32, addr: MacAddress, hwsim_addr: MacAddress) -> Self90     fn new(client_id: u32, addr: MacAddress, hwsim_addr: MacAddress) -> Self {
91         Self { client_id, addr, hwsim_addr, freq: Arc::new(AtomicU32::new(0)) }
92     }
93 
update_freq(&self, freq: u32)94     fn update_freq(&self, freq: u32) {
95         self.freq.store(freq, Ordering::Relaxed);
96     }
97 }
98 
99 #[derive(Clone)]
100 pub struct Client {
101     pub enabled: Arc<AtomicBool>,
102     pub tx_count: Arc<AtomicU32>,
103     pub rx_count: Arc<AtomicU32>,
104 }
105 
106 impl Client {
new() -> Self107     fn new() -> Self {
108         Self {
109             enabled: Arc::new(AtomicBool::new(true)),
110             tx_count: Arc::new(AtomicU32::new(0)),
111             rx_count: Arc::new(AtomicU32::new(0)),
112         }
113     }
114 }
115 
116 pub struct Medium {
117     callback: HwsimCmdCallback,
118     // Ieee80211 source address
119     stations: RwLock<HashMap<MacAddress, Arc<Station>>>,
120     clients: RwLock<HashMap<u32, Client>>,
121     // Simulate the re-transmission of frames sent to hostapd
122     ap_simulation: bool,
123     hostapd: Arc<Hostapd>,
124 }
125 
126 type HwsimCmdCallback = fn(u32, &Bytes);
127 impl Medium {
new(callback: HwsimCmdCallback, hostapd: Arc<Hostapd>) -> Medium128     pub fn new(callback: HwsimCmdCallback, hostapd: Arc<Hostapd>) -> Medium {
129         Self {
130             callback,
131             stations: RwLock::new(HashMap::new()),
132             clients: RwLock::new(HashMap::new()),
133             ap_simulation: true,
134             hostapd,
135         }
136     }
137 
add(&self, client_id: u32)138     pub fn add(&self, client_id: u32) {
139         let _ = self.clients.write().unwrap().entry(client_id).or_insert_with(|| {
140             info!("Insert client {}", client_id);
141             Client::new()
142         });
143     }
144 
remove(&self, client_id: u32)145     pub fn remove(&self, client_id: u32) {
146         self.stations.write().unwrap().retain(|_, s| s.client_id != client_id);
147         self.clients.write().unwrap().remove(&client_id);
148     }
149 
reset(&self, client_id: u32)150     pub fn reset(&self, client_id: u32) {
151         if let Some(client) = self.clients.read().unwrap().get(&client_id) {
152             client.enabled.store(true, Ordering::Relaxed);
153             client.tx_count.store(0, Ordering::Relaxed);
154             client.rx_count.store(0, Ordering::Relaxed);
155         }
156     }
157 
get(&self, client_id: u32) -> Option<Client>158     pub fn get(&self, client_id: u32) -> Option<Client> {
159         self.clients.read().unwrap().get(&client_id).map(|c| c.to_owned())
160     }
161 
contains_client(&self, client_id: u32) -> bool162     fn contains_client(&self, client_id: u32) -> bool {
163         self.clients.read().unwrap().contains_key(&client_id)
164     }
165 
stations(&self) -> impl Iterator<Item = Arc<Station>>166     fn stations(&self) -> impl Iterator<Item = Arc<Station>> {
167         self.stations.read().unwrap().clone().into_values()
168     }
169 
contains_station(&self, addr: &MacAddress) -> bool170     fn contains_station(&self, addr: &MacAddress) -> bool {
171         self.stations.read().unwrap().contains_key(addr)
172     }
173 
get_station(&self, addr: &MacAddress) -> anyhow::Result<Arc<Station>>174     fn get_station(&self, addr: &MacAddress) -> anyhow::Result<Arc<Station>> {
175         self.stations.read().unwrap().get(addr).context("get station").cloned()
176     }
177 
upsert_station(&self, client_id: u32, frame: &Frame) -> anyhow::Result<()>178     fn upsert_station(&self, client_id: u32, frame: &Frame) -> anyhow::Result<()> {
179         let src_addr = frame.ieee80211.get_source();
180         let hwsim_addr = frame.transmitter.context("transmitter")?;
181         self.stations.write().unwrap().entry(src_addr).or_insert_with(|| {
182             info!(
183                 "Insert station with client id {}, hwsimaddr: {}, \
184                 Ieee80211 addr: {}",
185                 client_id, hwsim_addr, src_addr
186             );
187             Arc::new(Station::new(client_id, src_addr, hwsim_addr))
188         });
189         if !self.contains_client(client_id) {
190             warn!("Client {} is missing", client_id);
191             self.add(client_id);
192         }
193         Ok(())
194     }
195 
ack_frame(&self, client_id: u32, frame: &Frame)196     pub fn ack_frame(&self, client_id: u32, frame: &Frame) {
197         // Send Ack frame back to source
198         self.ack_frame_internal(client_id, frame).unwrap_or_else(move |e| {
199             // TODO: add this error to the netsim_session_stats
200             warn!("error ack frame {e}");
201         });
202     }
203 
ack_frame_internal(&self, client_id: u32, frame: &Frame) -> anyhow::Result<()>204     fn ack_frame_internal(&self, client_id: u32, frame: &Frame) -> anyhow::Result<()> {
205         self.send_tx_info_frame(frame)?;
206         self.incr_tx(client_id)?;
207         Ok(())
208     }
209 
210     /// Process commands from the kernel's mac80211_hwsim subsystem.
211     ///
212     /// This is the processing that will be implemented:
213     ///
214     /// * The source MacAddress in 802.11 frames is re-mapped to a globally
215     ///   unique MacAddress because resumed Emulator AVDs appear with the
216     ///   same address.
217     ///
218     /// * 802.11 frames sent between stations
219     ///
220     /// * 802.11 multicast frames are re-broadcast to connected stations.
get_processor(&self, client_id: u32, packet: &Bytes) -> Option<Processor>221     pub fn get_processor(&self, client_id: u32, packet: &Bytes) -> Option<Processor> {
222         let frame = self
223             .validate(client_id, packet)
224             .map_err(|e| warn!("error validate for client {client_id}: {e}"))
225             .ok()?;
226 
227         // Creates Stations on the fly when there is no config file.
228         // WiFi Direct will use a randomized mac address for probing
229         // new networks. This block associates the new mac with the station.
230         self.upsert_station(client_id, &frame)
231             .map_err(|e| warn!("error upsert station for client {client_id}: {e}"))
232             .ok()?;
233 
234         let plaintext_ieee80211 = self.hostapd.try_decrypt(&frame.ieee80211);
235 
236         let mut processor = Processor {
237             hostapd: false,
238             network: false,
239             wmedium: false,
240             frame,
241             plaintext_ieee80211,
242         };
243 
244         let dest_addr = processor.frame.ieee80211.get_destination();
245 
246         processor.frame.attrs.freq.map(|freq| {
247             self.get_station(&processor.frame.ieee80211.get_source())
248                 .map(|sta| sta.update_freq(freq))
249                 .map_err(|e| {
250                     warn!("Failed to get station for client {client_id} to update freq: {e}")
251                 })
252         });
253 
254         if self.contains_station(&dest_addr) {
255             processor.wmedium = true;
256             return Some(processor);
257         }
258         if dest_addr.is_multicast() {
259             processor.wmedium = true;
260         }
261 
262         let ieee80211: &Ieee80211 = processor.get_ieee80211();
263         // If the BSSID is unicast and does not match the hostapd's BSSID, the packet is not handled by hostapd. Skip further checks.
264         if let Some(bssid) = ieee80211.get_bssid() {
265             if !bssid.is_multicast() && bssid != self.hostapd.get_bssid() {
266                 return Some(processor);
267             }
268         }
269         // Data frames
270         if ieee80211.is_data() {
271             // EAPoL is used in Wi-Fi 4-way handshake.
272             let is_eapol = ieee80211.is_eapol().unwrap_or_else(|e| {
273                 debug!("Failed to get ether type for is_eapol(): {}", e);
274                 false
275             });
276             if is_eapol {
277                 processor.hostapd = true;
278             } else if ieee80211.is_to_ap() {
279                 // Don't forward Null Data frames to slirp because they are used to maintain an active connection and carry no user data.
280                 if ieee80211.stype() != DataSubType::Nodata.into() {
281                     processor.network = true;
282                 }
283             }
284         } else {
285             // Mgmt or Ctrl frames.
286             // TODO: Refactor this check after verifying all packets sent to hostapd are of ToAP type.
287             let addr1 = ieee80211.get_addr1();
288             if addr1.is_multicast() || addr1.is_broadcast() || addr1 == self.hostapd.get_bssid() {
289                 processor.hostapd = true;
290             }
291         }
292         Some(processor)
293     }
294 
validate(&self, client_id: u32, packet: &Bytes) -> anyhow::Result<Frame>295     fn validate(&self, client_id: u32, packet: &Bytes) -> anyhow::Result<Frame> {
296         let hwsim_msg = HwsimMsg::decode_full(packet)?;
297 
298         // The virtio handler only accepts HWSIM_CMD_FRAME, HWSIM_CMD_TX_INFO_FRAME and HWSIM_CMD_REPORT_PMSR
299         // in https://source.corp.google.com/h/kernel/pub/scm/linux/kernel/git/torvalds/linux/+/master:drivers/net/wireless/virtual/mac80211_hwsim.c
300         match hwsim_msg.hwsim_hdr.hwsim_cmd {
301             HwsimCmd::Frame => {
302                 let frame = Frame::parse(&hwsim_msg)?;
303                 // Incoming frame must contain transmitter, flag, cookie, and tx_info fields.
304                 if frame.transmitter.is_none()
305                     || frame.flags.is_none()
306                     || frame.cookie.is_none()
307                     || frame.tx_info.is_none()
308                 {
309                     return Err(anyhow!("Missing Hwsim attributes for incoming packet"));
310                 }
311                 // Use as receiver for outgoing HwsimMsg.
312                 let hwsim_addr = frame.transmitter.context("transmitter")?;
313                 let flags = frame.flags.context("flags")?;
314                 let cookie = frame.cookie.context("cookie")?;
315                 debug!(
316                     "Frame chip {}, transmitter {}, flags {}, cookie {}, ieee80211 {}",
317                     client_id, hwsim_addr, flags, cookie, frame.ieee80211
318                 );
319                 Ok(frame)
320             }
321             _ => Err(anyhow!("Another command found {:?}", hwsim_msg)),
322         }
323     }
324 
325     /// Handle Wi-Fi Ieee802.3 frame from network.
326     /// Convert to HwsimMsg and send to clients.
process_ieee8023_response(&self, packet: &Bytes)327     pub fn process_ieee8023_response(&self, packet: &Bytes) {
328         let result = Ieee80211::from_ieee8023(packet, self.hostapd.get_bssid())
329             .and_then(|ieee80211| self.handle_ieee80211_response(ieee80211));
330 
331         if let Err(e) = result {
332             warn!("{}", e);
333         }
334     }
335 
336     /// Handle Wi-Fi Ieee802.11 frame from network.
337     /// Convert to HwsimMsg and send to clients.
process_ieee80211_response(&self, packet: &Bytes)338     pub fn process_ieee80211_response(&self, packet: &Bytes) {
339         let result = Ieee80211::decode_full(packet)
340             .context("Ieee80211")
341             .and_then(|ieee80211| self.handle_ieee80211_response(ieee80211));
342 
343         if let Err(e) = result {
344             warn!("{}", e);
345         }
346     }
347 
348     /// Determine the client id based on destination and send to client.
handle_ieee80211_response(&self, mut ieee80211: Ieee80211) -> anyhow::Result<()>349     fn handle_ieee80211_response(&self, mut ieee80211: Ieee80211) -> anyhow::Result<()> {
350         if let Some(encrypted_ieee80211) = self.hostapd.try_encrypt(&ieee80211) {
351             ieee80211 = encrypted_ieee80211;
352         }
353         let dest_addr = ieee80211.get_destination();
354         if let Ok(destination) = self.get_station(&dest_addr) {
355             self.send_ieee80211_response(&ieee80211, &destination)?;
356         } else if dest_addr.is_multicast() {
357             for destination in self.stations() {
358                 self.send_ieee80211_response(&ieee80211, &destination)?;
359             }
360         } else {
361             warn!("Send frame response to unknown destination: {}", dest_addr);
362         }
363         Ok(())
364     }
365 
send_ieee80211_response( &self, ieee80211: &Ieee80211, destination: &Station, ) -> anyhow::Result<()>366     fn send_ieee80211_response(
367         &self,
368         ieee80211: &Ieee80211,
369         destination: &Station,
370     ) -> anyhow::Result<()> {
371         let hwsim_msg = self.create_hwsim_msg_from_ieee80211(ieee80211, destination)?;
372         (self.callback)(destination.client_id, &hwsim_msg.encode_to_vec()?.into());
373         self.incr_rx(destination.client_id)?;
374         Ok(())
375     }
376 
create_hwsim_msg_from_ieee80211( &self, ieee80211: &Ieee80211, destination: &Station, ) -> anyhow::Result<HwsimMsg>377     fn create_hwsim_msg_from_ieee80211(
378         &self,
379         ieee80211: &Ieee80211,
380         destination: &Station,
381     ) -> anyhow::Result<HwsimMsg> {
382         let attributes = self.create_hwsim_msg_attr(ieee80211, destination)?;
383         let hwsim_hdr = HwsimMsgHdr { hwsim_cmd: HwsimCmd::Frame, hwsim_version: 0, reserved: 0 };
384         let nlmsg_len = (NL_MSG_HDR_LEN + hwsim_hdr.encoded_len() + attributes.len()) as u32;
385         let nl_hdr = NlMsgHdr {
386             nlmsg_len,
387             nlmsg_type: NLMSG_MIN_TYPE,
388             nlmsg_flags: NL_AUTO_SEQ,
389             nlmsg_seq: NL_AUTO_PORT,
390             nlmsg_pid: 0,
391         };
392         Ok(HwsimMsg { nl_hdr, hwsim_hdr, attributes })
393     }
394 
create_hwsim_msg_attr( &self, ieee80211: &Ieee80211, destination: &Station, ) -> anyhow::Result<Vec<u8>>395     fn create_hwsim_msg_attr(
396         &self,
397         ieee80211: &Ieee80211,
398         destination: &Station,
399     ) -> anyhow::Result<Vec<u8>> {
400         let mut builder = HwsimAttrSet::builder();
401         // Attributes required by mac80211_hwsim.
402         builder.receiver(&destination.hwsim_addr.to_vec());
403         let frame_bytes = ieee80211.encode_to_vec()?;
404         builder.frame(&frame_bytes);
405         builder.rx_rate(RX_RATE);
406         builder.signal(SIGNAL);
407         builder.freq(destination.freq.load(Ordering::Relaxed));
408         Ok(builder.build()?.attributes)
409     }
410 
set_enabled(&self, client_id: u32, enabled: bool)411     pub fn set_enabled(&self, client_id: u32, enabled: bool) {
412         if let Some(client) = self.clients.read().unwrap().get(&client_id) {
413             client.enabled.store(enabled, Ordering::Relaxed);
414         }
415     }
416 
enabled(&self, client_id: u32) -> anyhow::Result<bool>417     fn enabled(&self, client_id: u32) -> anyhow::Result<bool> {
418         Ok(self
419             .clients
420             .read()
421             .unwrap()
422             .get(&client_id)
423             .context(format!("client {client_id} is missing"))?
424             .enabled
425             .load(Ordering::Relaxed))
426     }
427 
428     /// Create tx info frame to station to ack HwsimMsg.
send_tx_info_frame(&self, frame: &Frame) -> anyhow::Result<()>429     fn send_tx_info_frame(&self, frame: &Frame) -> anyhow::Result<()> {
430         let client_id = self.get_station(&frame.ieee80211.get_source())?.client_id;
431         let hwsim_msg_tx_info = build_tx_info(&frame.hwsim_msg).unwrap().encode_to_vec()?;
432         (self.callback)(client_id, &hwsim_msg_tx_info.into());
433         Ok(())
434     }
435 
incr_tx(&self, client_id: u32) -> anyhow::Result<()>436     fn incr_tx(&self, client_id: u32) -> anyhow::Result<()> {
437         self.clients
438             .read()
439             .unwrap()
440             .get(&client_id)
441             .context("incr_tx")?
442             .tx_count
443             .fetch_add(1, Ordering::Relaxed);
444         Ok(())
445     }
446 
incr_rx(&self, client_id: u32) -> anyhow::Result<()>447     fn incr_rx(&self, client_id: u32) -> anyhow::Result<()> {
448         self.clients
449             .read()
450             .unwrap()
451             .get(&client_id)
452             .context("incr_rx")?
453             .rx_count
454             .fetch_add(1, Ordering::Relaxed);
455         Ok(())
456     }
457 
458     // Send an 802.11 frame from a station to a station after wrapping in HwsimMsg.
459     // The HwsimMsg is processed by mac80211_hwsim framework in the guest OS.
460     //
461     // Simulates transmission through hostapd.
send_from_sta_frame( &self, frame: &Frame, ieee80211: &Ieee80211, source: &Station, destination: &Station, ) -> anyhow::Result<()>462     fn send_from_sta_frame(
463         &self,
464         frame: &Frame,
465         ieee80211: &Ieee80211,
466         source: &Station,
467         destination: &Station,
468     ) -> anyhow::Result<()> {
469         if self.enabled(source.client_id)? && self.enabled(destination.client_id)? {
470             if let Some(packet) = self.create_hwsim_msg(frame, ieee80211, &destination.hwsim_addr) {
471                 self.incr_rx(destination.client_id)?;
472                 (self.callback)(destination.client_id, &packet.encode_to_vec()?.into());
473                 log_hwsim_msg(frame, source.client_id, destination.client_id);
474             }
475         }
476         Ok(())
477     }
478 
479     // Broadcast an 802.11 frame to all stations.
480     /// TODO: Compare with the implementations in mac80211_hwsim.c and wmediumd.c.
broadcast_from_sta_frame( &self, frame: &Frame, ieee80211: &Ieee80211, source: &Station, ) -> anyhow::Result<()>481     fn broadcast_from_sta_frame(
482         &self,
483         frame: &Frame,
484         ieee80211: &Ieee80211,
485         source: &Station,
486     ) -> anyhow::Result<()> {
487         for destination in self.stations() {
488             if source.addr != destination.addr {
489                 self.send_from_sta_frame(frame, ieee80211, source, &destination)?;
490             }
491         }
492         Ok(())
493     }
494     /// Queues the frame for sending to medium.
495     ///
496     /// The `frame` contains an `ieee80211` field, but it might be encrypted. This function uses the provided `ieee80211` parameter directly, as it's expected to be decrypted if necessary.
queue_frame(&self, frame: Frame, ieee80211: Ieee80211)497     pub fn queue_frame(&self, frame: Frame, ieee80211: Ieee80211) {
498         self.queue_frame_internal(frame, ieee80211).unwrap_or_else(move |e| {
499             // TODO: add this error to the netsim_session_stats
500             warn!("queue frame error {e}");
501         });
502     }
503 
queue_frame_internal(&self, frame: Frame, ieee80211: Ieee80211) -> anyhow::Result<()>504     fn queue_frame_internal(&self, frame: Frame, ieee80211: Ieee80211) -> anyhow::Result<()> {
505         let source = self.get_station(&ieee80211.get_source())?;
506         let dest_addr = ieee80211.get_destination();
507         if self.contains_station(&dest_addr) {
508             debug!("Frame deliver from {} to {}", source.addr, dest_addr);
509             let destination = self.get_station(&dest_addr)?;
510             self.send_from_sta_frame(&frame, &ieee80211, &source, &destination)?;
511             return Ok(());
512         } else if dest_addr.is_multicast() {
513             debug!("Frame multicast {}", ieee80211);
514             self.broadcast_from_sta_frame(&frame, &ieee80211, &source)?;
515             return Ok(());
516         }
517 
518         Err(anyhow!("Dropped packet {}", ieee80211))
519     }
520 
521     // Simulate transmission through hostapd by rewriting frames with 802.11 ToDS
522     // and hostapd_bssid to frames with FromDS set.
create_hwsim_attr( &self, frame: &Frame, ieee80211: &Ieee80211, dest_hwsim_addr: &MacAddress, ) -> anyhow::Result<Vec<u8>>523     fn create_hwsim_attr(
524         &self,
525         frame: &Frame,
526         ieee80211: &Ieee80211,
527         dest_hwsim_addr: &MacAddress,
528     ) -> anyhow::Result<Vec<u8>> {
529         // Encrypt Ieee80211 if needed
530         let attrs = &frame.attrs;
531         let mut ieee80211_response = match self.ap_simulation
532             && ieee80211.is_to_ap()
533             && ieee80211.get_bssid() == Some(self.hostapd.get_bssid())
534         {
535             true => ieee80211.into_from_ap()?.try_into()?,
536             false => ieee80211.clone(),
537         };
538         if let Some(encrypted_ieee80211) = self.hostapd.try_encrypt(&ieee80211_response) {
539             ieee80211_response = encrypted_ieee80211;
540         }
541         let frame = ieee80211_response.encode_to_vec()?;
542 
543         let mut builder = HwsimAttrSet::builder();
544 
545         // Attributes required by mac80211_hwsim.
546         builder.receiver(&dest_hwsim_addr.to_vec());
547         builder.frame(&frame);
548         // Incoming HwsimMsg don't have rx_rate and signal.
549         builder.rx_rate(attrs.rx_rate_idx.unwrap_or(RX_RATE));
550         builder.signal(attrs.signal.unwrap_or(SIGNAL));
551 
552         attrs.flags.map(|v| builder.flags(v));
553         attrs.freq.map(|v| builder.freq(v));
554         attrs.tx_info.as_ref().map(|v| builder.tx_info(v));
555         attrs.tx_info_flags.as_ref().map(|v| builder.tx_info_flags(v));
556 
557         Ok(builder.build()?.attributes)
558     }
559 
560     // Simulates transmission through hostapd.
create_hwsim_msg( &self, frame: &Frame, ieee80211: &Ieee80211, dest_hwsim_addr: &MacAddress, ) -> Option<HwsimMsg>561     fn create_hwsim_msg(
562         &self,
563         frame: &Frame,
564         ieee80211: &Ieee80211,
565         dest_hwsim_addr: &MacAddress,
566     ) -> Option<HwsimMsg> {
567         let hwsim_msg = &frame.hwsim_msg;
568         assert_eq!(hwsim_msg.hwsim_hdr.hwsim_cmd, HwsimCmd::Frame);
569         let attributes_result = self.create_hwsim_attr(frame, ieee80211, dest_hwsim_addr);
570         let attributes = match attributes_result {
571             Ok(attributes) => attributes,
572             Err(e) => {
573                 warn!("Failed to create from_ap attributes. E: {}", e);
574                 return None;
575             }
576         };
577 
578         let nlmsg_len = hwsim_msg.nl_hdr.nlmsg_len + attributes.len() as u32
579             - hwsim_msg.attributes.len() as u32;
580         let new_hwsim_msg = HwsimMsg {
581             nl_hdr: NlMsgHdr {
582                 nlmsg_len,
583                 nlmsg_type: NLMSG_MIN_TYPE,
584                 nlmsg_flags: hwsim_msg.nl_hdr.nlmsg_flags,
585                 nlmsg_seq: 0,
586                 nlmsg_pid: 0,
587             },
588             hwsim_hdr: hwsim_msg.hwsim_hdr.clone(),
589             attributes,
590         };
591         Some(new_hwsim_msg)
592     }
593 }
594 
log_hwsim_msg(frame: &Frame, client_id: u32, dest_client_id: u32)595 fn log_hwsim_msg(frame: &Frame, client_id: u32, dest_client_id: u32) {
596     debug!(
597         "Sent hwsim_msg from client {} to {}. flags {:?}, ieee80211 {}",
598         client_id, dest_client_id, frame.flags, frame.ieee80211,
599     );
600 }
601 
602 /// Build TxInfoFrame HwsimMsg from CmdFrame HwsimMsg.
603 ///
604 /// Reference to ackLocalFrame() in external/qemu/android-qemu2-glue/emulation/VirtioWifiForwarder.cpp
build_tx_info(hwsim_msg: &HwsimMsg) -> anyhow::Result<HwsimMsg>605 fn build_tx_info(hwsim_msg: &HwsimMsg) -> anyhow::Result<HwsimMsg> {
606     let attrs = HwsimAttrSet::parse(&hwsim_msg.attributes).context("HwsimAttrSet").unwrap();
607 
608     let hwsim_hdr = &hwsim_msg.hwsim_hdr;
609     let nl_hdr = &hwsim_msg.nl_hdr;
610     let mut new_attr_builder = HwsimAttrSet::builder();
611     const HWSIM_TX_STAT_ACK: u32 = 1 << 2;
612 
613     new_attr_builder
614         .transmitter(&attrs.transmitter.context("transmitter")?.into())
615         .flags(attrs.flags.context("flags")? | HWSIM_TX_STAT_ACK)
616         .cookie(attrs.cookie.context("cookie")?)
617         .signal(attrs.signal.unwrap_or(SIGNAL))
618         .tx_info(attrs.tx_info.context("tx_info")?.as_slice());
619 
620     let new_attr = new_attr_builder.build().unwrap();
621     let nlmsg_len =
622         nl_hdr.nlmsg_len + new_attr.attributes.len() as u32 - attrs.attributes.len() as u32;
623     let new_hwsim_msg = HwsimMsg {
624         attributes: new_attr.attributes,
625         hwsim_hdr: HwsimMsgHdr {
626             hwsim_cmd: HwsimCmd::TxInfoFrame,
627             hwsim_version: 0,
628             reserved: hwsim_hdr.reserved,
629         },
630         nl_hdr: NlMsgHdr {
631             nlmsg_len,
632             nlmsg_type: NLMSG_MIN_TYPE,
633             nlmsg_flags: nl_hdr.nlmsg_flags,
634             nlmsg_seq: 0,
635             nlmsg_pid: 0,
636         },
637     };
638     Ok(new_hwsim_msg)
639 }
640 
641 // It's used by radiotap.rs for packet capture.
parse_hwsim_cmd(packet: &[u8]) -> anyhow::Result<HwsimCmdEnum>642 pub fn parse_hwsim_cmd(packet: &[u8]) -> anyhow::Result<HwsimCmdEnum> {
643     let hwsim_msg = HwsimMsg::decode_full(packet)?;
644     match hwsim_msg.hwsim_hdr.hwsim_cmd {
645         HwsimCmd::Frame => {
646             let frame = Frame::parse(&hwsim_msg)?;
647             Ok(HwsimCmdEnum::Frame(Box::new(frame)))
648         }
649         HwsimCmd::TxInfoFrame => Ok(HwsimCmdEnum::TxInfoFrame),
650         _ => Err(anyhow!("Unknown HwsimMsg cmd={:?}", hwsim_msg.hwsim_hdr.hwsim_cmd)),
651     }
652 }
653 
654 #[cfg(test)]
655 mod tests {
656     use super::*;
657     use crate::wifi::hostapd;
658     use netsim_packets::ieee80211::{parse_mac_address, FrameType, Ieee80211, Ieee80211ToAp};
659 
660     #[test]
test_get_plaintext_ieee80211()661     fn test_get_plaintext_ieee80211() {
662         // Test Data (802.11 frame with LLC/SNAP)
663         let bssid = parse_mac_address("0:0:0:0:0:0").unwrap();
664         let source = parse_mac_address("1:1:1:1:1:1").unwrap();
665         let destination = parse_mac_address("2:2:2:2:2:2").unwrap();
666         let ieee80211: Ieee80211 = Ieee80211ToAp {
667             duration_id: 0,
668             ftype: FrameType::Data,
669             more_data: 0,
670             more_frags: 0,
671             order: 0,
672             pm: 0,
673             protected: 0,
674             retry: 0,
675             stype: 0,
676             version: 0,
677             bssid,
678             source,
679             destination,
680             seq_ctrl: 0,
681             payload: Vec::new(),
682         }
683         .try_into()
684         .unwrap();
685 
686         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame_mdns.csv");
687         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
688         let frame1 = Frame::parse(&hwsim_msg).unwrap();
689         let frame2 = Frame::parse(&hwsim_msg).unwrap();
690 
691         // Case 1: plaintext_ieee80211 is None
692         let processor = Processor {
693             hostapd: false,
694             network: false,
695             wmedium: false,
696             frame: frame1,
697             plaintext_ieee80211: None,
698         };
699         assert_eq!(processor.get_ieee80211(), &processor.frame.ieee80211);
700         assert_eq!(processor.get_ieee80211_bytes(), Bytes::from(processor.frame.data.clone()));
701 
702         // Case 2: plaintext_ieee80211 has a value
703         let processor = Processor {
704             hostapd: false,
705             network: false,
706             wmedium: false,
707             frame: frame2,
708             plaintext_ieee80211: Some(ieee80211),
709         };
710         assert_eq!(processor.get_ieee80211(), processor.plaintext_ieee80211.as_ref().unwrap());
711         assert_eq!(
712             processor.get_ieee80211_bytes(),
713             Bytes::from(processor.plaintext_ieee80211.as_ref().unwrap().encode_to_vec().unwrap())
714         );
715     }
716 
717     #[test]
test_remove()718     fn test_remove() {
719         let test_client_id: u32 = 1234;
720         let other_client_id: u32 = 5678;
721         let addr: MacAddress = parse_mac_address("00:0b:85:71:20:00").unwrap();
722         let other_addr: MacAddress = parse_mac_address("00:0b:85:71:20:01").unwrap();
723         let hwsim_addr: MacAddress = parse_mac_address("00:0b:85:71:20:ce").unwrap();
724         let other_hwsim_addr: MacAddress = parse_mac_address("00:0b:85:71:20:cf").unwrap();
725 
726         let hostapd_options = netsim_proto::config::HostapdOptions::new();
727         let (tx, _rx) = std::sync::mpsc::channel();
728         let hostapd = Arc::new(hostapd::hostapd_run(hostapd_options, tx).unwrap());
729 
730         // Create a test Medium object
731         let callback: HwsimCmdCallback = |_, _| {};
732         let medium = Medium {
733             callback,
734             stations: RwLock::new(HashMap::from([
735                 (
736                     addr,
737                     Arc::new(Station {
738                         client_id: test_client_id,
739                         addr,
740                         hwsim_addr,
741                         freq: Arc::new(AtomicU32::new(0)),
742                     }),
743                 ),
744                 (
745                     other_addr,
746                     Arc::new(Station {
747                         client_id: other_client_id,
748                         addr: other_addr,
749                         hwsim_addr: other_hwsim_addr,
750                         freq: Arc::new(AtomicU32::new(0)),
751                     }),
752                 ),
753             ])),
754             clients: RwLock::new(HashMap::from([
755                 (test_client_id, Client::new()),
756                 (other_client_id, Client::new()),
757             ])),
758             ap_simulation: true,
759             hostapd,
760         };
761 
762         medium.remove(test_client_id);
763 
764         assert!(!medium.contains_station(&addr));
765         assert!(medium.contains_station(&other_addr));
766         assert!(!medium.contains_client(test_client_id));
767         assert!(medium.contains_client(other_client_id));
768     }
769 
770     #[test]
test_netlink_attr()771     fn test_netlink_attr() {
772         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
773         assert!(parse_hwsim_cmd(&packet).is_ok());
774 
775         let tx_info_packet: Vec<u8> = include!("test_packets/hwsim_cmd_tx_info.csv");
776         assert!(parse_hwsim_cmd(&tx_info_packet).is_ok());
777     }
778 
779     #[test]
test_netlink_attr_response_packet()780     fn test_netlink_attr_response_packet() {
781         // Response packet may not contain transmitter, flags, tx_info, or cookie fields.
782         let response_packet: Vec<u8> =
783             include!("test_packets/hwsim_cmd_frame_response_no_transmitter_flags_tx_info.csv");
784         assert!(parse_hwsim_cmd(&response_packet).is_ok());
785 
786         let response_packet2: Vec<u8> =
787             include!("test_packets/hwsim_cmd_frame_response_no_cookie.csv");
788         assert!(parse_hwsim_cmd(&response_packet2).is_ok());
789     }
790 
791     #[test]
test_is_mdns_packet()792     fn test_is_mdns_packet() {
793         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame_mdns.csv");
794         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
795         let mdns_frame = Frame::parse(&hwsim_msg).unwrap();
796         assert!(!mdns_frame.ieee80211.get_source().is_multicast());
797         assert!(mdns_frame.ieee80211.get_destination().is_multicast());
798     }
799 
800     #[test]
test_build_tx_info_reconstruct()801     fn test_build_tx_info_reconstruct() {
802         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_tx_info.csv");
803         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
804         assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
805 
806         let new_hwsim_msg = build_tx_info(&hwsim_msg).unwrap();
807         assert_eq!(hwsim_msg, new_hwsim_msg);
808     }
809 
810     #[test]
test_build_tx_info()811     fn test_build_tx_info() {
812         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
813         let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
814         let hwsim_msg_tx_info = build_tx_info(&hwsim_msg).unwrap();
815         assert_eq!(hwsim_msg_tx_info.hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
816     }
817 
build_tx_info_and_compare(frame_bytes: &Bytes, tx_info_expected_bytes: &Bytes)818     fn build_tx_info_and_compare(frame_bytes: &Bytes, tx_info_expected_bytes: &Bytes) {
819         let frame = HwsimMsg::decode_full(frame_bytes).unwrap();
820         let tx_info = build_tx_info(&frame).unwrap();
821 
822         let tx_info_expected = HwsimMsg::decode_full(tx_info_expected_bytes).unwrap();
823 
824         assert_eq!(tx_info.hwsim_hdr(), tx_info_expected.hwsim_hdr());
825         assert_eq!(tx_info.nl_hdr(), tx_info_expected.nl_hdr());
826 
827         let attrs = HwsimAttrSet::parse(tx_info.attributes()).context("HwsimAttrSet").unwrap();
828         let attrs_expected =
829             HwsimAttrSet::parse(tx_info_expected.attributes()).context("HwsimAttrSet").unwrap();
830 
831         // NOTE: TX info is different and the counts are all zeros in the TX info packet generated by WifiService.
832         // TODO: Confirm if the behavior is intended in WifiService.
833         assert_eq!(attrs.transmitter, attrs_expected.transmitter);
834         assert_eq!(attrs.flags, attrs_expected.flags);
835         assert_eq!(attrs.cookie, attrs_expected.cookie);
836         assert_eq!(attrs.signal, attrs_expected.signal);
837     }
838 
839     #[test]
test_build_tx_info_and_compare()840     fn test_build_tx_info_and_compare() {
841         let frame_bytes = Bytes::from(include!("test_packets/hwsim_cmd_frame_request.csv"));
842         let tx_info_expected_bytes =
843             Bytes::from(include!("test_packets/hwsim_cmd_tx_info_response.csv"));
844         build_tx_info_and_compare(&frame_bytes, &tx_info_expected_bytes);
845     }
846 
847     #[test]
test_build_tx_info_and_compare_mdns()848     fn test_build_tx_info_and_compare_mdns() {
849         let frame_bytes = Bytes::from(include!("test_packets/hwsim_cmd_frame_request_mdns.csv"));
850         let tx_info_expected_bytes =
851             Bytes::from(include!("test_packets/hwsim_cmd_tx_info_response_mdns.csv"));
852         build_tx_info_and_compare(&frame_bytes, &tx_info_expected_bytes);
853     }
854 }
855