OSDN Git Service

Merge "Add function for triggering scan"
[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::vector;
32
33 namespace android {
34 namespace wificond {
35 namespace {
36
37 constexpr uint8_t kElemIdSsid = 0;
38
39 }  // namespace
40
41 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
42     : netlink_manager_(netlink_manager) {
43   if (!netlink_manager_->IsStarted()) {
44     netlink_manager_->Start();
45   }
46 }
47
48 NetlinkUtils::~NetlinkUtils() {}
49
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(),
55       getpid());
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";
60     return false;
61   }
62   if (response.empty()) {
63     LOG(ERROR) << "Unexpected empty response from kernel";
64     return false;
65   }
66   for (NL80211Packet& packet : response) {
67     if (packet.GetMessageType() == NLMSG_ERROR) {
68       LOG(ERROR) << "Receive ERROR message: "
69                  << strerror(packet.GetErrorCode());
70       return false;
71     }
72     if (packet.GetMessageType() != netlink_manager_->GetFamilyId()) {
73       LOG(ERROR) << "Wrong message type for new interface message: "
74                  << packet.GetMessageType();
75       return false;
76     }
77     if (packet.GetCommand() != NL80211_CMD_NEW_WIPHY) {
78       LOG(ERROR) << "Wrong command for new wiphy message";
79       return false;
80     }
81     if (!packet.GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) {
82       LOG(ERROR) << "Failed to get wiphy index from reply message";
83       return false;
84     }
85   }
86   return true;
87 }
88
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(),
96       getpid());
97
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";
104   }
105   if (response.empty()) {
106     LOG(ERROR) << "Unexpected empty response from kernel";
107     return false;
108   }
109   for (NL80211Packet& packet : response) {
110     if (packet.GetMessageType() == NLMSG_ERROR) {
111       LOG(ERROR) << "Receive ERROR message: "
112                  << strerror(packet.GetErrorCode());
113       return false;
114     }
115     if (packet.GetMessageType() != netlink_manager_->GetFamilyId()) {
116       LOG(ERROR) << "Wrong message type for new interface message: "
117                  << packet.GetMessageType();
118       return false;
119     }
120     if (packet.GetCommand() != NL80211_CMD_NEW_INTERFACE) {
121       LOG(ERROR) << "Wrong command for new interface message: "
122                  << packet.GetCommand();
123       return false;
124     }
125
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.
130
131     string if_name;
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
136       // IFNAME.
137       LOG(DEBUG) << "Failed to get interface name";
138       continue;
139     }
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.";
143       continue;
144     }
145
146     uint32_t if_index;
147     if (!packet.GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
148       LOG(DEBUG) << "Failed to get interface index";
149       continue;
150     }
151     *interface_name = if_name;
152     *interface_index = if_index;
153     return true;
154   }
155
156   LOG(ERROR) << "Failed to get expected interface info from kernel";
157   return false;
158 }
159
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) {
170     uint8_t type = *ptr;
171     uint8_t length = *(ptr + 1);
172     // Length field is invalid.
173     if (ptr + 1 + length >= end) {
174       return false;
175     }
176     // SSID element is found.
177     if (type == kElemIdSsid) {
178       // SSID is an empty string.
179       if (length == 0) {
180         *ssid = vector<uint8_t>();
181       } else {
182         *ssid = vector<uint8_t>(ptr + 2, ptr + length + 2);
183       }
184       return true;
185     }
186     ptr += 2 + length;
187   }
188   return false;
189 }
190
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(),
198       getpid());
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
204   // NetlinkManager.
205   trigger_scan.AddFlag(NLM_F_ACK);
206   NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
207
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]));
211   }
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]));
215   }
216
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);
223   }
224
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";
231     return false;
232   }
233   if (response.size() != 1) {
234     LOG(ERROR) << "Unexpected trigger scan response size: " <<response.size();
235   }
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) {
241       return true;
242     }
243     LOG(ERROR) << "Received error messsage in response to scan request "
244                << strerror(packet.GetErrorCode());
245   } else {
246     LOG(ERROR) << "Receive unexpected message type :"
247                << "in response to scan request: " << type;
248   }
249
250   return false;
251 }
252
253 }  // namespace wificond
254 }  // namespace android