1#!/usr/bin/env python3 2# 3# Copyright 2022 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from enum import IntEnum, unique 18 19 20@unique 21class ApReachability(IntEnum): 22 """Neighbor Report AP Reachability values. 23 24 See IEEE 802.11-2020 Figure 9-172. 25 """ 26 NOT_REACHABLE = 1 27 UNKNOWN = 2 28 REACHABLE = 3 29 30 31class BssidInformationCapabilities: 32 """Representation of Neighbor Report BSSID Information Capabilities. 33 34 See IEEE 802.11-2020 Figure 9-338 and 9.4.1.4. 35 """ 36 37 def __init__(self, 38 spectrum_management: bool = False, 39 qos: bool = False, 40 apsd: bool = False, 41 radio_measurement: bool = False): 42 """Create a capabilities object. 43 44 Args: 45 spectrum_management: whether spectrum management is required. 46 qos: whether QoS is implemented. 47 apsd: whether APSD is implemented. 48 radio_measurement: whether radio measurement is activated. 49 """ 50 self._spectrum_management = spectrum_management 51 self._qos = qos 52 self._apsd = apsd 53 self._radio_measurement = radio_measurement 54 55 def __index__(self) -> int: 56 """Convert to numeric representation of the field's bits.""" 57 return self.spectrum_management << 5 \ 58 | self.qos << 4 \ 59 | self.apsd << 3 \ 60 | self.radio_measurement << 2 61 62 @property 63 def spectrum_management(self) -> bool: 64 return self._spectrum_management 65 66 @property 67 def qos(self) -> bool: 68 return self._qos 69 70 @property 71 def apsd(self) -> bool: 72 return self._apsd 73 74 @property 75 def radio_measurement(self) -> bool: 76 return self._radio_measurement 77 78 79class BssidInformation: 80 """Representation of Neighbor Report BSSID Information field. 81 82 BssidInformation contains info about a neighboring AP, to be included in a 83 neighbor report element. See IEEE 802.11-2020 Figure 9-337. 84 """ 85 86 def __init__(self, 87 ap_reachability: ApReachability = ApReachability.UNKNOWN, 88 security: bool = False, 89 key_scope: bool = False, 90 capabilities: 91 BssidInformationCapabilities = BssidInformationCapabilities(), 92 mobility_domain: bool = False, 93 high_throughput: bool = False, 94 very_high_throughput: bool = False, 95 ftm: bool = False): 96 """Create a BSSID Information object for a neighboring AP. 97 98 Args: 99 ap_reachability: whether this AP is reachable by the STA that 100 requested the neighbor report. 101 security: whether this AP is known to support the same security 102 provisioning as used by the STA in its current association. 103 key_scope: whether this AP is known to have the same 104 authenticator as the AP sending the report. 105 capabilities: selected capabilities of this AP. 106 mobility_domain: whether the AP is including an MDE in its beacon 107 frames and the contents of that MDE are identical to the MDE 108 advertised by the AP sending the report. 109 high_throughput: whether the AP is an HT AP including the HT 110 Capabilities element in its Beacons, and that the contents of 111 that HT capabilities element are identical to the HT 112 capabilities element advertised by the AP sending the report. 113 very_high_throughput: whether the AP is a VHT AP and the VHT 114 capabilities element, if included as a subelement, is 115 identical in content to the VHT capabilities element included 116 in the AP’s beacon. 117 ftm: whether the AP is known to have the Fine Timing Measurement 118 Responder extended capability. 119 """ 120 self._ap_reachability = ap_reachability 121 self._security = security 122 self._key_scope = key_scope 123 self._capabilities = capabilities 124 self._mobility_domain = mobility_domain 125 self._high_throughput = high_throughput 126 self._very_high_throughput = very_high_throughput 127 self._ftm = ftm 128 129 def __index__(self) -> int: 130 """Convert to numeric representation of the field's bits.""" 131 return self._ap_reachability << 30 \ 132 | self.security << 29 \ 133 | self.key_scope << 28 \ 134 | int(self.capabilities) << 22 \ 135 | self.mobility_domain << 21 \ 136 | self.high_throughput << 20 \ 137 | self.very_high_throughput << 19 \ 138 | self.ftm << 18 139 140 @property 141 def security(self) -> bool: 142 return self._security 143 144 @property 145 def key_scope(self) -> bool: 146 return self._key_scope 147 148 @property 149 def capabilities(self) -> BssidInformationCapabilities: 150 return self._capabilities 151 152 @property 153 def mobility_domain(self) -> bool: 154 return self._mobility_domain 155 156 @property 157 def high_throughput(self) -> bool: 158 return self._high_throughput 159 160 @property 161 def very_high_throughput(self) -> bool: 162 return self._very_high_throughput 163 164 @property 165 def ftm(self) -> bool: 166 return self._ftm 167 168 169@unique 170class PhyType(IntEnum): 171 """PHY type values, see dot11PhyType in 802.11-2020 Annex C.""" 172 DSSS = 2 173 OFDM = 4 174 HRDSS = 5 175 ERP = 6 176 HT = 7 177 DMG = 8 178 VHT = 9 179 TVHT = 10 180 S1G = 11 181 CDMG = 12 182 CMMG = 13 183 184 185class NeighborReportElement: 186 """Representation of Neighbor Report element. 187 188 See IEEE 802.11-2020 9.4.2.36. 189 """ 190 191 def __init__(self, bssid: str, bssid_information: BssidInformation, 192 operating_class: int, channel_number: int, phy_type: PhyType): 193 """Create a neighbor report element. 194 195 Args: 196 bssid: MAC address of the neighbor. 197 bssid_information: BSSID Information of the neigbor. 198 operating_class: operating class of the neighbor. 199 channel_number: channel number of the neighbor. 200 phy_type: dot11PhyType of the neighbor. 201 """ 202 self._bssid = bssid 203 self._bssid_information = bssid_information 204 205 # Operating Class, IEEE 802.11-2020 Annex E. 206 self._operating_class = operating_class 207 208 self._channel_number = channel_number 209 210 # PHY Type, IEEE 802.11-2020 Annex C. 211 self._phy_type = phy_type 212 213 @property 214 def bssid(self) -> str: 215 return self._bssid 216 217 @property 218 def bssid_information(self) -> BssidInformation: 219 return self._bssid_information 220 221 @property 222 def operating_class(self) -> int: 223 return self._operating_class 224 225 @property 226 def channel_number(self) -> int: 227 return self._channel_number 228 229 @property 230 def phy_type(self) -> PhyType: 231 return self._phy_type 232