1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "wificond/net/netlink_utils.h" 18 19 #include <string> 20 #include <vector> 21 22 #include <linux/netlink.h> 23 #include <linux/nl80211.h> 24 25 #include <android-base/logging.h> 26 27 #include "wificond/net/mlme_event_handler.h" 28 #include "wificond/net/nl80211_packet.h" 29 30 using std::string; 31 using std::unique_ptr; 32 using std::vector; 33 34 namespace android { 35 namespace wificond { 36 37 namespace { 38 39 uint32_t k2GHzFrequencyLowerBound = 2400; 40 uint32_t k2GHzFrequencyUpperBound = 2500; 41 42 } // namespace 43 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager) 44 : netlink_manager_(netlink_manager) { 45 if (!netlink_manager_->IsStarted()) { 46 netlink_manager_->Start(); 47 } 48 } 49 50 NetlinkUtils::~NetlinkUtils() {} 51 52 bool NetlinkUtils::GetWiphyIndex(uint32_t* out_wiphy_index) { 53 NL80211Packet get_wiphy( 54 netlink_manager_->GetFamilyId(), 55 NL80211_CMD_GET_WIPHY, 56 netlink_manager_->GetSequenceNumber(), 57 getpid()); 58 get_wiphy.AddFlag(NLM_F_DUMP); 59 vector<unique_ptr<const NL80211Packet>> response; 60 if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response)) { 61 LOG(ERROR) << "NL80211_CMD_GET_WIPHY dump failed"; 62 return false; 63 } 64 if (response.empty()) { 65 LOG(DEBUG) << "No wiphy is found"; 66 return false; 67 } 68 for (auto& packet : response) { 69 if (packet->GetMessageType() == NLMSG_ERROR) { 70 LOG(ERROR) << "Receive ERROR message: " 71 << strerror(packet->GetErrorCode()); 72 return false; 73 } 74 if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) { 75 LOG(ERROR) << "Wrong message type for new interface message: " 76 << packet->GetMessageType(); 77 return false; 78 } 79 if (packet->GetCommand() != NL80211_CMD_NEW_WIPHY) { 80 LOG(ERROR) << "Wrong command in response to " 81 << "a wiphy dump request: " 82 << static_cast<int>(packet->GetCommand()); 83 return false; 84 } 85 if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) { 86 LOG(ERROR) << "Failed to get wiphy index from reply message"; 87 return false; 88 } 89 } 90 return true; 91 } 92 93 bool NetlinkUtils::GetInterfaces(uint32_t wiphy_index, 94 vector<InterfaceInfo>* interface_info) { 95 NL80211Packet get_interfaces( 96 netlink_manager_->GetFamilyId(), 97 NL80211_CMD_GET_INTERFACE, 98 netlink_manager_->GetSequenceNumber(), 99 getpid()); 100 101 get_interfaces.AddFlag(NLM_F_DUMP); 102 get_interfaces.AddAttribute( 103 NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index)); 104 vector<unique_ptr<const NL80211Packet>> response; 105 if (!netlink_manager_->SendMessageAndGetResponses(get_interfaces, &response)) { 106 LOG(ERROR) << "NL80211_CMD_GET_INTERFACE dump failed"; 107 return false; 108 } 109 if (response.empty()) { 110 LOG(ERROR) << "No interface is found"; 111 return false; 112 } 113 for (auto& packet : response) { 114 if (packet->GetMessageType() == NLMSG_ERROR) { 115 LOG(ERROR) << "Receive ERROR message: " 116 << strerror(packet->GetErrorCode()); 117 return false; 118 } 119 if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) { 120 LOG(ERROR) << "Wrong message type for new interface message: " 121 << packet->GetMessageType(); 122 return false; 123 } 124 if (packet->GetCommand() != NL80211_CMD_NEW_INTERFACE) { 125 LOG(ERROR) << "Wrong command in response to " 126 << "an interface dump request: " 127 << static_cast<int>(packet->GetCommand()); 128 return false; 129 } 130 131 // In some situations, it has been observed that the kernel tells us 132 // about a pseudo interface that does not have a real netdev. In this 133 // case, responses will have a NL80211_ATTR_WDEV, and not the expected 134 // IFNAME/IFINDEX. In this case we just skip these pseudo interfaces. 135 uint32_t if_index; 136 if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) { 137 LOG(DEBUG) << "Failed to get interface index"; 138 continue; 139 } 140 141 // Today we don't check NL80211_ATTR_IFTYPE because at this point of time 142 // driver always reports that interface is in STATION mode. Even when we 143 // are asking interfaces infomation on behalf of tethering, it is still so 144 // because hostapd is supposed to set interface to AP mode later. 145 146 string if_name; 147 if (!packet->GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) { 148 LOG(WARNING) << "Failed to get interface name"; 149 continue; 150 } 151 152 vector<uint8_t> if_mac_addr; 153 if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) { 154 LOG(WARNING) << "Failed to get interface mac address"; 155 continue; 156 } 157 158 interface_info->emplace_back(if_index, if_name, if_mac_addr); 159 } 160 161 return true; 162 } 163 164 bool NetlinkUtils::SetInterfaceMode(uint32_t interface_index, 165 InterfaceMode mode) { 166 uint32_t set_to_mode = NL80211_IFTYPE_UNSPECIFIED; 167 if (mode == STATION_MODE) { 168 set_to_mode = NL80211_IFTYPE_STATION; 169 } else { 170 LOG(ERROR) << "Unexpected mode for interface with index: " 171 << interface_index; 172 return false; 173 } 174 NL80211Packet set_interface_mode( 175 netlink_manager_->GetFamilyId(), 176 NL80211_CMD_SET_INTERFACE, 177 netlink_manager_->GetSequenceNumber(), 178 getpid()); 179 // Force an ACK response upon success. 180 set_interface_mode.AddFlag(NLM_F_ACK); 181 182 set_interface_mode.AddAttribute( 183 NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index)); 184 set_interface_mode.AddAttribute( 185 NL80211Attr<uint32_t>(NL80211_ATTR_IFTYPE, set_to_mode)); 186 187 if (!netlink_manager_->SendMessageAndGetAck(set_interface_mode)) { 188 LOG(ERROR) << "NL80211_CMD_SET_INTERFACE failed"; 189 return false; 190 } 191 192 return true; 193 } 194 195 bool NetlinkUtils::GetWiphyInfo( 196 uint32_t wiphy_index, 197 BandInfo* out_band_info, 198 ScanCapabilities* out_scan_capabilities, 199 WiphyFeatures* out_wiphy_features) { 200 NL80211Packet get_wiphy( 201 netlink_manager_->GetFamilyId(), 202 NL80211_CMD_GET_WIPHY, 203 netlink_manager_->GetSequenceNumber(), 204 getpid()); 205 get_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index)); 206 unique_ptr<const NL80211Packet> response; 207 if (!netlink_manager_->SendMessageAndGetSingleResponse(get_wiphy, 208 &response)) { 209 LOG(ERROR) << "NL80211_CMD_GET_WIPHY failed"; 210 return false; 211 } 212 if (response->GetCommand() != NL80211_CMD_NEW_WIPHY) { 213 LOG(ERROR) << "Wrong command in response to a get wiphy request: " 214 << static_cast<int>(response->GetCommand()); 215 return false; 216 } 217 if (!ParseBandInfo(response.get(), out_band_info) || 218 !ParseScanCapabilities(response.get(), out_scan_capabilities)) { 219 return false; 220 } 221 uint32_t feature_flags; 222 if (!response->GetAttributeValue(NL80211_ATTR_FEATURE_FLAGS, 223 &feature_flags)) { 224 LOG(ERROR) << "Failed to get NL80211_ATTR_FEATURE_FLAGS"; 225 return false; 226 } 227 *out_wiphy_features = WiphyFeatures(feature_flags); 228 return true; 229 } 230 231 bool NetlinkUtils::ParseScanCapabilities( 232 const NL80211Packet* const packet, 233 ScanCapabilities* out_scan_capabilities) { 234 uint8_t max_num_scan_ssids; 235 if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCAN_SSIDS, 236 &max_num_scan_ssids)) { 237 LOG(ERROR) << "Failed to get the capacity of maximum number of scan ssids"; 238 return false; 239 } 240 241 uint8_t max_num_sched_scan_ssids; 242 if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, 243 &max_num_sched_scan_ssids)) { 244 LOG(ERROR) << "Failed to get the capacity of " 245 << "maximum number of scheduled scan ssids"; 246 return false; 247 } 248 249 // Use default value 0 for scan plan capabilities if attributes are missing. 250 uint32_t max_num_scan_plans = 0; 251 packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS, 252 &max_num_scan_plans); 253 uint32_t max_scan_plan_interval = 0; 254 packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, 255 &max_scan_plan_interval); 256 uint32_t max_scan_plan_iterations = 0; 257 packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS, 258 &max_scan_plan_iterations); 259 260 uint8_t max_match_sets; 261 if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS, 262 &max_match_sets)) { 263 LOG(ERROR) << "Failed to get the capacity of maximum number of match set" 264 << "of a scheduled scan"; 265 return false; 266 } 267 *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids, 268 max_num_sched_scan_ssids, 269 max_match_sets, 270 max_num_scan_plans, 271 max_scan_plan_interval, 272 max_scan_plan_iterations); 273 return true; 274 } 275 276 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet, 277 BandInfo* out_band_info) { 278 279 NL80211NestedAttr bands_attr(0); 280 if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) { 281 LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS"; 282 return false; 283 } 284 vector<NL80211NestedAttr> bands; 285 if (!bands_attr.GetListOfNestedAttributes(&bands)) { 286 LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS"; 287 return false; 288 } 289 vector<uint32_t> frequencies_2g; 290 vector<uint32_t> frequencies_5g; 291 vector<uint32_t> frequencies_dfs; 292 for (unsigned int band_index = 0; band_index < bands.size(); band_index++) { 293 NL80211NestedAttr freqs_attr(0); 294 if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) { 295 LOG(DEBUG) << "Failed to get NL80211_BAND_ATTR_FREQS"; 296 continue; 297 } 298 vector<NL80211NestedAttr> freqs; 299 if (!freqs_attr.GetListOfNestedAttributes(&freqs)) { 300 LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS"; 301 continue; 302 } 303 for (auto& freq : freqs) { 304 uint32_t frequency_value; 305 if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ, 306 &frequency_value)) { 307 LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ"; 308 continue; 309 } 310 // Channel is disabled in current regulatory domain. 311 if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) { 312 continue; 313 } 314 // If this is an available/usable DFS frequency, we should save it to 315 // DFS frequencies list. 316 uint32_t dfs_state; 317 if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE, 318 &dfs_state) && 319 (dfs_state == NL80211_DFS_AVAILABLE || 320 dfs_state == NL80211_DFS_USABLE)) { 321 frequencies_dfs.push_back(frequency_value); 322 } else { 323 // Since there is no guarantee for the order of band attributes, 324 // we do some math here. 325 if (frequency_value > k2GHzFrequencyLowerBound && 326 frequency_value < k2GHzFrequencyUpperBound) { 327 frequencies_2g.push_back(frequency_value); 328 } else { 329 frequencies_5g.push_back(frequency_value); 330 } 331 } 332 } 333 } 334 *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs); 335 return true; 336 } 337 338 bool NetlinkUtils::GetStationInfo(uint32_t interface_index, 339 const vector<uint8_t>& mac_address, 340 StationInfo* out_station_info) { 341 NL80211Packet get_station( 342 netlink_manager_->GetFamilyId(), 343 NL80211_CMD_GET_STATION, 344 netlink_manager_->GetSequenceNumber(), 345 getpid()); 346 get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, 347 interface_index)); 348 get_station.AddAttribute(NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC, 349 mac_address)); 350 351 unique_ptr<const NL80211Packet> response; 352 if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station, 353 &response)) { 354 LOG(ERROR) << "NL80211_CMD_GET_STATION failed"; 355 return false; 356 } 357 if (response->GetCommand() != NL80211_CMD_NEW_STATION) { 358 LOG(ERROR) << "Wrong command in response to a get station request: " 359 << static_cast<int>(response->GetCommand()); 360 return false; 361 } 362 NL80211NestedAttr sta_info(0); 363 if (!response->GetAttribute(NL80211_ATTR_STA_INFO, &sta_info)) { 364 LOG(ERROR) << "Failed to get NL80211_ATTR_STA_INFO"; 365 return false; 366 } 367 int32_t tx_good, tx_bad; 368 if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_PACKETS, &tx_good)) { 369 LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_PACKETS"; 370 return false; 371 } 372 if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_FAILED, &tx_bad)) { 373 LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_FAILED"; 374 return false; 375 } 376 int8_t current_rssi; 377 if (!sta_info.GetAttributeValue(NL80211_STA_INFO_SIGNAL, ¤t_rssi)) { 378 LOG(ERROR) << "Failed to get NL80211_STA_INFO_SIGNAL"; 379 return false; 380 } 381 NL80211NestedAttr tx_bitrate_attr(0); 382 if (!sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE, 383 &tx_bitrate_attr)) { 384 LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_BITRATE"; 385 return false; 386 } 387 uint32_t tx_bitrate; 388 if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32, 389 &tx_bitrate)) { 390 LOG(ERROR) << "Failed to get NL80211_RATE_INFO_BITRATE32"; 391 return false; 392 } 393 394 *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi); 395 return true; 396 } 397 398 void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index, 399 MlmeEventHandler* handler) { 400 netlink_manager_->SubscribeMlmeEvent(interface_index, handler); 401 } 402 403 void NetlinkUtils::UnsubscribeMlmeEvent(uint32_t interface_index) { 404 netlink_manager_->UnsubscribeMlmeEvent(interface_index); 405 } 406 407 void NetlinkUtils::SubscribeRegDomainChange( 408 uint32_t wiphy_index, 409 OnRegDomainChangedHandler handler) { 410 netlink_manager_->SubscribeRegDomainChange(wiphy_index, handler); 411 } 412 413 void NetlinkUtils::UnsubscribeRegDomainChange(uint32_t wiphy_index) { 414 netlink_manager_->UnsubscribeRegDomainChange(wiphy_index); 415 } 416 417 void NetlinkUtils::SubscribeStationEvent(uint32_t interface_index, 418 OnStationEventHandler handler) { 419 netlink_manager_->SubscribeStationEvent(interface_index, handler); 420 } 421 422 void NetlinkUtils::UnsubscribeStationEvent(uint32_t interface_index) { 423 netlink_manager_->UnsubscribeStationEvent(interface_index); 424 } 425 426 } // namespace wificond 427 } // namespace android 428