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 <array>
20 #include <algorithm>
21 #include <bitset>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 #include <net/if.h>
27 #include <linux/netlink.h>
28 
29 #include <android-base/logging.h>
30 
31 #include "wificond/net/kernel-header-latest/nl80211.h"
32 #include "wificond/net/mlme_event_handler.h"
33 #include "wificond/net/nl80211_packet.h"
34 
35 using std::array;
36 using std::make_pair;
37 using std::make_unique;
38 using std::map;
39 using std::move;
40 using std::string;
41 using std::unique_ptr;
42 using std::vector;
43 
44 namespace android {
45 namespace wificond {
46 
47 namespace {
48 
49 uint32_t k2GHzFrequencyLowerBound = 2400;
50 uint32_t k2GHzFrequencyUpperBound = 2500;
51 
52 uint32_t k5GHzFrequencyLowerBound = 5000;
53 // This upper bound will exclude any 5.9Ghz channels which belong to 802.11p
54 // for "vehicular communication systems".
55 uint32_t k5GHzFrequencyUpperBound = 5850;
56 
IsExtFeatureFlagSet(const std::vector<uint8_t> & ext_feature_flags_bytes,enum nl80211_ext_feature_index ext_feature_flag)57 bool IsExtFeatureFlagSet(
58     const std::vector<uint8_t>& ext_feature_flags_bytes,
59     enum nl80211_ext_feature_index ext_feature_flag) {
60   static_assert(NUM_NL80211_EXT_FEATURES <= SIZE_MAX,
61                 "Ext feature values doesn't fit in |size_t|");
62   // TODO:This is an unsafe cast because this assumes that the values
63   // are always unsigned!
64   size_t ext_feature_flag_idx = static_cast<size_t>(ext_feature_flag);
65   size_t ext_feature_flag_byte_pos = ext_feature_flag_idx / 8;
66   size_t ext_feature_flag_bit_pos = ext_feature_flag_idx % 8;
67   if (ext_feature_flag_byte_pos >= ext_feature_flags_bytes.size()) {
68     return false;
69   }
70   uint8_t ext_feature_flag_byte =
71       ext_feature_flags_bytes[ext_feature_flag_byte_pos];
72   return (ext_feature_flag_byte & (1U << ext_feature_flag_bit_pos));
73 }
74 }  // namespace
75 
WiphyFeatures(uint32_t feature_flags,const std::vector<uint8_t> & ext_feature_flags_bytes)76 WiphyFeatures::WiphyFeatures(uint32_t feature_flags,
77                              const std::vector<uint8_t>& ext_feature_flags_bytes)
78     : supports_random_mac_oneshot_scan(
79             feature_flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR),
80         supports_random_mac_sched_scan(
81             feature_flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR) {
82   supports_low_span_oneshot_scan =
83       IsExtFeatureFlagSet(ext_feature_flags_bytes,
84                           NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
85   supports_low_power_oneshot_scan =
86       IsExtFeatureFlagSet(ext_feature_flags_bytes,
87                           NL80211_EXT_FEATURE_LOW_POWER_SCAN);
88   supports_high_accuracy_oneshot_scan =
89       IsExtFeatureFlagSet(ext_feature_flags_bytes,
90                           NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
91   // TODO (b/112029045) check if sending frame at specified MCS is supported
92   supports_tx_mgmt_frame_mcs = false;
93   supports_ext_sched_scan_relative_rssi =
94       IsExtFeatureFlagSet(ext_feature_flags_bytes,
95                           NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI);
96 }
97 
NetlinkUtils(NetlinkManager * netlink_manager)98 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
99     : netlink_manager_(netlink_manager) {
100   if (!netlink_manager_->IsStarted()) {
101     netlink_manager_->Start();
102   }
103   uint32_t protocol_features = 0;
104   supports_split_wiphy_dump_ = GetProtocolFeatures(&protocol_features) &&
105       (protocol_features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP);
106 }
107 
~NetlinkUtils()108 NetlinkUtils::~NetlinkUtils() {}
109 
GetWiphyIndex(uint32_t * out_wiphy_index,const std::string & iface_name)110 bool NetlinkUtils::GetWiphyIndex(uint32_t* out_wiphy_index,
111                                  const std::string& iface_name) {
112   NL80211Packet get_wiphy(
113       netlink_manager_->GetFamilyId(),
114       NL80211_CMD_GET_WIPHY,
115       netlink_manager_->GetSequenceNumber(),
116       getpid());
117   get_wiphy.AddFlag(NLM_F_DUMP);
118   if (!iface_name.empty()) {
119     int ifindex = if_nametoindex(iface_name.c_str());
120     get_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, ifindex));
121   }
122   vector<unique_ptr<const NL80211Packet>> response;
123   if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response))  {
124     LOG(ERROR) << "NL80211_CMD_GET_WIPHY dump failed";
125     return false;
126   }
127   if (response.empty()) {
128     LOG(DEBUG) << "No wiphy is found";
129     return false;
130   }
131   for (auto& packet : response) {
132     if (packet->GetMessageType() == NLMSG_ERROR) {
133       LOG(ERROR) << "Receive ERROR message: "
134                  << strerror(packet->GetErrorCode());
135       return false;
136     }
137     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
138       LOG(ERROR) << "Wrong message type for new interface message: "
139                  << packet->GetMessageType();
140       return false;
141     }
142     if (packet->GetCommand() != NL80211_CMD_NEW_WIPHY) {
143       LOG(ERROR) << "Wrong command in response to "
144                  << "a wiphy dump request: "
145                  << static_cast<int>(packet->GetCommand());
146       return false;
147     }
148     if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) {
149       LOG(ERROR) << "Failed to get wiphy index from reply message";
150       return false;
151     }
152   }
153   return true;
154 }
155 
GetWiphyIndex(uint32_t * out_wiphy_index)156 bool NetlinkUtils::GetWiphyIndex(uint32_t* out_wiphy_index) {
157   return GetWiphyIndex(out_wiphy_index, "");
158 }
159 
GetInterfaces(uint32_t wiphy_index,vector<InterfaceInfo> * interface_info)160 bool NetlinkUtils::GetInterfaces(uint32_t wiphy_index,
161                                  vector<InterfaceInfo>* interface_info) {
162   NL80211Packet get_interfaces(
163       netlink_manager_->GetFamilyId(),
164       NL80211_CMD_GET_INTERFACE,
165       netlink_manager_->GetSequenceNumber(),
166       getpid());
167 
168   get_interfaces.AddFlag(NLM_F_DUMP);
169   get_interfaces.AddAttribute(
170       NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
171   vector<unique_ptr<const NL80211Packet>> response;
172   if (!netlink_manager_->SendMessageAndGetResponses(get_interfaces, &response)) {
173     LOG(ERROR) << "NL80211_CMD_GET_INTERFACE dump failed";
174     return false;
175   }
176   if (response.empty()) {
177     LOG(ERROR) << "No interface is found";
178     return false;
179   }
180   for (auto& packet : response) {
181     if (packet->GetMessageType() == NLMSG_ERROR) {
182       LOG(ERROR) << "Receive ERROR message: "
183                  << strerror(packet->GetErrorCode());
184       return false;
185     }
186     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
187       LOG(ERROR) << "Wrong message type for new interface message: "
188                  << packet->GetMessageType();
189       return false;
190     }
191     if (packet->GetCommand() != NL80211_CMD_NEW_INTERFACE) {
192       LOG(ERROR) << "Wrong command in response to "
193                  << "an interface dump request: "
194                  << static_cast<int>(packet->GetCommand());
195       return false;
196     }
197 
198     // In some situations, it has been observed that the kernel tells us
199     // about a pseudo interface that does not have a real netdev.  In this
200     // case, responses will have a NL80211_ATTR_WDEV, and not the expected
201     // IFNAME/IFINDEX. In this case we just skip these pseudo interfaces.
202     uint32_t if_index;
203     if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
204       LOG(DEBUG) << "Failed to get interface index";
205       continue;
206     }
207 
208     // Today we don't check NL80211_ATTR_IFTYPE because at this point of time
209     // driver always reports that interface is in STATION mode. Even when we
210     // are asking interfaces infomation on behalf of tethering, it is still so
211     // because hostapd is supposed to set interface to AP mode later.
212 
213     string if_name;
214     if (!packet->GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) {
215       LOG(WARNING) << "Failed to get interface name";
216       continue;
217     }
218 
219     array<uint8_t, ETH_ALEN> if_mac_addr;
220     if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) {
221       LOG(WARNING) << "Failed to get interface mac address";
222       continue;
223     }
224 
225     interface_info->emplace_back(if_index, if_name, if_mac_addr);
226   }
227 
228   return true;
229 }
230 
SetInterfaceMode(uint32_t interface_index,InterfaceMode mode)231 bool NetlinkUtils::SetInterfaceMode(uint32_t interface_index,
232                                     InterfaceMode mode) {
233   uint32_t set_to_mode = NL80211_IFTYPE_UNSPECIFIED;
234   if (mode == STATION_MODE) {
235     set_to_mode = NL80211_IFTYPE_STATION;
236   } else {
237     LOG(ERROR) << "Unexpected mode for interface with index: "
238                << interface_index;
239     return false;
240   }
241   NL80211Packet set_interface_mode(
242       netlink_manager_->GetFamilyId(),
243       NL80211_CMD_SET_INTERFACE,
244       netlink_manager_->GetSequenceNumber(),
245       getpid());
246   // Force an ACK response upon success.
247   set_interface_mode.AddFlag(NLM_F_ACK);
248 
249   set_interface_mode.AddAttribute(
250       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
251   set_interface_mode.AddAttribute(
252       NL80211Attr<uint32_t>(NL80211_ATTR_IFTYPE, set_to_mode));
253 
254   if (!netlink_manager_->SendMessageAndGetAck(set_interface_mode)) {
255     LOG(ERROR) << "NL80211_CMD_SET_INTERFACE failed";
256     return false;
257   }
258 
259   return true;
260 }
261 
GetProtocolFeatures(uint32_t * features)262 bool NetlinkUtils::GetProtocolFeatures(uint32_t* features) {
263   NL80211Packet get_protocol_features(
264       netlink_manager_->GetFamilyId(),
265       NL80211_CMD_GET_PROTOCOL_FEATURES,
266       netlink_manager_->GetSequenceNumber(),
267       getpid());
268   unique_ptr<const NL80211Packet> response;
269   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_protocol_features,
270                                                          &response)) {
271     LOG(ERROR) << "NL80211_CMD_GET_PROTOCOL_FEATURES failed";
272     return false;
273   }
274   if (!response->GetAttributeValue(NL80211_ATTR_PROTOCOL_FEATURES, features)) {
275     LOG(ERROR) << "Failed to get NL80211_ATTR_PROTOCOL_FEATURES";
276     return false;
277   }
278   return true;
279 }
280 
GetWiphyInfo(uint32_t wiphy_index,BandInfo * out_band_info,ScanCapabilities * out_scan_capabilities,WiphyFeatures * out_wiphy_features)281 bool NetlinkUtils::GetWiphyInfo(
282     uint32_t wiphy_index,
283     BandInfo* out_band_info,
284     ScanCapabilities* out_scan_capabilities,
285     WiphyFeatures* out_wiphy_features) {
286   NL80211Packet get_wiphy(
287       netlink_manager_->GetFamilyId(),
288       NL80211_CMD_GET_WIPHY,
289       netlink_manager_->GetSequenceNumber(),
290       getpid());
291   get_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
292   if (supports_split_wiphy_dump_) {
293     get_wiphy.AddFlagAttribute(NL80211_ATTR_SPLIT_WIPHY_DUMP);
294     get_wiphy.AddFlag(NLM_F_DUMP);
295   }
296   vector<unique_ptr<const NL80211Packet>> response;
297   if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response))  {
298     LOG(ERROR) << "NL80211_CMD_GET_WIPHY dump failed";
299     return false;
300   }
301 
302   vector<NL80211Packet> packet_per_wiphy;
303   if (supports_split_wiphy_dump_) {
304     if (!MergePacketsForSplitWiphyDump(response, &packet_per_wiphy)) {
305       LOG(WARNING) << "Failed to merge responses from split wiphy dump";
306     }
307   } else {
308     for (auto& packet : response) {
309       packet_per_wiphy.push_back(move(*(packet.release())));
310     }
311   }
312 
313   for (const auto& packet : packet_per_wiphy) {
314     uint32_t current_wiphy_index;
315     if (!packet.GetAttributeValue(NL80211_ATTR_WIPHY, &current_wiphy_index) ||
316         // Not the wihpy we requested.
317         current_wiphy_index != wiphy_index) {
318       continue;
319     }
320     if (ParseWiphyInfoFromPacket(packet, out_band_info,
321                                  out_scan_capabilities, out_wiphy_features)) {
322       return true;
323     }
324   }
325 
326   LOG(ERROR) << "Failed to find expected wiphy info "
327              << "from NL80211_CMD_GET_WIPHY responses";
328   return false;
329 }
330 
ParseWiphyInfoFromPacket(const NL80211Packet & packet,BandInfo * out_band_info,ScanCapabilities * out_scan_capabilities,WiphyFeatures * out_wiphy_features)331 bool NetlinkUtils::ParseWiphyInfoFromPacket(
332     const NL80211Packet& packet,
333     BandInfo* out_band_info,
334     ScanCapabilities* out_scan_capabilities,
335     WiphyFeatures* out_wiphy_features) {
336   if (packet.GetCommand() != NL80211_CMD_NEW_WIPHY) {
337     LOG(ERROR) << "Wrong command in response to a get wiphy request: "
338                << static_cast<int>(packet.GetCommand());
339     return false;
340   }
341   if (!ParseBandInfo(&packet, out_band_info) ||
342       !ParseScanCapabilities(&packet, out_scan_capabilities)) {
343     return false;
344   }
345   uint32_t feature_flags;
346   if (!packet.GetAttributeValue(NL80211_ATTR_FEATURE_FLAGS,
347                                  &feature_flags)) {
348     LOG(ERROR) << "Failed to get NL80211_ATTR_FEATURE_FLAGS";
349     return false;
350   }
351   std::vector<uint8_t> ext_feature_flags_bytes;
352   if (!packet.GetAttributeValue(NL80211_ATTR_EXT_FEATURES,
353                                 &ext_feature_flags_bytes)) {
354     LOG(WARNING) << "Failed to get NL80211_ATTR_EXT_FEATURES";
355   }
356   *out_wiphy_features = WiphyFeatures(feature_flags,
357                                       ext_feature_flags_bytes);
358   return true;
359 }
360 
ParseScanCapabilities(const NL80211Packet * const packet,ScanCapabilities * out_scan_capabilities)361 bool NetlinkUtils::ParseScanCapabilities(
362     const NL80211Packet* const packet,
363     ScanCapabilities* out_scan_capabilities) {
364   uint8_t max_num_scan_ssids;
365   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
366                                    &max_num_scan_ssids)) {
367     LOG(ERROR) << "Failed to get the capacity of maximum number of scan ssids";
368     return false;
369   }
370 
371   uint8_t max_num_sched_scan_ssids;
372   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
373                                  &max_num_sched_scan_ssids)) {
374     LOG(ERROR) << "Failed to get the capacity of "
375                << "maximum number of scheduled scan ssids";
376     return false;
377   }
378 
379   // Use default value 0 for scan plan capabilities if attributes are missing.
380   uint32_t max_num_scan_plans = 0;
381   packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
382                             &max_num_scan_plans);
383   uint32_t max_scan_plan_interval = 0;
384   packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
385                             &max_scan_plan_interval);
386   uint32_t max_scan_plan_iterations = 0;
387   packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
388                             &max_scan_plan_iterations);
389 
390   uint8_t max_match_sets;
391   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
392                                    &max_match_sets)) {
393     LOG(ERROR) << "Failed to get the capacity of maximum number of match set"
394                << "of a scheduled scan";
395     return false;
396   }
397   *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
398                                             max_num_sched_scan_ssids,
399                                             max_match_sets,
400                                             max_num_scan_plans,
401                                             max_scan_plan_interval,
402                                             max_scan_plan_iterations);
403   return true;
404 }
405 
ParseBandInfo(const NL80211Packet * const packet,BandInfo * out_band_info)406 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
407                                  BandInfo* out_band_info) {
408 
409   NL80211NestedAttr bands_attr(0);
410   if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) {
411     LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS";
412     return false;
413   }
414   vector<NL80211NestedAttr> bands;
415   if (!bands_attr.GetListOfNestedAttributes(&bands)) {
416     LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS";
417     return false;
418   }
419   vector<uint32_t> frequencies_2g;
420   vector<uint32_t> frequencies_5g;
421   vector<uint32_t> frequencies_dfs;
422   for (unsigned int band_index = 0; band_index < bands.size(); band_index++) {
423     NL80211NestedAttr freqs_attr(0);
424     if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
425       LOG(DEBUG) << "Failed to get NL80211_BAND_ATTR_FREQS";
426       continue;
427     }
428     vector<NL80211NestedAttr> freqs;
429     if (!freqs_attr.GetListOfNestedAttributes(&freqs)) {
430       LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS";
431       continue;
432     }
433     for (auto& freq : freqs) {
434       uint32_t frequency_value;
435       if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
436                                   &frequency_value)) {
437         LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ";
438         continue;
439       }
440       // Channel is disabled in current regulatory domain.
441       if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) {
442         continue;
443       }
444       if (frequency_value > k2GHzFrequencyLowerBound &&
445             frequency_value < k2GHzFrequencyUpperBound) {
446           frequencies_2g.push_back(frequency_value);
447       } else if (frequency_value > k5GHzFrequencyLowerBound &&
448             frequency_value < k5GHzFrequencyUpperBound) {
449         // If this is an available/usable DFS frequency, we should save it to
450         // DFS frequencies list.
451         uint32_t dfs_state;
452         if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE,
453                                    &dfs_state) &&
454             (dfs_state == NL80211_DFS_AVAILABLE ||
455                  dfs_state == NL80211_DFS_USABLE)) {
456           frequencies_dfs.push_back(frequency_value);
457           continue;
458         }
459 
460         // Put non-dfs passive-only channels into the dfs category.
461         // This aligns with what framework always assumes.
462         if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_NO_IR)) {
463           frequencies_dfs.push_back(frequency_value);
464           continue;
465         }
466 
467         // Otherwise, this is a regular 5g frequency.
468         frequencies_5g.push_back(frequency_value);
469       }
470 
471     }
472   }
473   *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs);
474   return true;
475 }
476 
GetStationInfo(uint32_t interface_index,const array<uint8_t,ETH_ALEN> & mac_address,StationInfo * out_station_info)477 bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
478                                   const array<uint8_t, ETH_ALEN>& mac_address,
479                                   StationInfo* out_station_info) {
480   NL80211Packet get_station(
481       netlink_manager_->GetFamilyId(),
482       NL80211_CMD_GET_STATION,
483       netlink_manager_->GetSequenceNumber(),
484       getpid());
485   get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX,
486                                                  interface_index));
487   get_station.AddAttribute(NL80211Attr<array<uint8_t, ETH_ALEN>>(
488       NL80211_ATTR_MAC, mac_address));
489 
490   unique_ptr<const NL80211Packet> response;
491   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station,
492                                                          &response)) {
493     LOG(ERROR) << "NL80211_CMD_GET_STATION failed";
494     return false;
495   }
496   if (response->GetCommand() != NL80211_CMD_NEW_STATION) {
497     LOG(ERROR) << "Wrong command in response to a get station request: "
498                << static_cast<int>(response->GetCommand());
499     return false;
500   }
501   NL80211NestedAttr sta_info(0);
502   if (!response->GetAttribute(NL80211_ATTR_STA_INFO, &sta_info)) {
503     LOG(ERROR) << "Failed to get NL80211_ATTR_STA_INFO";
504     return false;
505   }
506   int32_t tx_good, tx_bad;
507   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_PACKETS, &tx_good)) {
508     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_PACKETS";
509     return false;
510   }
511   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_FAILED, &tx_bad)) {
512     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_FAILED";
513     return false;
514   }
515   int8_t current_rssi;
516   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_SIGNAL, &current_rssi)) {
517     LOG(ERROR) << "Failed to get NL80211_STA_INFO_SIGNAL";
518     return false;
519   }
520   NL80211NestedAttr tx_bitrate_attr(0);
521   uint32_t tx_bitrate = 0;
522   if (sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
523                             &tx_bitrate_attr)) {
524     if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
525                                          &tx_bitrate)) {
526       // Return invalid tx rate to avoid breaking the get station cmd
527       tx_bitrate = 0;
528     }
529   }
530   NL80211NestedAttr rx_bitrate_attr(0);
531   uint32_t rx_bitrate = 0;
532   if (sta_info.GetAttribute(NL80211_STA_INFO_RX_BITRATE,
533                             &rx_bitrate_attr)) {
534     if (!rx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
535                                          &rx_bitrate)) {
536       // Return invalid rx rate to avoid breaking the get station cmd
537       rx_bitrate = 0;
538     }
539   }
540   *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi, rx_bitrate);
541   return true;
542 }
543 
544 // This is a helper function for merging split NL80211_CMD_NEW_WIPHY packets.
545 // For example:
546 // First NL80211_CMD_NEW_WIPHY has attribute A with payload 0x1234.
547 // Second NL80211_CMD_NEW_WIPHY has attribute A with payload 0x5678.
548 // The generated NL80211_CMD_NEW_WIPHY will have attribute A with
549 // payload 0x12345678.
550 // NL80211_ATTR_WIPHY, NL80211_ATTR_IFINDEX, and NL80211_ATTR_WDEV
551 // are used for filtering packets so we know which packets should
552 // be merged together.
MergePacketsForSplitWiphyDump(const vector<unique_ptr<const NL80211Packet>> & split_dump_info,vector<NL80211Packet> * packet_per_wiphy)553 bool NetlinkUtils::MergePacketsForSplitWiphyDump(
554     const vector<unique_ptr<const NL80211Packet>>& split_dump_info,
555     vector<NL80211Packet>* packet_per_wiphy) {
556   map<uint32_t, map<int, BaseNL80211Attr>> attr_by_wiphy_and_id;
557 
558   // Construct the map using input packets.
559   for (const auto& packet : split_dump_info) {
560     uint32_t wiphy_index;
561     if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, &wiphy_index)) {
562       LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY from wiphy split dump";
563       return false;
564     }
565     vector<BaseNL80211Attr> attributes;
566     if (!packet->GetAllAttributes(&attributes)) {
567       return false;
568     }
569     for (auto& attr : attributes) {
570       int attr_id = attr.GetAttributeId();
571       if (attr_id != NL80211_ATTR_WIPHY &&
572           attr_id != NL80211_ATTR_IFINDEX &&
573               attr_id != NL80211_ATTR_WDEV) {
574           auto attr_id_and_attr =
575               attr_by_wiphy_and_id[wiphy_index].find(attr_id);
576           if (attr_id_and_attr == attr_by_wiphy_and_id[wiphy_index].end()) {
577             attr_by_wiphy_and_id[wiphy_index].
578                 insert(make_pair(attr_id, move(attr)));
579           } else {
580             attr_id_and_attr->second.Merge(attr);
581           }
582       }
583     }
584   }
585 
586   // Generate output packets using the constructed map.
587   for (const auto& wiphy_and_attributes : attr_by_wiphy_and_id) {
588     NL80211Packet new_wiphy(0, NL80211_CMD_NEW_WIPHY, 0, 0);
589     new_wiphy.AddAttribute(
590         NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_and_attributes.first));
591     for (const auto& attr : wiphy_and_attributes.second) {
592       new_wiphy.AddAttribute(attr.second);
593     }
594     packet_per_wiphy->emplace_back(move(new_wiphy));
595   }
596   return true;
597 }
598 
GetCountryCode(string * out_country_code)599 bool NetlinkUtils::GetCountryCode(string* out_country_code) {
600   NL80211Packet get_country_code(
601       netlink_manager_->GetFamilyId(),
602       NL80211_CMD_GET_REG,
603       netlink_manager_->GetSequenceNumber(),
604       getpid());
605   unique_ptr<const NL80211Packet> response;
606   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_country_code,
607                                                          &response)) {
608     LOG(ERROR) << "NL80211_CMD_GET_REG failed";
609     return false;
610   }
611   if (!response->GetAttributeValue(NL80211_ATTR_REG_ALPHA2, out_country_code)) {
612     LOG(ERROR) << "Get NL80211_ATTR_REG_ALPHA2 failed";
613     return false;
614   }
615   return true;
616 }
617 
SendMgmtFrame(uint32_t interface_index,const vector<uint8_t> & frame,int32_t mcs,uint64_t * out_cookie)618 bool NetlinkUtils::SendMgmtFrame(uint32_t interface_index,
619     const vector<uint8_t>& frame, int32_t mcs, uint64_t* out_cookie) {
620 
621   NL80211Packet send_mgmt_frame(
622       netlink_manager_->GetFamilyId(),
623       NL80211_CMD_FRAME,
624       netlink_manager_->GetSequenceNumber(),
625       getpid());
626 
627   send_mgmt_frame.AddAttribute(
628       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
629 
630   send_mgmt_frame.AddAttribute(
631       NL80211Attr<vector<uint8_t>>(NL80211_ATTR_FRAME, frame));
632 
633   if (mcs >= 0) {
634     // TODO (b/112029045) if mcs >= 0, add MCS attribute
635   }
636 
637   unique_ptr<const NL80211Packet> response;
638   if (!netlink_manager_->SendMessageAndGetSingleResponse(
639       send_mgmt_frame, &response)) {
640     LOG(ERROR) << "NL80211_CMD_FRAME failed";
641     return false;
642   }
643 
644   if (!response->GetAttributeValue(NL80211_ATTR_COOKIE, out_cookie)) {
645     LOG(ERROR) << "Get NL80211_ATTR_COOKIE failed";
646     return false;
647   }
648 
649   return true;
650 }
651 
SubscribeMlmeEvent(uint32_t interface_index,MlmeEventHandler * handler)652 void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index,
653                                       MlmeEventHandler* handler) {
654   netlink_manager_->SubscribeMlmeEvent(interface_index, handler);
655 }
656 
UnsubscribeMlmeEvent(uint32_t interface_index)657 void NetlinkUtils::UnsubscribeMlmeEvent(uint32_t interface_index) {
658   netlink_manager_->UnsubscribeMlmeEvent(interface_index);
659 }
660 
SubscribeRegDomainChange(uint32_t wiphy_index,OnRegDomainChangedHandler handler)661 void NetlinkUtils::SubscribeRegDomainChange(
662     uint32_t wiphy_index,
663     OnRegDomainChangedHandler handler) {
664   netlink_manager_->SubscribeRegDomainChange(wiphy_index, handler);
665 }
666 
UnsubscribeRegDomainChange(uint32_t wiphy_index)667 void NetlinkUtils::UnsubscribeRegDomainChange(uint32_t wiphy_index) {
668   netlink_manager_->UnsubscribeRegDomainChange(wiphy_index);
669 }
670 
SubscribeStationEvent(uint32_t interface_index,OnStationEventHandler handler)671 void NetlinkUtils::SubscribeStationEvent(uint32_t interface_index,
672                                          OnStationEventHandler handler) {
673   netlink_manager_->SubscribeStationEvent(interface_index, handler);
674 }
675 
UnsubscribeStationEvent(uint32_t interface_index)676 void NetlinkUtils::UnsubscribeStationEvent(uint32_t interface_index) {
677   netlink_manager_->UnsubscribeStationEvent(interface_index);
678 }
679 
SubscribeChannelSwitchEvent(uint32_t interface_index,OnChannelSwitchEventHandler handler)680 void NetlinkUtils::SubscribeChannelSwitchEvent(uint32_t interface_index,
681                                          OnChannelSwitchEventHandler handler) {
682   netlink_manager_->SubscribeChannelSwitchEvent(interface_index, handler);
683 }
684 
UnsubscribeChannelSwitchEvent(uint32_t interface_index)685 void NetlinkUtils::UnsubscribeChannelSwitchEvent(uint32_t interface_index) {
686   netlink_manager_->UnsubscribeChannelSwitchEvent(interface_index);
687 }
688 
SubscribeFrameTxStatusEvent(uint32_t interface_index,OnFrameTxStatusEventHandler handler)689 void NetlinkUtils::SubscribeFrameTxStatusEvent(
690     uint32_t interface_index, OnFrameTxStatusEventHandler handler) {
691   netlink_manager_->SubscribeFrameTxStatusEvent(interface_index, handler);
692 }
693 
UnsubscribeFrameTxStatusEvent(uint32_t interface_index)694 void NetlinkUtils::UnsubscribeFrameTxStatusEvent(uint32_t interface_index) {
695   netlink_manager_->UnsubscribeFrameTxStatusEvent(interface_index);
696 }
697 
698 }  // namespace wificond
699 }  // namespace android
700