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"
37 constexpr uint8_t kElemIdSsid = 0;
41 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
42 : netlink_manager_(netlink_manager) {
43 if (!netlink_manager_->IsStarted()) {
44 netlink_manager_->Start();
48 NetlinkUtils::~NetlinkUtils() {}
50 bool NetlinkUtils::GetWiphyIndex(uint32_t* out_wiphy_index) {
51 NL80211Packet get_wiphy(
52 netlink_manager_->GetFamilyId(),
53 NL80211_CMD_GET_WIPHY,
54 netlink_manager_->GetSequenceNumber(),
56 get_wiphy.AddFlag(NLM_F_DUMP);
57 vector<NL80211Packet> response;
58 if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response)) {
59 LOG(ERROR) << "Failed to get wiphy index";
62 if (response.empty()) {
63 LOG(ERROR) << "Unexpected empty response from kernel";
66 for (NL80211Packet& packet : response) {
67 if (packet.GetMessageType() == NLMSG_ERROR) {
68 LOG(ERROR) << "Receive ERROR message: "
69 << strerror(packet.GetErrorCode());
72 if (packet.GetMessageType() != netlink_manager_->GetFamilyId()) {
73 LOG(ERROR) << "Wrong message type for new interface message: "
74 << packet.GetMessageType();
77 if (packet.GetCommand() != NL80211_CMD_NEW_WIPHY) {
78 LOG(ERROR) << "Wrong command for new wiphy message";
81 if (!packet.GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) {
82 LOG(ERROR) << "Failed to get wiphy index from reply message";
89 bool NetlinkUtils::GetInterfaceNameAndIndex(uint32_t wiphy_index,
90 string* interface_name,
91 uint32_t* interface_index) {
92 NL80211Packet get_interface(
93 netlink_manager_->GetFamilyId(),
94 NL80211_CMD_GET_INTERFACE,
95 netlink_manager_->GetSequenceNumber(),
98 get_interface.AddFlag(NLM_F_DUMP);
99 NL80211Attr<uint32_t> wiphy(NL80211_ATTR_WIPHY, wiphy_index);
100 get_interface.AddAttribute(wiphy);
101 vector<NL80211Packet> response;
102 if (!netlink_manager_->SendMessageAndGetResponses(get_interface, &response)) {
103 LOG(ERROR) << "Failed to send GetWiphy message";
105 if (response.empty()) {
106 LOG(ERROR) << "Unexpected empty response from kernel";
109 for (NL80211Packet& packet : response) {
110 if (packet.GetMessageType() == NLMSG_ERROR) {
111 LOG(ERROR) << "Receive ERROR message: "
112 << strerror(packet.GetErrorCode());
115 if (packet.GetMessageType() != netlink_manager_->GetFamilyId()) {
116 LOG(ERROR) << "Wrong message type for new interface message: "
117 << packet.GetMessageType();
120 if (packet.GetCommand() != NL80211_CMD_NEW_INTERFACE) {
121 LOG(ERROR) << "Wrong command for new interface message: "
122 << packet.GetCommand();
126 // Today we don't check NL80211_ATTR_IFTYPE because at this point of time
127 // driver always reports that interface is in STATION mode. Even when we
128 // are asking interfaces infomation on behalf of tethering, it is still so
129 // because hostapd is supposed to set interface to AP mode later.
132 if (!packet.GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) {
133 // In some situations, it has been observed that the kernel tells us
134 // about a pseudo-device that does not have a real netdev. In this
135 // case, responses will have a NL80211_ATTR_WDEV, and not the expected
137 LOG(DEBUG) << "Failed to get interface name";
140 if (if_name == "p2p0") {
141 LOG(DEBUG) << "Driver may tell a lie that p2p0 is in STATION mode,"
142 <<" we need to blacklist it.";
147 if (!packet.GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
148 LOG(DEBUG) << "Failed to get interface index";
151 *interface_name = if_name;
152 *interface_index = if_index;
156 LOG(ERROR) << "Failed to get expected interface info from kernel";
160 bool NetlinkUtils::GetSSIDFromInfoElement(const vector<uint8_t>& ie,
161 vector<uint8_t>* ssid) {
162 // Information elements are stored in 'TLV' format.
163 // Field: | Type | Length | Value |
164 // Length: | 1 | 1 | variable |
165 // Content:| Element ID | Length of the Value field | Element payload |
166 const uint8_t* end = ie.data() + ie.size();
167 const uint8_t* ptr = ie.data();
168 // +1 means we must have space for the length field.
169 while (ptr + 1 < end) {
171 uint8_t length = *(ptr + 1);
172 // Length field is invalid.
173 if (ptr + 1 + length >= end) {
176 // SSID element is found.
177 if (type == kElemIdSsid) {
178 // SSID is an empty string.
180 *ssid = vector<uint8_t>();
182 *ssid = vector<uint8_t>(ptr + 2, ptr + length + 2);
191 bool NetlinkUtils::Scan(uint32_t interface_index,
192 const vector<vector<uint8_t>>& ssids,
193 const vector<uint32_t>& freqs) {
194 NL80211Packet trigger_scan(
195 netlink_manager_->GetFamilyId(),
196 NL80211_CMD_TRIGGER_SCAN,
197 netlink_manager_->GetSequenceNumber(),
199 // If we do not use NLM_F_ACK, we only receive a unicast repsonse
200 // when there is an error. If everything is good, scan results notification
201 // will only be sent through multicast.
202 // If NLM_F_ACK is set, there will always be an unicast repsonse, either an
203 // ERROR or an ACK message. The handler will always be called and removed by
205 trigger_scan.AddFlag(NLM_F_ACK);
206 NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
208 NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
209 for (size_t i = 0; i < ssids.size(); i++) {
210 ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
212 NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
213 for (size_t i = 0; i < freqs.size(); i++) {
214 freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
217 trigger_scan.AddAttribute(if_index_attr);
218 trigger_scan.AddAttribute(ssids_attr);
219 // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
220 // scan all supported frequencies.
221 if (!freqs.empty()) {
222 trigger_scan.AddAttribute(freqs_attr);
225 // We are receiving an ERROR/ACK message instead of the actual
226 // scan results here, so it is OK to expect a timely response because
227 // kernel is supposed to send the ERROR/ACK back before the scan starts.
228 vector<NL80211Packet> response;
229 if (!netlink_manager_->SendMessageAndGetResponses(trigger_scan, &response)) {
230 LOG(ERROR) << "Failed to send TriggerScan message";
233 if (response.size() != 1) {
234 LOG(ERROR) << "Unexpected trigger scan response size: " <<response.size();
236 NL80211Packet& packet = response[0];
237 uint16_t type = packet.GetMessageType();
238 if (type == NLMSG_ERROR) {
239 // It is an ACK message if error code is 0.
240 if (packet.GetErrorCode() == 0) {
243 LOG(ERROR) << "Received error messsage in response to scan request "
244 << strerror(packet.GetErrorCode());
246 LOG(ERROR) << "Receive unexpected message type :"
247 << "in response to scan request: " << type;
253 } // namespace wificond
254 } // namespace android