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 //! ieee80211 frames
16*cf78ab8cSAndroid Build Coastguard Worker
17*cf78ab8cSAndroid Build Coastguard Worker // TODO: only allow the warnings for the included code
18*cf78ab8cSAndroid Build Coastguard Worker #![allow(clippy::all)]
19*cf78ab8cSAndroid Build Coastguard Worker #![allow(missing_docs)]
20*cf78ab8cSAndroid Build Coastguard Worker #![allow(unused)]
21*cf78ab8cSAndroid Build Coastguard Worker include!(concat!(env!("OUT_DIR"), "/ieee80211_packets.rs"));
22*cf78ab8cSAndroid Build Coastguard Worker
23*cf78ab8cSAndroid Build Coastguard Worker use crate::llc::{EtherType, LlcCtrl, LlcSap, LlcSnapHeader};
24*cf78ab8cSAndroid Build Coastguard Worker use anyhow::anyhow;
25*cf78ab8cSAndroid Build Coastguard Worker
26*cf78ab8cSAndroid Build Coastguard Worker const ETHERTYPE_LEN: usize = 2;
27*cf78ab8cSAndroid Build Coastguard Worker
28*cf78ab8cSAndroid Build Coastguard Worker /// A Ieee80211 MAC address
29*cf78ab8cSAndroid Build Coastguard Worker
30*cf78ab8cSAndroid Build Coastguard Worker impl MacAddress {
to_vec(&self) -> [u8; 6]31*cf78ab8cSAndroid Build Coastguard Worker pub fn to_vec(&self) -> [u8; 6] {
32*cf78ab8cSAndroid Build Coastguard Worker u64::to_le_bytes(self.0)[0..6].try_into().expect("slice with incorrect length")
33*cf78ab8cSAndroid Build Coastguard Worker }
34*cf78ab8cSAndroid Build Coastguard Worker }
35*cf78ab8cSAndroid Build Coastguard Worker
36*cf78ab8cSAndroid Build Coastguard Worker // TODO: Add unit tests.
37*cf78ab8cSAndroid Build Coastguard Worker impl fmt::Display for MacAddress {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result38*cf78ab8cSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39*cf78ab8cSAndroid Build Coastguard Worker let bytes = u64::to_le_bytes(self.0);
40*cf78ab8cSAndroid Build Coastguard Worker write!(
41*cf78ab8cSAndroid Build Coastguard Worker f,
42*cf78ab8cSAndroid Build Coastguard Worker "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
43*cf78ab8cSAndroid Build Coastguard Worker bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
44*cf78ab8cSAndroid Build Coastguard Worker )
45*cf78ab8cSAndroid Build Coastguard Worker }
46*cf78ab8cSAndroid Build Coastguard Worker }
47*cf78ab8cSAndroid Build Coastguard Worker
48*cf78ab8cSAndroid Build Coastguard Worker impl fmt::Display for Ieee80211 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result49*cf78ab8cSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50*cf78ab8cSAndroid Build Coastguard Worker write!(
51*cf78ab8cSAndroid Build Coastguard Worker f,
52*cf78ab8cSAndroid Build Coastguard Worker "{{ds: {}, src: {}, dst: {}}}",
53*cf78ab8cSAndroid Build Coastguard Worker self.get_ds(),
54*cf78ab8cSAndroid Build Coastguard Worker self.get_source(),
55*cf78ab8cSAndroid Build Coastguard Worker self.get_destination()
56*cf78ab8cSAndroid Build Coastguard Worker )
57*cf78ab8cSAndroid Build Coastguard Worker }
58*cf78ab8cSAndroid Build Coastguard Worker }
59*cf78ab8cSAndroid Build Coastguard Worker
60*cf78ab8cSAndroid Build Coastguard Worker impl From<&[u8; 6]> for MacAddress {
from(bytes: &[u8; 6]) -> Self61*cf78ab8cSAndroid Build Coastguard Worker fn from(bytes: &[u8; 6]) -> Self {
62*cf78ab8cSAndroid Build Coastguard Worker Self(u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], 0, 0]))
63*cf78ab8cSAndroid Build Coastguard Worker }
64*cf78ab8cSAndroid Build Coastguard Worker }
65*cf78ab8cSAndroid Build Coastguard Worker
66*cf78ab8cSAndroid Build Coastguard Worker impl From<MacAddress> for [u8; 6] {
from(MacAddress(addr): MacAddress) -> Self67*cf78ab8cSAndroid Build Coastguard Worker fn from(MacAddress(addr): MacAddress) -> Self {
68*cf78ab8cSAndroid Build Coastguard Worker let bytes = u64::to_le_bytes(addr);
69*cf78ab8cSAndroid Build Coastguard Worker bytes[0..6].try_into().unwrap()
70*cf78ab8cSAndroid Build Coastguard Worker }
71*cf78ab8cSAndroid Build Coastguard Worker }
72*cf78ab8cSAndroid Build Coastguard Worker
73*cf78ab8cSAndroid Build Coastguard Worker impl MacAddress {
74*cf78ab8cSAndroid Build Coastguard Worker pub const LEN: usize = 6;
75*cf78ab8cSAndroid Build Coastguard Worker
is_multicast(&self) -> bool76*cf78ab8cSAndroid Build Coastguard Worker pub fn is_multicast(&self) -> bool {
77*cf78ab8cSAndroid Build Coastguard Worker let addr = u64::to_le_bytes(self.0);
78*cf78ab8cSAndroid Build Coastguard Worker (addr[0] & 0x1) == 1
79*cf78ab8cSAndroid Build Coastguard Worker }
80*cf78ab8cSAndroid Build Coastguard Worker
is_broadcast(&self) -> bool81*cf78ab8cSAndroid Build Coastguard Worker pub fn is_broadcast(&self) -> bool {
82*cf78ab8cSAndroid Build Coastguard Worker self.0 == u64::MAX
83*cf78ab8cSAndroid Build Coastguard Worker }
84*cf78ab8cSAndroid Build Coastguard Worker }
85*cf78ab8cSAndroid Build Coastguard Worker
86*cf78ab8cSAndroid Build Coastguard Worker struct Ieee8023<'a> {
87*cf78ab8cSAndroid Build Coastguard Worker destination: MacAddress,
88*cf78ab8cSAndroid Build Coastguard Worker source: MacAddress,
89*cf78ab8cSAndroid Build Coastguard Worker ethertype: EtherType,
90*cf78ab8cSAndroid Build Coastguard Worker payload: &'a [u8],
91*cf78ab8cSAndroid Build Coastguard Worker }
92*cf78ab8cSAndroid Build Coastguard Worker
93*cf78ab8cSAndroid Build Coastguard Worker impl<'a> Ieee8023<'a> {
94*cf78ab8cSAndroid Build Coastguard Worker pub const HDR_LEN: usize = 14;
95*cf78ab8cSAndroid Build Coastguard Worker
96*cf78ab8cSAndroid Build Coastguard Worker /// Creates an `Ieee8023` instance from packet slice.
from(packet: &'a [u8]) -> anyhow::Result<Self>97*cf78ab8cSAndroid Build Coastguard Worker fn from(packet: &'a [u8]) -> anyhow::Result<Self> {
98*cf78ab8cSAndroid Build Coastguard Worker // Ensure the packet has enough bytes for the header
99*cf78ab8cSAndroid Build Coastguard Worker anyhow::ensure!(
100*cf78ab8cSAndroid Build Coastguard Worker packet.len() >= Self::HDR_LEN,
101*cf78ab8cSAndroid Build Coastguard Worker "Packet (len: {}) too short for IEEE 802.3 header",
102*cf78ab8cSAndroid Build Coastguard Worker packet.len()
103*cf78ab8cSAndroid Build Coastguard Worker );
104*cf78ab8cSAndroid Build Coastguard Worker let dest_slice: &[u8; 6] = packet[..MacAddress::LEN].try_into()?;
105*cf78ab8cSAndroid Build Coastguard Worker let src_slice: &[u8; 6] = packet[MacAddress::LEN..2 * MacAddress::LEN].try_into()?;
106*cf78ab8cSAndroid Build Coastguard Worker let ethertype_bytes = packet[2 * MacAddress::LEN..Self::HDR_LEN].try_into()?;
107*cf78ab8cSAndroid Build Coastguard Worker let ethertype = EtherType::try_from(u16::from_be_bytes(ethertype_bytes))
108*cf78ab8cSAndroid Build Coastguard Worker .map_err(|e| anyhow::anyhow!("invalid EtherType: {e}"))?;
109*cf78ab8cSAndroid Build Coastguard Worker
110*cf78ab8cSAndroid Build Coastguard Worker Ok(Ieee8023 {
111*cf78ab8cSAndroid Build Coastguard Worker destination: MacAddress::from(dest_slice),
112*cf78ab8cSAndroid Build Coastguard Worker source: MacAddress::from(src_slice),
113*cf78ab8cSAndroid Build Coastguard Worker ethertype,
114*cf78ab8cSAndroid Build Coastguard Worker payload: &packet[Self::HDR_LEN..],
115*cf78ab8cSAndroid Build Coastguard Worker })
116*cf78ab8cSAndroid Build Coastguard Worker }
117*cf78ab8cSAndroid Build Coastguard Worker
to_vec(self) -> anyhow::Result<Vec<u8>>118*cf78ab8cSAndroid Build Coastguard Worker fn to_vec(self) -> anyhow::Result<Vec<u8>> {
119*cf78ab8cSAndroid Build Coastguard Worker // Build 802.3 frame
120*cf78ab8cSAndroid Build Coastguard Worker let mut ethernet_frame =
121*cf78ab8cSAndroid Build Coastguard Worker Vec::with_capacity(MacAddress::LEN * 2 + ETHERTYPE_LEN + self.payload.len());
122*cf78ab8cSAndroid Build Coastguard Worker
123*cf78ab8cSAndroid Build Coastguard Worker ethernet_frame.extend_from_slice(&self.destination.to_vec());
124*cf78ab8cSAndroid Build Coastguard Worker ethernet_frame.extend_from_slice(&self.source.to_vec());
125*cf78ab8cSAndroid Build Coastguard Worker // Add extracted EtherType
126*cf78ab8cSAndroid Build Coastguard Worker ethernet_frame.extend_from_slice(&u16::from(self.ethertype).to_be_bytes());
127*cf78ab8cSAndroid Build Coastguard Worker // Actually data is after 802.2 LLC/SNAP header
128*cf78ab8cSAndroid Build Coastguard Worker ethernet_frame.extend_from_slice(self.payload);
129*cf78ab8cSAndroid Build Coastguard Worker Ok(ethernet_frame)
130*cf78ab8cSAndroid Build Coastguard Worker }
131*cf78ab8cSAndroid Build Coastguard Worker }
132*cf78ab8cSAndroid Build Coastguard Worker
133*cf78ab8cSAndroid Build Coastguard Worker impl Ieee80211 {
134*cf78ab8cSAndroid Build Coastguard Worker // Create Ieee80211 from Ieee8023 frame.
from_ieee8023(packet: &[u8], bssid: MacAddress) -> anyhow::Result<Ieee80211>135*cf78ab8cSAndroid Build Coastguard Worker pub fn from_ieee8023(packet: &[u8], bssid: MacAddress) -> anyhow::Result<Ieee80211> {
136*cf78ab8cSAndroid Build Coastguard Worker let ieee8023 = Ieee8023::from(packet)?;
137*cf78ab8cSAndroid Build Coastguard Worker
138*cf78ab8cSAndroid Build Coastguard Worker let llc_snap_header = LlcSnapHeader {
139*cf78ab8cSAndroid Build Coastguard Worker dsap: LlcSap::Snap,
140*cf78ab8cSAndroid Build Coastguard Worker ssap: LlcSap::Snap,
141*cf78ab8cSAndroid Build Coastguard Worker ctrl: LlcCtrl::UiCmd,
142*cf78ab8cSAndroid Build Coastguard Worker oui: 0,
143*cf78ab8cSAndroid Build Coastguard Worker ethertype: ieee8023.ethertype,
144*cf78ab8cSAndroid Build Coastguard Worker };
145*cf78ab8cSAndroid Build Coastguard Worker // IEEE80211 payload: LLC/SNAP Header + IEEE8023 payload
146*cf78ab8cSAndroid Build Coastguard Worker let mut payload = Vec::with_capacity(LlcSnapHeader::LEN + ieee8023.payload.len());
147*cf78ab8cSAndroid Build Coastguard Worker llc_snap_header.encode(&mut payload)?;
148*cf78ab8cSAndroid Build Coastguard Worker payload.extend_from_slice(ieee8023.payload);
149*cf78ab8cSAndroid Build Coastguard Worker
150*cf78ab8cSAndroid Build Coastguard Worker Ok(Ieee80211FromAp {
151*cf78ab8cSAndroid Build Coastguard Worker duration_id: 0,
152*cf78ab8cSAndroid Build Coastguard Worker ftype: FrameType::Data,
153*cf78ab8cSAndroid Build Coastguard Worker more_data: 0,
154*cf78ab8cSAndroid Build Coastguard Worker more_frags: 0,
155*cf78ab8cSAndroid Build Coastguard Worker order: 0,
156*cf78ab8cSAndroid Build Coastguard Worker pm: 0,
157*cf78ab8cSAndroid Build Coastguard Worker protected: 0,
158*cf78ab8cSAndroid Build Coastguard Worker retry: 0,
159*cf78ab8cSAndroid Build Coastguard Worker stype: 0,
160*cf78ab8cSAndroid Build Coastguard Worker version: 0,
161*cf78ab8cSAndroid Build Coastguard Worker bssid,
162*cf78ab8cSAndroid Build Coastguard Worker source: ieee8023.source,
163*cf78ab8cSAndroid Build Coastguard Worker destination: ieee8023.destination,
164*cf78ab8cSAndroid Build Coastguard Worker seq_ctrl: 0,
165*cf78ab8cSAndroid Build Coastguard Worker payload,
166*cf78ab8cSAndroid Build Coastguard Worker }
167*cf78ab8cSAndroid Build Coastguard Worker .try_into()?)
168*cf78ab8cSAndroid Build Coastguard Worker }
169*cf78ab8cSAndroid Build Coastguard Worker
170*cf78ab8cSAndroid Build Coastguard Worker // Frame has addr4 field
has_a4(&self) -> bool171*cf78ab8cSAndroid Build Coastguard Worker pub fn has_a4(&self) -> bool {
172*cf78ab8cSAndroid Build Coastguard Worker self.to_ds == 1 || self.from_ds == 1
173*cf78ab8cSAndroid Build Coastguard Worker }
174*cf78ab8cSAndroid Build Coastguard Worker
is_to_ap(&self) -> bool175*cf78ab8cSAndroid Build Coastguard Worker pub fn is_to_ap(&self) -> bool {
176*cf78ab8cSAndroid Build Coastguard Worker self.to_ds == 1 && self.from_ds == 0
177*cf78ab8cSAndroid Build Coastguard Worker }
178*cf78ab8cSAndroid Build Coastguard Worker
179*cf78ab8cSAndroid Build Coastguard Worker // Frame type is management
is_mgmt(&self) -> bool180*cf78ab8cSAndroid Build Coastguard Worker pub fn is_mgmt(&self) -> bool {
181*cf78ab8cSAndroid Build Coastguard Worker self.ftype == FrameType::Mgmt
182*cf78ab8cSAndroid Build Coastguard Worker }
183*cf78ab8cSAndroid Build Coastguard Worker
184*cf78ab8cSAndroid Build Coastguard Worker // Frame is (management) beacon frame
is_beacon(&self) -> bool185*cf78ab8cSAndroid Build Coastguard Worker pub fn is_beacon(&self) -> bool {
186*cf78ab8cSAndroid Build Coastguard Worker self.ftype == FrameType::Mgmt && self.stype == (ManagementSubType::Beacon as u8)
187*cf78ab8cSAndroid Build Coastguard Worker }
188*cf78ab8cSAndroid Build Coastguard Worker
189*cf78ab8cSAndroid Build Coastguard Worker // Frame type is data
is_data(&self) -> bool190*cf78ab8cSAndroid Build Coastguard Worker pub fn is_data(&self) -> bool {
191*cf78ab8cSAndroid Build Coastguard Worker self.ftype == FrameType::Data
192*cf78ab8cSAndroid Build Coastguard Worker }
193*cf78ab8cSAndroid Build Coastguard Worker
194*cf78ab8cSAndroid Build Coastguard Worker // Frame is probe request
is_probe_req(&self) -> bool195*cf78ab8cSAndroid Build Coastguard Worker pub fn is_probe_req(&self) -> bool {
196*cf78ab8cSAndroid Build Coastguard Worker self.ftype == FrameType::Ctl && self.stype == (ManagementSubType::ProbeReq as u8)
197*cf78ab8cSAndroid Build Coastguard Worker }
198*cf78ab8cSAndroid Build Coastguard Worker
199*cf78ab8cSAndroid Build Coastguard Worker // Frame type is EAPoL
is_eapol(&self) -> anyhow::Result<bool>200*cf78ab8cSAndroid Build Coastguard Worker pub fn is_eapol(&self) -> anyhow::Result<bool> {
201*cf78ab8cSAndroid Build Coastguard Worker Ok(self.get_ethertype()? == EtherType::Eapol)
202*cf78ab8cSAndroid Build Coastguard Worker }
203*cf78ab8cSAndroid Build Coastguard Worker
get_ds(&self) -> String204*cf78ab8cSAndroid Build Coastguard Worker pub fn get_ds(&self) -> String {
205*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
206*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(hdr) => "ToAp",
207*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(hdr) => "FromAp",
208*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(hdr) => "Ibss",
209*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(hdr) => "Wds",
210*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("unexpected specialized header"),
211*cf78ab8cSAndroid Build Coastguard Worker }
212*cf78ab8cSAndroid Build Coastguard Worker .to_string()
213*cf78ab8cSAndroid Build Coastguard Worker }
214*cf78ab8cSAndroid Build Coastguard Worker
get_source(&self) -> MacAddress215*cf78ab8cSAndroid Build Coastguard Worker pub fn get_source(&self) -> MacAddress {
216*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
217*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(hdr) => hdr.source,
218*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(hdr) => hdr.source,
219*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(hdr) => hdr.source,
220*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(hdr) => hdr.source,
221*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("unexpected specialized header"),
222*cf78ab8cSAndroid Build Coastguard Worker }
223*cf78ab8cSAndroid Build Coastguard Worker }
224*cf78ab8cSAndroid Build Coastguard Worker
225*cf78ab8cSAndroid Build Coastguard Worker /// Ieee80211 packets have 3-4 addresses in different positions based
226*cf78ab8cSAndroid Build Coastguard Worker /// on the FromDS and ToDS flags. This function gets the destination
227*cf78ab8cSAndroid Build Coastguard Worker /// address depending on the FromDS+ToDS packet subtypes.
get_destination(&self) -> MacAddress228*cf78ab8cSAndroid Build Coastguard Worker pub fn get_destination(&self) -> MacAddress {
229*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
230*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(hdr) => hdr.destination,
231*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(hdr) => hdr.destination,
232*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(hdr) => hdr.destination,
233*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(hdr) => hdr.destination,
234*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("unexpected specialized header"),
235*cf78ab8cSAndroid Build Coastguard Worker }
236*cf78ab8cSAndroid Build Coastguard Worker }
237*cf78ab8cSAndroid Build Coastguard Worker
get_bssid(&self) -> Option<MacAddress>238*cf78ab8cSAndroid Build Coastguard Worker pub fn get_bssid(&self) -> Option<MacAddress> {
239*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
240*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(hdr) => Some(hdr.bssid),
241*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(hdr) => Some(hdr.bssid),
242*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(hdr) => Some(hdr.bssid),
243*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(hdr) => None,
244*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("unexpected specialized header"),
245*cf78ab8cSAndroid Build Coastguard Worker }
246*cf78ab8cSAndroid Build Coastguard Worker }
247*cf78ab8cSAndroid Build Coastguard Worker
get_addr1(&self) -> MacAddress248*cf78ab8cSAndroid Build Coastguard Worker pub fn get_addr1(&self) -> MacAddress {
249*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
250*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(hdr) => hdr.bssid,
251*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(hdr) => hdr.destination,
252*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(hdr) => hdr.destination,
253*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(hdr) => hdr.receiver,
254*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("unexpected specialized header"),
255*cf78ab8cSAndroid Build Coastguard Worker }
256*cf78ab8cSAndroid Build Coastguard Worker }
257*cf78ab8cSAndroid Build Coastguard Worker
get_ssid_from_beacon_frame(&self) -> anyhow::Result<String>258*cf78ab8cSAndroid Build Coastguard Worker pub fn get_ssid_from_beacon_frame(&self) -> anyhow::Result<String> {
259*cf78ab8cSAndroid Build Coastguard Worker // Verify packet is a beacon frame
260*cf78ab8cSAndroid Build Coastguard Worker if !self.is_beacon() {
261*cf78ab8cSAndroid Build Coastguard Worker return Err(anyhow!("Frame is not beacon frame."));
262*cf78ab8cSAndroid Build Coastguard Worker };
263*cf78ab8cSAndroid Build Coastguard Worker
264*cf78ab8cSAndroid Build Coastguard Worker // SSID field starts after the first 36 bytes. Ieee80211 payload starts after 4 bytes.
265*cf78ab8cSAndroid Build Coastguard Worker let pos = 36 - 4;
266*cf78ab8cSAndroid Build Coastguard Worker
267*cf78ab8cSAndroid Build Coastguard Worker // Check for SSID element ID (0) and extract the SSID
268*cf78ab8cSAndroid Build Coastguard Worker let payload = &self.payload;
269*cf78ab8cSAndroid Build Coastguard Worker if payload[pos] == 0 {
270*cf78ab8cSAndroid Build Coastguard Worker let ssid_len = payload[pos + 1] as usize;
271*cf78ab8cSAndroid Build Coastguard Worker let ssid_bytes = &payload[pos + 2..pos + 2 + ssid_len];
272*cf78ab8cSAndroid Build Coastguard Worker return Ok(String::from_utf8(ssid_bytes.to_vec())?);
273*cf78ab8cSAndroid Build Coastguard Worker }
274*cf78ab8cSAndroid Build Coastguard Worker
275*cf78ab8cSAndroid Build Coastguard Worker Err(anyhow!("SSID not found."))
276*cf78ab8cSAndroid Build Coastguard Worker }
277*cf78ab8cSAndroid Build Coastguard Worker
get_payload(&self) -> Vec<u8>278*cf78ab8cSAndroid Build Coastguard Worker fn get_payload(&self) -> Vec<u8> {
279*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
280*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(hdr) => hdr.payload,
281*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(hdr) => hdr.payload,
282*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(hdr) => hdr.payload,
283*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(hdr) => hdr.payload,
284*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("unexpected specialized header"),
285*cf78ab8cSAndroid Build Coastguard Worker }
286*cf78ab8cSAndroid Build Coastguard Worker }
287*cf78ab8cSAndroid Build Coastguard Worker
get_ethertype(&self) -> anyhow::Result<EtherType>288*cf78ab8cSAndroid Build Coastguard Worker fn get_ethertype(&self) -> anyhow::Result<EtherType> {
289*cf78ab8cSAndroid Build Coastguard Worker if !self.is_data() {
290*cf78ab8cSAndroid Build Coastguard Worker return Err(anyhow!("Not an 802.2 LLC/SNAP frame"));
291*cf78ab8cSAndroid Build Coastguard Worker }
292*cf78ab8cSAndroid Build Coastguard Worker
293*cf78ab8cSAndroid Build Coastguard Worker // Extract and validate LLC/SNAP header
294*cf78ab8cSAndroid Build Coastguard Worker let payload = self.get_payload();
295*cf78ab8cSAndroid Build Coastguard Worker if payload.len() < LlcSnapHeader::LEN {
296*cf78ab8cSAndroid Build Coastguard Worker return Err(anyhow!("Payload too short for LLC/SNAP header"));
297*cf78ab8cSAndroid Build Coastguard Worker }
298*cf78ab8cSAndroid Build Coastguard Worker let llc_snap_header = LlcSnapHeader::decode_full(&payload[..LlcSnapHeader::LEN])?;
299*cf78ab8cSAndroid Build Coastguard Worker Ok(llc_snap_header.ethertype())
300*cf78ab8cSAndroid Build Coastguard Worker }
301*cf78ab8cSAndroid Build Coastguard Worker
with_address( &self, source: Option<MacAddress>, destination: Option<MacAddress>, ) -> Ieee80211302*cf78ab8cSAndroid Build Coastguard Worker pub fn with_address(
303*cf78ab8cSAndroid Build Coastguard Worker &self,
304*cf78ab8cSAndroid Build Coastguard Worker source: Option<MacAddress>,
305*cf78ab8cSAndroid Build Coastguard Worker destination: Option<MacAddress>,
306*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211 {
307*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
308*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(frame) => {
309*cf78ab8cSAndroid Build Coastguard Worker frame.with_address(source, destination).try_into().unwrap()
310*cf78ab8cSAndroid Build Coastguard Worker }
311*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211FromAp(frame) => {
312*cf78ab8cSAndroid Build Coastguard Worker frame.with_address(source, destination).try_into().unwrap()
313*cf78ab8cSAndroid Build Coastguard Worker }
314*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Ibss(frame) => {
315*cf78ab8cSAndroid Build Coastguard Worker frame.with_address(source, destination).try_into().unwrap()
316*cf78ab8cSAndroid Build Coastguard Worker }
317*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211Wds(frame) => {
318*cf78ab8cSAndroid Build Coastguard Worker frame.with_address(source, destination).try_into().unwrap()
319*cf78ab8cSAndroid Build Coastguard Worker }
320*cf78ab8cSAndroid Build Coastguard Worker _ => panic!("Unknown Ieee80211Child type"),
321*cf78ab8cSAndroid Build Coastguard Worker }
322*cf78ab8cSAndroid Build Coastguard Worker }
323*cf78ab8cSAndroid Build Coastguard Worker
324*cf78ab8cSAndroid Build Coastguard Worker /// Covert Ieee80211ToAp to Ieee80211FromAp packet.
into_from_ap(&self) -> anyhow::Result<Ieee80211FromAp>325*cf78ab8cSAndroid Build Coastguard Worker pub fn into_from_ap(&self) -> anyhow::Result<Ieee80211FromAp> {
326*cf78ab8cSAndroid Build Coastguard Worker match self.specialize().unwrap() {
327*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Child::Ieee80211ToAp(frame_to_ap) => {
328*cf78ab8cSAndroid Build Coastguard Worker // Flip from_ap and to_ap bits.
329*cf78ab8cSAndroid Build Coastguard Worker // TODO: Investigate if there is a way to copy frame_control flags at once.
330*cf78ab8cSAndroid Build Coastguard Worker // The header struct only has 7 fields, not 15. Most fields come from le16 frame_control.
331*cf78ab8cSAndroid Build Coastguard Worker Ok(Ieee80211FromAp {
332*cf78ab8cSAndroid Build Coastguard Worker duration_id: frame_to_ap.duration_id,
333*cf78ab8cSAndroid Build Coastguard Worker ftype: frame_to_ap.ftype,
334*cf78ab8cSAndroid Build Coastguard Worker more_data: frame_to_ap.more_data,
335*cf78ab8cSAndroid Build Coastguard Worker more_frags: frame_to_ap.more_frags,
336*cf78ab8cSAndroid Build Coastguard Worker order: frame_to_ap.order,
337*cf78ab8cSAndroid Build Coastguard Worker pm: frame_to_ap.pm,
338*cf78ab8cSAndroid Build Coastguard Worker protected: frame_to_ap.protected,
339*cf78ab8cSAndroid Build Coastguard Worker retry: frame_to_ap.retry,
340*cf78ab8cSAndroid Build Coastguard Worker stype: frame_to_ap.stype,
341*cf78ab8cSAndroid Build Coastguard Worker version: frame_to_ap.version,
342*cf78ab8cSAndroid Build Coastguard Worker bssid: frame_to_ap.bssid,
343*cf78ab8cSAndroid Build Coastguard Worker source: frame_to_ap.source,
344*cf78ab8cSAndroid Build Coastguard Worker destination: frame_to_ap.destination,
345*cf78ab8cSAndroid Build Coastguard Worker seq_ctrl: frame_to_ap.seq_ctrl,
346*cf78ab8cSAndroid Build Coastguard Worker payload: frame_to_ap.payload.to_vec(),
347*cf78ab8cSAndroid Build Coastguard Worker })
348*cf78ab8cSAndroid Build Coastguard Worker }
349*cf78ab8cSAndroid Build Coastguard Worker _ => Err(anyhow!(
350*cf78ab8cSAndroid Build Coastguard Worker "Invalid Ieee80211Child packet. from_ds: {}, to_ds: {}",
351*cf78ab8cSAndroid Build Coastguard Worker self.from_ds,
352*cf78ab8cSAndroid Build Coastguard Worker self.to_ds
353*cf78ab8cSAndroid Build Coastguard Worker )),
354*cf78ab8cSAndroid Build Coastguard Worker }
355*cf78ab8cSAndroid Build Coastguard Worker }
356*cf78ab8cSAndroid Build Coastguard Worker
357*cf78ab8cSAndroid Build Coastguard Worker // Convert to ieee802.3
to_ieee8023(&self) -> anyhow::Result<Vec<u8>>358*cf78ab8cSAndroid Build Coastguard Worker pub fn to_ieee8023(&self) -> anyhow::Result<Vec<u8>> {
359*cf78ab8cSAndroid Build Coastguard Worker let ethertype = self.get_ethertype()?;
360*cf78ab8cSAndroid Build Coastguard Worker let payload = self.get_payload();
361*cf78ab8cSAndroid Build Coastguard Worker Ieee8023 {
362*cf78ab8cSAndroid Build Coastguard Worker destination: self.get_destination(),
363*cf78ab8cSAndroid Build Coastguard Worker source: self.get_source(),
364*cf78ab8cSAndroid Build Coastguard Worker ethertype,
365*cf78ab8cSAndroid Build Coastguard Worker payload: &payload[LlcSnapHeader::LEN..],
366*cf78ab8cSAndroid Build Coastguard Worker }
367*cf78ab8cSAndroid Build Coastguard Worker .to_vec()
368*cf78ab8cSAndroid Build Coastguard Worker }
369*cf78ab8cSAndroid Build Coastguard Worker }
370*cf78ab8cSAndroid Build Coastguard Worker
371*cf78ab8cSAndroid Build Coastguard Worker impl Ieee80211FromAp {
with_address( &self, source: Option<MacAddress>, destination: Option<MacAddress>, ) -> Ieee80211FromAp372*cf78ab8cSAndroid Build Coastguard Worker pub fn with_address(
373*cf78ab8cSAndroid Build Coastguard Worker &self,
374*cf78ab8cSAndroid Build Coastguard Worker source: Option<MacAddress>,
375*cf78ab8cSAndroid Build Coastguard Worker destination: Option<MacAddress>,
376*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211FromAp {
377*cf78ab8cSAndroid Build Coastguard Worker Ieee80211FromAp {
378*cf78ab8cSAndroid Build Coastguard Worker source: source.unwrap_or(self.source),
379*cf78ab8cSAndroid Build Coastguard Worker destination: destination.unwrap_or(self.destination),
380*cf78ab8cSAndroid Build Coastguard Worker ..self.clone()
381*cf78ab8cSAndroid Build Coastguard Worker }
382*cf78ab8cSAndroid Build Coastguard Worker }
383*cf78ab8cSAndroid Build Coastguard Worker }
384*cf78ab8cSAndroid Build Coastguard Worker
385*cf78ab8cSAndroid Build Coastguard Worker impl Ieee80211ToAp {
with_address( &self, source: Option<MacAddress>, destination: Option<MacAddress>, ) -> Ieee80211ToAp386*cf78ab8cSAndroid Build Coastguard Worker pub fn with_address(
387*cf78ab8cSAndroid Build Coastguard Worker &self,
388*cf78ab8cSAndroid Build Coastguard Worker source: Option<MacAddress>,
389*cf78ab8cSAndroid Build Coastguard Worker destination: Option<MacAddress>,
390*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211ToAp {
391*cf78ab8cSAndroid Build Coastguard Worker Ieee80211ToAp {
392*cf78ab8cSAndroid Build Coastguard Worker source: source.unwrap_or(self.source),
393*cf78ab8cSAndroid Build Coastguard Worker destination: destination.unwrap_or(self.destination),
394*cf78ab8cSAndroid Build Coastguard Worker ..self.clone()
395*cf78ab8cSAndroid Build Coastguard Worker }
396*cf78ab8cSAndroid Build Coastguard Worker }
397*cf78ab8cSAndroid Build Coastguard Worker }
398*cf78ab8cSAndroid Build Coastguard Worker
399*cf78ab8cSAndroid Build Coastguard Worker impl Ieee80211Ibss {
with_address( &self, source: Option<MacAddress>, destination: Option<MacAddress>, ) -> Ieee80211Ibss400*cf78ab8cSAndroid Build Coastguard Worker pub fn with_address(
401*cf78ab8cSAndroid Build Coastguard Worker &self,
402*cf78ab8cSAndroid Build Coastguard Worker source: Option<MacAddress>,
403*cf78ab8cSAndroid Build Coastguard Worker destination: Option<MacAddress>,
404*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211Ibss {
405*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Ibss {
406*cf78ab8cSAndroid Build Coastguard Worker source: source.unwrap_or(self.source),
407*cf78ab8cSAndroid Build Coastguard Worker destination: destination.unwrap_or(self.destination),
408*cf78ab8cSAndroid Build Coastguard Worker ..self.clone()
409*cf78ab8cSAndroid Build Coastguard Worker }
410*cf78ab8cSAndroid Build Coastguard Worker }
411*cf78ab8cSAndroid Build Coastguard Worker }
412*cf78ab8cSAndroid Build Coastguard Worker
413*cf78ab8cSAndroid Build Coastguard Worker impl Ieee80211Wds {
with_address( &self, source: Option<MacAddress>, destination: Option<MacAddress>, ) -> Ieee80211Wds414*cf78ab8cSAndroid Build Coastguard Worker pub fn with_address(
415*cf78ab8cSAndroid Build Coastguard Worker &self,
416*cf78ab8cSAndroid Build Coastguard Worker source: Option<MacAddress>,
417*cf78ab8cSAndroid Build Coastguard Worker destination: Option<MacAddress>,
418*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211Wds {
419*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Wds {
420*cf78ab8cSAndroid Build Coastguard Worker source: source.unwrap_or(self.source),
421*cf78ab8cSAndroid Build Coastguard Worker destination: destination.unwrap_or(self.destination),
422*cf78ab8cSAndroid Build Coastguard Worker ..self.clone()
423*cf78ab8cSAndroid Build Coastguard Worker }
424*cf78ab8cSAndroid Build Coastguard Worker }
425*cf78ab8cSAndroid Build Coastguard Worker }
426*cf78ab8cSAndroid Build Coastguard Worker
parse_mac_address(s: &str) -> Option<MacAddress>427*cf78ab8cSAndroid Build Coastguard Worker pub fn parse_mac_address(s: &str) -> Option<MacAddress> {
428*cf78ab8cSAndroid Build Coastguard Worker let parts: Vec<&str> = s.split(':').collect();
429*cf78ab8cSAndroid Build Coastguard Worker if parts.len() != 6 {
430*cf78ab8cSAndroid Build Coastguard Worker return None;
431*cf78ab8cSAndroid Build Coastguard Worker }
432*cf78ab8cSAndroid Build Coastguard Worker let mut bytes = [0u8; 6];
433*cf78ab8cSAndroid Build Coastguard Worker for (i, part) in parts.iter().enumerate() {
434*cf78ab8cSAndroid Build Coastguard Worker match u8::from_str_radix(part, 16) {
435*cf78ab8cSAndroid Build Coastguard Worker Ok(n) => bytes[i] = n,
436*cf78ab8cSAndroid Build Coastguard Worker Err(e) => return None,
437*cf78ab8cSAndroid Build Coastguard Worker }
438*cf78ab8cSAndroid Build Coastguard Worker }
439*cf78ab8cSAndroid Build Coastguard Worker Some(MacAddress::from(&bytes))
440*cf78ab8cSAndroid Build Coastguard Worker }
441*cf78ab8cSAndroid Build Coastguard Worker
442*cf78ab8cSAndroid Build Coastguard Worker #[cfg(test)]
443*cf78ab8cSAndroid Build Coastguard Worker mod tests {
444*cf78ab8cSAndroid Build Coastguard Worker use super::*;
445*cf78ab8cSAndroid Build Coastguard Worker
446*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_mac_address_len()447*cf78ab8cSAndroid Build Coastguard Worker fn test_mac_address_len() {
448*cf78ab8cSAndroid Build Coastguard Worker let mac_address: MacAddress = parse_mac_address("00:0b:85:71:20:ce").unwrap();
449*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(mac_address.encoded_len(), MacAddress::LEN);
450*cf78ab8cSAndroid Build Coastguard Worker }
451*cf78ab8cSAndroid Build Coastguard Worker
452*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_mac_address_to_vec()453*cf78ab8cSAndroid Build Coastguard Worker fn test_mac_address_to_vec() {
454*cf78ab8cSAndroid Build Coastguard Worker let mac_address: MacAddress = parse_mac_address("00:0b:85:71:20:ce").unwrap();
455*cf78ab8cSAndroid Build Coastguard Worker let mac_address_bytes = mac_address.to_vec();
456*cf78ab8cSAndroid Build Coastguard Worker let reconstructed_mac_address = MacAddress::from(&mac_address_bytes);
457*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(mac_address, reconstructed_mac_address);
458*cf78ab8cSAndroid Build Coastguard Worker }
459*cf78ab8cSAndroid Build Coastguard Worker
460*cf78ab8cSAndroid Build Coastguard Worker // These tests use the packets available here
461*cf78ab8cSAndroid Build Coastguard Worker // https://community.cisco.com/t5/wireless-mobility-knowledge-base/802-11-frames-a-starter-guide-to-learn-wireless-sniffer-traces/ta-p/3110019
462*cf78ab8cSAndroid Build Coastguard Worker
463*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_frame_qos()464*cf78ab8cSAndroid Build Coastguard Worker fn test_frame_qos() {
465*cf78ab8cSAndroid Build Coastguard Worker let frame: Vec<u8> = vec![
466*cf78ab8cSAndroid Build Coastguard Worker 0x88, 0x02, 0x2c, 0x00, 0x00, 0x13, 0xe8, 0xeb, 0xd6, 0x03, 0x00, 0x0b, 0x85, 0x71,
467*cf78ab8cSAndroid Build Coastguard Worker 0x20, 0xce, 0x00, 0x0b, 0x85, 0x71, 0x20, 0xce, 0x00, 0x26, 0x00, 0x00,
468*cf78ab8cSAndroid Build Coastguard Worker ];
469*cf78ab8cSAndroid Build Coastguard Worker let hdr = Ieee80211::decode_full(&frame).unwrap();
470*cf78ab8cSAndroid Build Coastguard Worker assert!(hdr.is_data());
471*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(hdr.stype, DataSubType::Qos as u8);
472*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(hdr.from_ds, 1);
473*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(hdr.to_ds, 0);
474*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(hdr.duration_id, 44);
475*cf78ab8cSAndroid Build Coastguard Worker // Source address: Cisco_71:20:ce (00:0b:85:71:20:ce)
476*cf78ab8cSAndroid Build Coastguard Worker let a = format!("{}", hdr.get_source());
477*cf78ab8cSAndroid Build Coastguard Worker let b = format!("{}", parse_mac_address("00:0b:85:71:20:ce").unwrap());
478*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(a, b);
479*cf78ab8cSAndroid Build Coastguard Worker }
480*cf78ab8cSAndroid Build Coastguard Worker
481*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_beacon_frame()482*cf78ab8cSAndroid Build Coastguard Worker fn test_beacon_frame() {
483*cf78ab8cSAndroid Build Coastguard Worker // Example from actual beacon frame from Hostapd with "AndroidWifi" SSID
484*cf78ab8cSAndroid Build Coastguard Worker let frame: Vec<u8> = vec![
485*cf78ab8cSAndroid Build Coastguard Worker 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x13, 0x10, 0x85,
486*cf78ab8cSAndroid Build Coastguard Worker 0xfe, 0x01, 0x00, 0x13, 0x10, 0x85, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487*cf78ab8cSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x01, 0x04, 0x00, 0x0b, 0x41, 0x6e, 0x64, 0x72,
488*cf78ab8cSAndroid Build Coastguard Worker 0x6f, 0x69, 0x64, 0x57, 0x69, 0x66, 0x69, 0x01, 0x04, 0x82, 0x84, 0x8b, 0x96, 0x03,
489*cf78ab8cSAndroid Build Coastguard Worker 0x01, 0x08, 0x2a, 0x01, 0x07, 0x2d, 0x1a, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490*cf78ab8cSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491*cf78ab8cSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492*cf78ab8cSAndroid Build Coastguard Worker 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493*cf78ab8cSAndroid Build Coastguard Worker 0x00, 0x7f, 0x04, 0x00, 0x00, 0x00, 0x02,
494*cf78ab8cSAndroid Build Coastguard Worker ];
495*cf78ab8cSAndroid Build Coastguard Worker let decoded_frame = Ieee80211::decode_full(&frame).unwrap();
496*cf78ab8cSAndroid Build Coastguard Worker assert!(decoded_frame.is_mgmt());
497*cf78ab8cSAndroid Build Coastguard Worker assert!(decoded_frame.is_beacon());
498*cf78ab8cSAndroid Build Coastguard Worker let ssid = decoded_frame.get_ssid_from_beacon_frame();
499*cf78ab8cSAndroid Build Coastguard Worker assert!(ssid.is_ok());
500*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ssid.unwrap(), "AndroidWifi");
501*cf78ab8cSAndroid Build Coastguard Worker }
502*cf78ab8cSAndroid Build Coastguard Worker
503*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_is_multicast()504*cf78ab8cSAndroid Build Coastguard Worker fn test_is_multicast() {
505*cf78ab8cSAndroid Build Coastguard Worker // Multicast MAC address: 01:00:5E:00:00:FB
506*cf78ab8cSAndroid Build Coastguard Worker let mdns_mac_address = parse_mac_address("01:00:5e:00:00:fb").unwrap();
507*cf78ab8cSAndroid Build Coastguard Worker assert!(mdns_mac_address.is_multicast());
508*cf78ab8cSAndroid Build Coastguard Worker // Broadcast MAC address: ff:ff:ff:ff:ff:ff
509*cf78ab8cSAndroid Build Coastguard Worker let broadcast_mac_address = parse_mac_address("ff:ff:ff:ff:ff:ff").unwrap();
510*cf78ab8cSAndroid Build Coastguard Worker assert!(broadcast_mac_address.is_multicast());
511*cf78ab8cSAndroid Build Coastguard Worker // Source address: Cisco_71:20:ce (00:0b:85:71:20:ce)
512*cf78ab8cSAndroid Build Coastguard Worker let non_mdns_mac_address = parse_mac_address("00:0b:85:71:20:ce").unwrap();
513*cf78ab8cSAndroid Build Coastguard Worker assert!(!non_mdns_mac_address.is_multicast());
514*cf78ab8cSAndroid Build Coastguard Worker }
515*cf78ab8cSAndroid Build Coastguard Worker
test_is_broadcast()516*cf78ab8cSAndroid Build Coastguard Worker fn test_is_broadcast() {
517*cf78ab8cSAndroid Build Coastguard Worker // Multicast MAC address: 01:00:5E:00:00:FB
518*cf78ab8cSAndroid Build Coastguard Worker let mdns_mac_address = parse_mac_address("01:00:5e:00:00:fb").unwrap();
519*cf78ab8cSAndroid Build Coastguard Worker assert!(!mdns_mac_address.is_broadcast());
520*cf78ab8cSAndroid Build Coastguard Worker // Broadcast MAC address: ff:ff:ff:ff:ff:ff
521*cf78ab8cSAndroid Build Coastguard Worker let broadcast_mac_address = parse_mac_address("ff:ff:ff:ff:ff:ff").unwrap();
522*cf78ab8cSAndroid Build Coastguard Worker assert!(broadcast_mac_address.is_broadcast());
523*cf78ab8cSAndroid Build Coastguard Worker // Source address: Cisco_71:20:ce (00:0b:85:71:20:ce)
524*cf78ab8cSAndroid Build Coastguard Worker let non_mdns_mac_address = parse_mac_address("00:0b:85:71:20:ce").unwrap();
525*cf78ab8cSAndroid Build Coastguard Worker assert!(!non_mdns_mac_address.is_broadcast());
526*cf78ab8cSAndroid Build Coastguard Worker }
527*cf78ab8cSAndroid Build Coastguard Worker
528*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_ieee8023_from_valid_packet()529*cf78ab8cSAndroid Build Coastguard Worker fn test_ieee8023_from_valid_packet() {
530*cf78ab8cSAndroid Build Coastguard Worker let packet: [u8; 20] = [
531*cf78ab8cSAndroid Build Coastguard Worker 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // Destination MAC
532*cf78ab8cSAndroid Build Coastguard Worker 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, // Source MAC
533*cf78ab8cSAndroid Build Coastguard Worker 0x08, 0x00, // EtherType (IPv4)
534*cf78ab8cSAndroid Build Coastguard Worker 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, // Data
535*cf78ab8cSAndroid Build Coastguard Worker ];
536*cf78ab8cSAndroid Build Coastguard Worker
537*cf78ab8cSAndroid Build Coastguard Worker let result = Ieee8023::from(&packet);
538*cf78ab8cSAndroid Build Coastguard Worker assert!(result.is_ok());
539*cf78ab8cSAndroid Build Coastguard Worker
540*cf78ab8cSAndroid Build Coastguard Worker let ieee8023 = result.unwrap();
541*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ieee8023.destination.to_vec(), [0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
542*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ieee8023.source.to_vec(), [0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB]);
543*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ieee8023.ethertype, EtherType::IPv4);
544*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ieee8023.payload, &[0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11]);
545*cf78ab8cSAndroid Build Coastguard Worker }
546*cf78ab8cSAndroid Build Coastguard Worker
547*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_ieee8023_from_short_packet()548*cf78ab8cSAndroid Build Coastguard Worker fn test_ieee8023_from_short_packet() {
549*cf78ab8cSAndroid Build Coastguard Worker let packet: [u8; 10] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99];
550*cf78ab8cSAndroid Build Coastguard Worker
551*cf78ab8cSAndroid Build Coastguard Worker let result = Ieee8023::from(&packet);
552*cf78ab8cSAndroid Build Coastguard Worker assert!(result.is_err());
553*cf78ab8cSAndroid Build Coastguard Worker }
554*cf78ab8cSAndroid Build Coastguard Worker
create_test_from_ap_ieee80211( source: MacAddress, destination: MacAddress, bssid: MacAddress, ) -> Ieee80211555*cf78ab8cSAndroid Build Coastguard Worker fn create_test_from_ap_ieee80211(
556*cf78ab8cSAndroid Build Coastguard Worker source: MacAddress,
557*cf78ab8cSAndroid Build Coastguard Worker destination: MacAddress,
558*cf78ab8cSAndroid Build Coastguard Worker bssid: MacAddress,
559*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211 {
560*cf78ab8cSAndroid Build Coastguard Worker Ieee80211FromAp {
561*cf78ab8cSAndroid Build Coastguard Worker duration_id: 0,
562*cf78ab8cSAndroid Build Coastguard Worker ftype: FrameType::Mgmt,
563*cf78ab8cSAndroid Build Coastguard Worker more_data: 0,
564*cf78ab8cSAndroid Build Coastguard Worker more_frags: 0,
565*cf78ab8cSAndroid Build Coastguard Worker order: 0,
566*cf78ab8cSAndroid Build Coastguard Worker pm: 0,
567*cf78ab8cSAndroid Build Coastguard Worker protected: 0,
568*cf78ab8cSAndroid Build Coastguard Worker retry: 0,
569*cf78ab8cSAndroid Build Coastguard Worker stype: 0,
570*cf78ab8cSAndroid Build Coastguard Worker version: 0,
571*cf78ab8cSAndroid Build Coastguard Worker bssid,
572*cf78ab8cSAndroid Build Coastguard Worker source,
573*cf78ab8cSAndroid Build Coastguard Worker destination,
574*cf78ab8cSAndroid Build Coastguard Worker seq_ctrl: 0,
575*cf78ab8cSAndroid Build Coastguard Worker payload: Vec::new(),
576*cf78ab8cSAndroid Build Coastguard Worker }
577*cf78ab8cSAndroid Build Coastguard Worker .try_into()
578*cf78ab8cSAndroid Build Coastguard Worker .unwrap()
579*cf78ab8cSAndroid Build Coastguard Worker }
580*cf78ab8cSAndroid Build Coastguard Worker
create_test_ibss_ieee80211( source: MacAddress, destination: MacAddress, bssid: MacAddress, ) -> Ieee80211581*cf78ab8cSAndroid Build Coastguard Worker fn create_test_ibss_ieee80211(
582*cf78ab8cSAndroid Build Coastguard Worker source: MacAddress,
583*cf78ab8cSAndroid Build Coastguard Worker destination: MacAddress,
584*cf78ab8cSAndroid Build Coastguard Worker bssid: MacAddress,
585*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211 {
586*cf78ab8cSAndroid Build Coastguard Worker Ieee80211Ibss {
587*cf78ab8cSAndroid Build Coastguard Worker duration_id: 0,
588*cf78ab8cSAndroid Build Coastguard Worker ftype: FrameType::Mgmt,
589*cf78ab8cSAndroid Build Coastguard Worker more_data: 0,
590*cf78ab8cSAndroid Build Coastguard Worker more_frags: 0,
591*cf78ab8cSAndroid Build Coastguard Worker order: 0,
592*cf78ab8cSAndroid Build Coastguard Worker pm: 0,
593*cf78ab8cSAndroid Build Coastguard Worker protected: 0,
594*cf78ab8cSAndroid Build Coastguard Worker retry: 0,
595*cf78ab8cSAndroid Build Coastguard Worker stype: 0,
596*cf78ab8cSAndroid Build Coastguard Worker version: 0,
597*cf78ab8cSAndroid Build Coastguard Worker bssid,
598*cf78ab8cSAndroid Build Coastguard Worker source,
599*cf78ab8cSAndroid Build Coastguard Worker destination,
600*cf78ab8cSAndroid Build Coastguard Worker seq_ctrl: 0,
601*cf78ab8cSAndroid Build Coastguard Worker payload: Vec::new(),
602*cf78ab8cSAndroid Build Coastguard Worker }
603*cf78ab8cSAndroid Build Coastguard Worker .try_into()
604*cf78ab8cSAndroid Build Coastguard Worker .unwrap()
605*cf78ab8cSAndroid Build Coastguard Worker }
606*cf78ab8cSAndroid Build Coastguard Worker
create_test_to_ap_ieee80211( source: MacAddress, destination: MacAddress, bssid: MacAddress, ) -> Ieee80211607*cf78ab8cSAndroid Build Coastguard Worker fn create_test_to_ap_ieee80211(
608*cf78ab8cSAndroid Build Coastguard Worker source: MacAddress,
609*cf78ab8cSAndroid Build Coastguard Worker destination: MacAddress,
610*cf78ab8cSAndroid Build Coastguard Worker bssid: MacAddress,
611*cf78ab8cSAndroid Build Coastguard Worker ) -> Ieee80211 {
612*cf78ab8cSAndroid Build Coastguard Worker Ieee80211ToAp {
613*cf78ab8cSAndroid Build Coastguard Worker duration_id: 0,
614*cf78ab8cSAndroid Build Coastguard Worker ftype: FrameType::Mgmt,
615*cf78ab8cSAndroid Build Coastguard Worker more_data: 0,
616*cf78ab8cSAndroid Build Coastguard Worker more_frags: 0,
617*cf78ab8cSAndroid Build Coastguard Worker order: 0,
618*cf78ab8cSAndroid Build Coastguard Worker pm: 0,
619*cf78ab8cSAndroid Build Coastguard Worker protected: 0,
620*cf78ab8cSAndroid Build Coastguard Worker retry: 0,
621*cf78ab8cSAndroid Build Coastguard Worker stype: 0,
622*cf78ab8cSAndroid Build Coastguard Worker version: 0,
623*cf78ab8cSAndroid Build Coastguard Worker bssid,
624*cf78ab8cSAndroid Build Coastguard Worker source,
625*cf78ab8cSAndroid Build Coastguard Worker destination,
626*cf78ab8cSAndroid Build Coastguard Worker seq_ctrl: 0,
627*cf78ab8cSAndroid Build Coastguard Worker payload: Vec::new(),
628*cf78ab8cSAndroid Build Coastguard Worker }
629*cf78ab8cSAndroid Build Coastguard Worker .try_into()
630*cf78ab8cSAndroid Build Coastguard Worker .unwrap()
631*cf78ab8cSAndroid Build Coastguard Worker }
632*cf78ab8cSAndroid Build Coastguard Worker
test_with_address( create_test_ieee80211: fn(MacAddress, MacAddress, MacAddress) -> Ieee80211, )633*cf78ab8cSAndroid Build Coastguard Worker fn test_with_address(
634*cf78ab8cSAndroid Build Coastguard Worker create_test_ieee80211: fn(MacAddress, MacAddress, MacAddress) -> Ieee80211,
635*cf78ab8cSAndroid Build Coastguard Worker ) {
636*cf78ab8cSAndroid Build Coastguard Worker let source = parse_mac_address("01:02:03:00:00:01").unwrap();
637*cf78ab8cSAndroid Build Coastguard Worker let destination = parse_mac_address("01:02:03:00:00:02").unwrap();
638*cf78ab8cSAndroid Build Coastguard Worker let bssid = parse_mac_address("00:13:10:85:fe:01").unwrap();
639*cf78ab8cSAndroid Build Coastguard Worker let ieee80211 = create_test_ieee80211(source, destination, bssid);
640*cf78ab8cSAndroid Build Coastguard Worker
641*cf78ab8cSAndroid Build Coastguard Worker let new_source = parse_mac_address("01:02:03:00:00:03").unwrap();
642*cf78ab8cSAndroid Build Coastguard Worker let new_destination = parse_mac_address("01:02:03:00:00:04").unwrap();
643*cf78ab8cSAndroid Build Coastguard Worker
644*cf78ab8cSAndroid Build Coastguard Worker let new_ieee80211 = ieee80211.with_address(Some(new_source), Some(new_destination));
645*cf78ab8cSAndroid Build Coastguard Worker assert!(new_ieee80211.get_source() == new_source);
646*cf78ab8cSAndroid Build Coastguard Worker assert!(new_ieee80211.get_destination() == new_destination);
647*cf78ab8cSAndroid Build Coastguard Worker
648*cf78ab8cSAndroid Build Coastguard Worker let new_ieee80211 = ieee80211.with_address(Some(new_source), None);
649*cf78ab8cSAndroid Build Coastguard Worker assert!(new_ieee80211.get_source() == new_source);
650*cf78ab8cSAndroid Build Coastguard Worker assert!(new_ieee80211.get_destination() == destination);
651*cf78ab8cSAndroid Build Coastguard Worker
652*cf78ab8cSAndroid Build Coastguard Worker let new_ieee80211 = ieee80211.with_address(None, Some(new_destination));
653*cf78ab8cSAndroid Build Coastguard Worker assert!(new_ieee80211.get_source() == source);
654*cf78ab8cSAndroid Build Coastguard Worker assert!(new_ieee80211.get_destination() == new_destination);
655*cf78ab8cSAndroid Build Coastguard Worker }
656*cf78ab8cSAndroid Build Coastguard Worker
657*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_with_address_from_ap()658*cf78ab8cSAndroid Build Coastguard Worker fn test_with_address_from_ap() {
659*cf78ab8cSAndroid Build Coastguard Worker test_with_address(create_test_from_ap_ieee80211);
660*cf78ab8cSAndroid Build Coastguard Worker }
661*cf78ab8cSAndroid Build Coastguard Worker
662*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_with_address_to_ap()663*cf78ab8cSAndroid Build Coastguard Worker fn test_with_address_to_ap() {
664*cf78ab8cSAndroid Build Coastguard Worker test_with_address(create_test_to_ap_ieee80211);
665*cf78ab8cSAndroid Build Coastguard Worker }
666*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_with_address_ibss()667*cf78ab8cSAndroid Build Coastguard Worker fn test_with_address_ibss() {
668*cf78ab8cSAndroid Build Coastguard Worker test_with_address(create_test_ibss_ieee80211);
669*cf78ab8cSAndroid Build Coastguard Worker }
670*cf78ab8cSAndroid Build Coastguard Worker
671*cf78ab8cSAndroid Build Coastguard Worker #[test]
test_to_ieee8023()672*cf78ab8cSAndroid Build Coastguard Worker fn test_to_ieee8023() {
673*cf78ab8cSAndroid Build Coastguard Worker let source = parse_mac_address("01:02:03:00:00:01").unwrap();
674*cf78ab8cSAndroid Build Coastguard Worker let destination = parse_mac_address("01:02:03:00:00:02").unwrap();
675*cf78ab8cSAndroid Build Coastguard Worker let bssid = parse_mac_address("00:13:10:85:fe:01").unwrap();
676*cf78ab8cSAndroid Build Coastguard Worker
677*cf78ab8cSAndroid Build Coastguard Worker // Test Data (802.11 frame with LLC/SNAP)
678*cf78ab8cSAndroid Build Coastguard Worker let ieee80211: Ieee80211 = Ieee80211ToAp {
679*cf78ab8cSAndroid Build Coastguard Worker duration_id: 0,
680*cf78ab8cSAndroid Build Coastguard Worker ftype: FrameType::Data,
681*cf78ab8cSAndroid Build Coastguard Worker more_data: 0,
682*cf78ab8cSAndroid Build Coastguard Worker more_frags: 0,
683*cf78ab8cSAndroid Build Coastguard Worker order: 0,
684*cf78ab8cSAndroid Build Coastguard Worker pm: 0,
685*cf78ab8cSAndroid Build Coastguard Worker protected: 0,
686*cf78ab8cSAndroid Build Coastguard Worker retry: 0,
687*cf78ab8cSAndroid Build Coastguard Worker stype: 0,
688*cf78ab8cSAndroid Build Coastguard Worker version: 0,
689*cf78ab8cSAndroid Build Coastguard Worker bssid,
690*cf78ab8cSAndroid Build Coastguard Worker source,
691*cf78ab8cSAndroid Build Coastguard Worker destination,
692*cf78ab8cSAndroid Build Coastguard Worker seq_ctrl: 0,
693*cf78ab8cSAndroid Build Coastguard Worker payload: vec![
694*cf78ab8cSAndroid Build Coastguard Worker // LLC/SNAP Header
695*cf78ab8cSAndroid Build Coastguard Worker LlcSap::Snap as u8,
696*cf78ab8cSAndroid Build Coastguard Worker LlcSap::Snap as u8,
697*cf78ab8cSAndroid Build Coastguard Worker LlcCtrl::UiCmd as u8,
698*cf78ab8cSAndroid Build Coastguard Worker // OUI
699*cf78ab8cSAndroid Build Coastguard Worker 0x00,
700*cf78ab8cSAndroid Build Coastguard Worker 0x00,
701*cf78ab8cSAndroid Build Coastguard Worker 0x00,
702*cf78ab8cSAndroid Build Coastguard Worker // EtherType
703*cf78ab8cSAndroid Build Coastguard Worker 0x08,
704*cf78ab8cSAndroid Build Coastguard Worker 0x00,
705*cf78ab8cSAndroid Build Coastguard Worker ],
706*cf78ab8cSAndroid Build Coastguard Worker }
707*cf78ab8cSAndroid Build Coastguard Worker .try_into()
708*cf78ab8cSAndroid Build Coastguard Worker .unwrap();
709*cf78ab8cSAndroid Build Coastguard Worker
710*cf78ab8cSAndroid Build Coastguard Worker // Call the function under test
711*cf78ab8cSAndroid Build Coastguard Worker let result = ieee80211.to_ieee8023();
712*cf78ab8cSAndroid Build Coastguard Worker // Assert
713*cf78ab8cSAndroid Build Coastguard Worker assert!(result.is_ok());
714*cf78ab8cSAndroid Build Coastguard Worker let ethernet_frame = result.unwrap();
715*cf78ab8cSAndroid Build Coastguard Worker
716*cf78ab8cSAndroid Build Coastguard Worker // Verify ethernet frame
717*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ðernet_frame[0..6], destination.to_vec().as_slice()); // Destination MAC
718*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ðernet_frame[6..12], source.to_vec().as_slice()); // Source MAC
719*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(ðernet_frame[12..14], [0x08, 0x00]); // EtherType
720*cf78ab8cSAndroid Build Coastguard Worker }
721*cf78ab8cSAndroid Build Coastguard Worker }
722