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, ¤t_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