OSDN Git Service

6534f17ac5a5d5d20e87ba5e2debe426d9ba4979
[android-x86/system-connectivity-wificond.git] / net / netlink_utils.cpp
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/netlink_manager.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) << "Failed to get wiphy index";
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::GetInterfaceInfo(uint32_t wiphy_index,
94                                     string* name,
95                                     uint32_t* index,
96                                     vector<uint8_t>* mac_addr) {
97   NL80211Packet get_interface(
98       netlink_manager_->GetFamilyId(),
99       NL80211_CMD_GET_INTERFACE,
100       netlink_manager_->GetSequenceNumber(),
101       getpid());
102
103   get_interface.AddFlag(NLM_F_DUMP);
104   NL80211Attr<uint32_t> wiphy(NL80211_ATTR_WIPHY, wiphy_index);
105   get_interface.AddAttribute(wiphy);
106   vector<unique_ptr<const NL80211Packet>> response;
107   if (!netlink_manager_->SendMessageAndGetResponses(get_interface, &response)) {
108     LOG(ERROR) << "Failed to send GetWiphy message";
109     return false;
110   }
111   if (response.empty()) {
112     LOG(ERROR) << "No interface is found";
113     return false;
114   }
115   for (auto& packet : response) {
116     if (packet->GetMessageType() == NLMSG_ERROR) {
117       LOG(ERROR) << "Receive ERROR message: "
118                  << strerror(packet->GetErrorCode());
119       return false;
120     }
121     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
122       LOG(ERROR) << "Wrong message type for new interface message: "
123                  << packet->GetMessageType();
124       return false;
125     }
126     if (packet->GetCommand() != NL80211_CMD_NEW_INTERFACE) {
127       LOG(ERROR) << "Wrong command in response to "
128                  << "an interface dump request: "
129                  << static_cast<int>(packet->GetCommand());
130       return false;
131     }
132
133     // Today we don't check NL80211_ATTR_IFTYPE because at this point of time
134     // driver always reports that interface is in STATION mode. Even when we
135     // are asking interfaces infomation on behalf of tethering, it is still so
136     // because hostapd is supposed to set interface to AP mode later.
137
138     string if_name;
139     if (!packet->GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) {
140       // In some situations, it has been observed that the kernel tells us
141       // about a pseudo-device that does not have a real netdev.  In this
142       // case, responses will have a NL80211_ATTR_WDEV, and not the expected
143       // IFNAME.
144       LOG(DEBUG) << "Failed to get interface name";
145       continue;
146     }
147     if (if_name == "p2p0") {
148       LOG(DEBUG) << "Driver may tell a lie that p2p0 is in STATION mode,"
149                  <<" we need to blacklist it.";
150       continue;
151     }
152
153     uint32_t if_index;
154     if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
155       LOG(DEBUG) << "Failed to get interface index";
156       continue;
157     }
158
159     vector<uint8_t> if_mac_addr;
160     if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) {
161       LOG(DEBUG) << "Failed to get interface mac address";
162       continue;
163     }
164
165     *name = if_name;
166     *index = if_index;
167     *mac_addr = if_mac_addr;
168     return true;
169   }
170
171   LOG(ERROR) << "Failed to get expected interface info from kernel";
172   return false;
173 }
174
175
176 bool NetlinkUtils::GetWiphyInfo(
177     uint32_t wiphy_index,
178     BandInfo* out_band_info,
179     ScanCapabilities* out_scan_capabilities) {
180   NL80211Packet get_wiphy(
181       netlink_manager_->GetFamilyId(),
182       NL80211_CMD_GET_WIPHY,
183       netlink_manager_->GetSequenceNumber(),
184       getpid());
185   get_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
186   unique_ptr<const NL80211Packet> response;
187   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_wiphy,
188                                                          &response)) {
189     LOG(ERROR) << "Failed to get scan capabilities";
190     return false;
191   }
192   if (response->GetMessageType() == NLMSG_ERROR) {
193     LOG(ERROR) << "Receive ERROR message: "
194                << strerror(response->GetErrorCode())
195                << "in response to a GetWiphy request";
196     return false;
197   }
198   if (response->GetCommand() != NL80211_CMD_NEW_WIPHY) {
199     LOG(ERROR) << "Wrong command in response to a get wiphy request: "
200                << static_cast<int>(response->GetCommand());
201     return false;
202   }
203   if (!ParseBandInfo(response.get(), out_band_info) ||
204       !ParseScanCapabilities(response.get(), out_scan_capabilities)) {
205     return false;
206   }
207   return true;
208 }
209
210 bool NetlinkUtils::ParseScanCapabilities(
211     const NL80211Packet* const packet,
212     ScanCapabilities* out_scan_capabilities) {
213   uint8_t max_num_scan_ssids;
214   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
215                                    &max_num_scan_ssids)) {
216     LOG(ERROR) << "Failed to get the capacity of maximum number of scan ssids";
217     return false;
218   }
219
220   uint8_t max_num_sched_scan_ssids;
221   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
222                                  &max_num_sched_scan_ssids)) {
223     LOG(ERROR) << "Failed to get the capacity of "
224                << "maximum number of scheduled scan ssids";
225     return false;
226   }
227
228   uint8_t max_match_sets;
229   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
230                                    &max_match_sets)) {
231     LOG(ERROR) << "Failed to get the capacity of maximum number of match set"
232                << "of a scheduled scan";
233     return false;
234   }
235   *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
236                                             max_num_sched_scan_ssids,
237                                             max_match_sets);
238   return true;
239 }
240
241 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
242                                  BandInfo* out_band_info) {
243
244   NL80211NestedAttr bands_attr(0);
245   if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) {
246     LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS";
247     return false;
248   }
249   vector<NL80211NestedAttr> bands;
250   if (!bands_attr.GetListOfNestedAttributes(&bands)) {
251     LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS";
252     return false;
253   }
254   vector<uint32_t> frequencies_2g;
255   vector<uint32_t> frequencies_5g;
256   vector<uint32_t> frequencies_dfs;
257   for (unsigned int band_index = 0; band_index < bands.size(); band_index++) {
258     NL80211NestedAttr freqs_attr(0);
259     if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
260       LOG(ERROR) << "Failed to get NL80211_BAND_ATTR_FREQS";
261       continue;
262     }
263     vector<NL80211NestedAttr> freqs;
264     if (!freqs_attr.GetListOfNestedAttributes(&freqs)) {
265       LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS";
266       continue;
267     }
268     for (auto& freq : freqs) {
269       uint32_t frequency_value;
270       if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
271                                   &frequency_value)) {
272         LOG(ERROR) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ";
273         continue;
274       }
275       // Channel is disabled in current regulatory domain.
276       if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) {
277         continue;
278       }
279       // If this is an available/usable DFS frequency, we should save it to
280       // DFS frequencies list.
281       uint32_t dfs_state;
282       if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE,
283                                  &dfs_state) &&
284           (dfs_state == NL80211_DFS_AVAILABLE ||
285                dfs_state == NL80211_DFS_USABLE)) {
286         frequencies_dfs.push_back(frequency_value);
287       } else {
288         // Since there is no guarantee for the order of band attributes,
289         // we do some math here.
290         if (frequency_value > k2GHzFrequencyLowerBound &&
291             frequency_value < k2GHzFrequencyUpperBound) {
292           frequencies_2g.push_back(frequency_value);
293         } else {
294           frequencies_5g.push_back(frequency_value);
295         }
296       }
297     }
298   }
299   *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs);
300   return true;
301 }
302
303 bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
304                                   const vector<uint8_t>& mac_address,
305                                   StationInfo* out_station_info) {
306   NL80211Packet get_station(
307       netlink_manager_->GetFamilyId(),
308       NL80211_CMD_GET_STATION,
309       netlink_manager_->GetSequenceNumber(),
310       getpid());
311   get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX,
312                                                  interface_index));
313   get_station.AddAttribute(NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC,
314                                                         mac_address));
315
316   unique_ptr<const NL80211Packet> response;
317   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station,
318                                                          &response)) {
319     LOG(ERROR) << "Failed to get packet counters";
320     return false;
321   }
322   if (response->GetMessageType() == NLMSG_ERROR) {
323     LOG(ERROR) << "Receive ERROR message: "
324                << strerror(response->GetErrorCode())
325                << "in response to a get station request";
326     return false;
327   }
328
329   if (response->GetCommand() != NL80211_CMD_NEW_STATION) {
330     LOG(ERROR) << "Wrong command in response to a get station request: "
331                << static_cast<int>(response->GetCommand());
332     return false;
333   }
334   NL80211NestedAttr sta_info(0);
335   if (!response->GetAttribute(NL80211_ATTR_STA_INFO, &sta_info)) {
336     LOG(ERROR) << "Failed to get NL80211_ATTR_STA_INFO";
337     return false;
338   }
339   int32_t tx_good, tx_bad;
340   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_PACKETS, &tx_good)) {
341     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_PACKETS";
342     return false;
343   }
344   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_FAILED, &tx_bad)) {
345     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_FAILED";
346     return false;
347   }
348   int8_t current_rssi;
349   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_SIGNAL, &current_rssi)) {
350     LOG(ERROR) << "Failed to get NL80211_STA_INFO_SIGNAL";
351     return false;
352   }
353   NL80211NestedAttr tx_bitrate_attr(0);
354   if (!sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
355                             &tx_bitrate_attr)) {
356     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_BITRATE";
357     return false;
358   }
359   uint32_t tx_bitrate;
360   if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
361                                          &tx_bitrate)) {
362     LOG(ERROR) << "Failed to get NL80211_RATE_INFO_BITRATE32";
363     return false;
364   }
365
366   *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi);
367   return true;
368 }
369
370 }  // namespace wificond
371 }  // namespace android