2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "wificond/net/netlink_utils.h"
22 #include <linux/netlink.h>
23 #include <linux/nl80211.h>
25 #include <android-base/logging.h>
27 #include "wificond/net/netlink_manager.h"
28 #include "wificond/net/nl80211_packet.h"
31 using std::unique_ptr;
39 uint32_t k2GHzFrequencyLowerBound = 2400;
40 uint32_t k2GHzFrequencyUpperBound = 2500;
43 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
44 : netlink_manager_(netlink_manager) {
45 if (!netlink_manager_->IsStarted()) {
46 netlink_manager_->Start();
50 NetlinkUtils::~NetlinkUtils() {}
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(),
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";
64 if (response.empty()) {
65 LOG(DEBUG) << "No wiphy is found";
68 for (auto& packet : response) {
69 if (packet->GetMessageType() == NLMSG_ERROR) {
70 LOG(ERROR) << "Receive ERROR message: "
71 << strerror(packet->GetErrorCode());
74 if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
75 LOG(ERROR) << "Wrong message type for new interface message: "
76 << packet->GetMessageType();
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());
85 if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) {
86 LOG(ERROR) << "Failed to get wiphy index from reply message";
93 bool NetlinkUtils::GetInterfaceInfo(uint32_t wiphy_index,
96 vector<uint8_t>* mac_addr) {
97 NL80211Packet get_interface(
98 netlink_manager_->GetFamilyId(),
99 NL80211_CMD_GET_INTERFACE,
100 netlink_manager_->GetSequenceNumber(),
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";
111 if (response.empty()) {
112 LOG(ERROR) << "No interface is found";
115 for (auto& packet : response) {
116 if (packet->GetMessageType() == NLMSG_ERROR) {
117 LOG(ERROR) << "Receive ERROR message: "
118 << strerror(packet->GetErrorCode());
121 if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
122 LOG(ERROR) << "Wrong message type for new interface message: "
123 << packet->GetMessageType();
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());
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.
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
144 LOG(DEBUG) << "Failed to get interface name";
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.";
154 if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
155 LOG(DEBUG) << "Failed to get interface index";
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";
167 *mac_addr = if_mac_addr;
171 LOG(ERROR) << "Failed to get expected interface info from kernel";
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(),
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,
189 LOG(ERROR) << "Failed to get scan capabilities";
192 if (response->GetMessageType() == NLMSG_ERROR) {
193 LOG(ERROR) << "Receive ERROR message: "
194 << strerror(response->GetErrorCode()) << "in response to a GetWiphy request";
197 if (response->GetCommand() != NL80211_CMD_NEW_WIPHY) {
198 LOG(ERROR) << "Wrong command in response to a get wiphy request: "
199 << static_cast<int>(response->GetCommand());
202 if (!ParseBandInfo(response.get(), out_band_info) ||
203 !ParseScanCapabilities(response.get(), out_scan_capabilities)) {
209 bool NetlinkUtils::ParseScanCapabilities(
210 const NL80211Packet* const packet,
211 ScanCapabilities* out_scan_capabilities) {
212 uint8_t max_num_scan_ssids;
213 if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
214 &max_num_scan_ssids)) {
215 LOG(ERROR) << "Failed to get the capacity of maximum number of scan ssids";
219 uint8_t max_num_sched_scan_ssids;
220 if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
221 &max_num_sched_scan_ssids)) {
222 LOG(ERROR) << "Failed to get the capacity of "
223 << "maximum number of scheduled scan ssids";
227 uint8_t max_match_sets;
228 if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
230 LOG(ERROR) << "Failed to get the capacity of maximum number of match set"
231 << "of a scheduled scan";
234 *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
235 max_num_sched_scan_ssids,
240 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
241 BandInfo* out_band_info) {
243 NL80211NestedAttr bands_attr(0);
244 if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) {
245 LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS";
248 vector<NL80211NestedAttr> bands;
249 if (!bands_attr.GetListOfNestedAttributes(&bands)) {
250 LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS";
253 vector<uint32_t> frequencies_2g;
254 vector<uint32_t> frequencies_5g;
255 vector<uint32_t> frequencies_dfs;
256 for (unsigned int band_index = 0; band_index < bands.size(); band_index++) {
257 NL80211NestedAttr freqs_attr(0);
258 if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
259 LOG(ERROR) << "Failed to get NL80211_BAND_ATTR_FREQS";
262 vector<NL80211NestedAttr> freqs;
263 if (!freqs_attr.GetListOfNestedAttributes(&freqs)) {
264 LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS";
267 for (auto& freq : freqs) {
268 uint32_t frequency_value;
269 if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
271 LOG(ERROR) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ";
274 // Channel is disabled in current regulatory domain.
275 if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) {
278 // If this is an available/usable DFS frequency, we should save it to
279 // DFS frequencies list.
281 if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE,
283 (dfs_state == NL80211_DFS_AVAILABLE ||
284 dfs_state == NL80211_DFS_USABLE)) {
285 frequencies_dfs.push_back(frequency_value);
287 // Since there is no guarantee for the order of band attributes,
288 // we do some math here.
289 if (frequency_value > k2GHzFrequencyLowerBound &&
290 frequency_value < k2GHzFrequencyUpperBound ) {
291 frequencies_2g.push_back(frequency_value);
293 frequencies_5g.push_back(frequency_value);
298 *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs);
302 } // namespace wificond
303 } // namespace android