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
NetlinkUtils(NetlinkManager * netlink_manager)43 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
44     : netlink_manager_(netlink_manager) {
45   if (!netlink_manager_->IsStarted()) {
46     netlink_manager_->Start();
47   }
48 }
49 
~NetlinkUtils()50 NetlinkUtils::~NetlinkUtils() {}
51 
GetWiphyIndex(uint32_t * out_wiphy_index)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 
GetInterfaces(uint32_t wiphy_index,vector<InterfaceInfo> * interface_info)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 
SetInterfaceMode(uint32_t interface_index,InterfaceMode mode)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 
GetWiphyInfo(uint32_t wiphy_index,BandInfo * out_band_info,ScanCapabilities * out_scan_capabilities,WiphyFeatures * out_wiphy_features)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 
ParseScanCapabilities(const NL80211Packet * const packet,ScanCapabilities * out_scan_capabilities)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   uint8_t max_match_sets;
250   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
251                                    &max_match_sets)) {
252     LOG(ERROR) << "Failed to get the capacity of maximum number of match set"
253                << "of a scheduled scan";
254     return false;
255   }
256   *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
257                                             max_num_sched_scan_ssids,
258                                             max_match_sets);
259   return true;
260 }
261 
ParseBandInfo(const NL80211Packet * const packet,BandInfo * out_band_info)262 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
263                                  BandInfo* out_band_info) {
264 
265   NL80211NestedAttr bands_attr(0);
266   if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) {
267     LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS";
268     return false;
269   }
270   vector<NL80211NestedAttr> bands;
271   if (!bands_attr.GetListOfNestedAttributes(&bands)) {
272     LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS";
273     return false;
274   }
275   vector<uint32_t> frequencies_2g;
276   vector<uint32_t> frequencies_5g;
277   vector<uint32_t> frequencies_dfs;
278   for (unsigned int band_index = 0; band_index < bands.size(); band_index++) {
279     NL80211NestedAttr freqs_attr(0);
280     if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
281       LOG(DEBUG) << "Failed to get NL80211_BAND_ATTR_FREQS";
282       continue;
283     }
284     vector<NL80211NestedAttr> freqs;
285     if (!freqs_attr.GetListOfNestedAttributes(&freqs)) {
286       LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS";
287       continue;
288     }
289     for (auto& freq : freqs) {
290       uint32_t frequency_value;
291       if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
292                                   &frequency_value)) {
293         LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ";
294         continue;
295       }
296       // Channel is disabled in current regulatory domain.
297       if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) {
298         continue;
299       }
300       // If this is an available/usable DFS frequency, we should save it to
301       // DFS frequencies list.
302       uint32_t dfs_state;
303       if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE,
304                                  &dfs_state) &&
305           (dfs_state == NL80211_DFS_AVAILABLE ||
306                dfs_state == NL80211_DFS_USABLE)) {
307         frequencies_dfs.push_back(frequency_value);
308       } else {
309         // Since there is no guarantee for the order of band attributes,
310         // we do some math here.
311         if (frequency_value > k2GHzFrequencyLowerBound &&
312             frequency_value < k2GHzFrequencyUpperBound) {
313           frequencies_2g.push_back(frequency_value);
314         } else {
315           frequencies_5g.push_back(frequency_value);
316         }
317       }
318     }
319   }
320   *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs);
321   return true;
322 }
323 
GetStationInfo(uint32_t interface_index,const vector<uint8_t> & mac_address,StationInfo * out_station_info)324 bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
325                                   const vector<uint8_t>& mac_address,
326                                   StationInfo* out_station_info) {
327   NL80211Packet get_station(
328       netlink_manager_->GetFamilyId(),
329       NL80211_CMD_GET_STATION,
330       netlink_manager_->GetSequenceNumber(),
331       getpid());
332   get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX,
333                                                  interface_index));
334   get_station.AddAttribute(NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC,
335                                                         mac_address));
336 
337   unique_ptr<const NL80211Packet> response;
338   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station,
339                                                          &response)) {
340     LOG(ERROR) << "NL80211_CMD_GET_STATION failed";
341     return false;
342   }
343   if (response->GetCommand() != NL80211_CMD_NEW_STATION) {
344     LOG(ERROR) << "Wrong command in response to a get station request: "
345                << static_cast<int>(response->GetCommand());
346     return false;
347   }
348   NL80211NestedAttr sta_info(0);
349   if (!response->GetAttribute(NL80211_ATTR_STA_INFO, &sta_info)) {
350     LOG(ERROR) << "Failed to get NL80211_ATTR_STA_INFO";
351     return false;
352   }
353   int32_t tx_good, tx_bad;
354   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_PACKETS, &tx_good)) {
355     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_PACKETS";
356     return false;
357   }
358   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_FAILED, &tx_bad)) {
359     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_FAILED";
360     return false;
361   }
362   int8_t current_rssi;
363   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_SIGNAL, &current_rssi)) {
364     LOG(ERROR) << "Failed to get NL80211_STA_INFO_SIGNAL";
365     return false;
366   }
367   NL80211NestedAttr tx_bitrate_attr(0);
368   if (!sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
369                             &tx_bitrate_attr)) {
370     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_BITRATE";
371     return false;
372   }
373   uint32_t tx_bitrate;
374   if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
375                                          &tx_bitrate)) {
376     LOG(ERROR) << "Failed to get NL80211_RATE_INFO_BITRATE32";
377     return false;
378   }
379 
380   *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi);
381   return true;
382 }
383 
SubscribeMlmeEvent(uint32_t interface_index,MlmeEventHandler * handler)384 void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index,
385                                       MlmeEventHandler* handler) {
386   netlink_manager_->SubscribeMlmeEvent(interface_index, handler);
387 }
388 
UnsubscribeMlmeEvent(uint32_t interface_index)389 void NetlinkUtils::UnsubscribeMlmeEvent(uint32_t interface_index) {
390   netlink_manager_->UnsubscribeMlmeEvent(interface_index);
391 }
392 
SubscribeRegDomainChange(uint32_t wiphy_index,OnRegDomainChangedHandler handler)393 void NetlinkUtils::SubscribeRegDomainChange(
394     uint32_t wiphy_index,
395     OnRegDomainChangedHandler handler) {
396   netlink_manager_->SubscribeRegDomainChange(wiphy_index, handler);
397 }
398 
UnsubscribeRegDomainChange(uint32_t wiphy_index)399 void NetlinkUtils::UnsubscribeRegDomainChange(uint32_t wiphy_index) {
400   netlink_manager_->UnsubscribeRegDomainChange(wiphy_index);
401 }
402 
SubscribeStationEvent(uint32_t interface_index,OnStationEventHandler handler)403 void NetlinkUtils::SubscribeStationEvent(uint32_t interface_index,
404                                          OnStationEventHandler handler) {
405   netlink_manager_->SubscribeStationEvent(interface_index, handler);
406 }
407 
UnsubscribeStationEvent(uint32_t interface_index)408 void NetlinkUtils::UnsubscribeStationEvent(uint32_t interface_index) {
409   netlink_manager_->UnsubscribeStationEvent(interface_index);
410 }
411 
412 }  // namespace wificond
413 }  // namespace android
414