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 "wifi_system/interface_tool.h"
18
19 #include <net/if.h>
20 #include <net/if_arp.h>
21 #include <netinet/in.h>
22 #include <sys/socket.h>
23
24 #include <linux/if_bridge.h>
25 #include <string.h>
26
27 #include <linux/ethtool.h>
28 /* We need linux/if.h for flags like IFF_UP. Sadly, it forward declares
29 struct sockaddr and must be included after sys/socket.h. */
30 #include <linux/if.h>
31
32 #include <android-base/logging.h>
33 #include <android-base/unique_fd.h>
34
35 #define IFNAMSIZ 16
36
37 namespace android {
38 namespace wifi_system {
39 namespace {
40
41 const char kWlan0InterfaceName[] = "wlan0";
42
GetIfState(const char * if_name,int sock,struct ifreq * ifr)43 bool GetIfState(const char* if_name, int sock, struct ifreq* ifr) {
44 memset(ifr, 0, sizeof(*ifr));
45 if (strlcpy(ifr->ifr_name, if_name, sizeof(ifr->ifr_name)) >=
46 sizeof(ifr->ifr_name)) {
47 LOG(ERROR) << "Interface name is too long: " << if_name;
48 return false;
49 }
50
51 if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCGIFFLAGS, ifr)) != 0) {
52 LOG(ERROR) << "Could not read interface state for " << if_name
53 << " (" << strerror(errno) << ")";
54 return false;
55 }
56
57 return true;
58 }
59
60 } // namespace
61
GetUpState(const char * if_name)62 bool InterfaceTool::GetUpState(const char* if_name) {
63 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
64 if (sock.get() < 0) {
65 LOG(ERROR) << "Failed to open socket to set up/down state ("
66 << strerror(errno) << ")";
67 return false;
68 }
69
70 struct ifreq ifr;
71 if (!GetIfState(if_name, sock.get(), &ifr)) {
72 return false; // logging done internally
73 }
74
75 return ifr.ifr_flags & IFF_UP;
76 }
77
SetUpState(const char * if_name,bool request_up)78 bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
79 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
80 if (sock.get() < 0) {
81 LOG(ERROR) << "Failed to open socket to set up/down state ("
82 << strerror(errno) << ")";
83 return false;
84 }
85
86 struct ifreq ifr;
87 if (!GetIfState(if_name, sock.get(), &ifr)) {
88 return false; // logging done internally
89 }
90
91 const bool currently_up = ifr.ifr_flags & IFF_UP;
92 if (currently_up == request_up) {
93 return true;
94 }
95
96 if (request_up) {
97 ifr.ifr_flags |= IFF_UP;
98 } else {
99 ifr.ifr_flags &= ~IFF_UP;
100 }
101
102 if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
103 LOG(ERROR) << "Could not set interface flags for " << if_name
104 << " (" << strerror(errno) << ")";
105 return false;
106 }
107
108 return true;
109 }
110
SetWifiUpState(bool request_up)111 bool InterfaceTool::SetWifiUpState(bool request_up) {
112 return SetUpState(kWlan0InterfaceName, request_up);
113 }
114
SetMacAddress(const char * if_name,const std::array<uint8_t,ETH_ALEN> & new_address)115 bool InterfaceTool::SetMacAddress(const char* if_name,
116 const std::array<uint8_t, ETH_ALEN>& new_address) {
117 struct ifreq ifr;
118 static_assert(ETH_ALEN <= sizeof(ifr.ifr_hwaddr.sa_data),
119 "new address is too long");
120
121 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
122 if (sock.get() < 0) {
123 LOG(ERROR) << "Failed to open socket to set MAC address ("
124 << strerror(errno) << ")";
125 return false;
126 }
127
128 if (!GetIfState(if_name, sock.get(), &ifr)) {
129 return false; // logging done internally
130 }
131
132 memset(&ifr.ifr_hwaddr, 0, sizeof(ifr.ifr_hwaddr));
133 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
134 memcpy(ifr.ifr_hwaddr.sa_data, new_address.data(), new_address.size());
135 if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFHWADDR, &ifr)) != 0) {
136 LOG(ERROR) << "Could not set interface MAC address for " << if_name
137 << " (" << strerror(errno) << ")";
138 return false;
139 }
140
141 return true;
142 }
143
GetFactoryMacAddress(const char * if_name)144 std::array<uint8_t, ETH_ALEN> InterfaceTool::GetFactoryMacAddress(const char* if_name) {
145 std::array<uint8_t, ETH_ALEN> paddr = {};
146 struct ifreq ifr;
147 struct {
148 // Allocate ETH_ALEN bytes after ethtool_perm_addr.
149 struct ethtool_perm_addr epaddr;
150 uint8_t data[ETH_ALEN];
151 } epaddr_buf;
152 struct ethtool_perm_addr* epaddr = &epaddr_buf.epaddr;
153
154 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
155 if (sock.get() < 0) {
156 LOG(ERROR) << "Failed to open socket to get factory MAC address ("
157 << strerror(errno) << ")";
158 return paddr;
159 }
160
161 if (!GetIfState(if_name, sock.get(), &ifr)) {
162 return paddr; // logging done internally
163 }
164
165 epaddr->cmd = ETHTOOL_GPERMADDR;
166 epaddr->size = ETH_ALEN;
167 ifr.ifr_data = epaddr;
168
169 if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCETHTOOL, &ifr)) != 0) {
170 LOG(ERROR) << "Could not get factory address MAC for " << if_name
171 << " (" << strerror(errno) << ")";
172 } else if (epaddr->size == ETH_ALEN) {
173 memcpy(paddr.data(), epaddr->data, ETH_ALEN);
174 }
175 return paddr;
176 }
177
createBridge(const std::string & br_name)178 bool InterfaceTool::createBridge(const std::string& br_name) {
179 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
180
181 if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCBRADDBR, br_name.c_str())) != 0) {
182 LOG(ERROR) << "Could not add bridge " << br_name.c_str()
183 << " (" << strerror(errno) << ")";
184 return false;
185 }
186
187 return true;
188 }
189
deleteBridge(const std::string & br_name)190 bool InterfaceTool::deleteBridge(const std::string& br_name) {
191 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
192
193 if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCBRDELBR, br_name.c_str())) != 0) {
194 LOG(ERROR) << "Could not remove bridge " << br_name.c_str()
195 << " (" << strerror(errno) << ")";
196 return false;
197 }
198 return true;
199 }
200
addIfaceToBridge(const std::string & br_name,const std::string & if_name)201 bool InterfaceTool::addIfaceToBridge(const std::string& br_name, const std::string& if_name) {
202 struct ifreq ifr;
203 memset(&ifr, 0, sizeof(ifr));
204
205 ifr.ifr_ifindex = if_nametoindex(if_name.c_str());
206 if (ifr.ifr_ifindex == 0) {
207 LOG(ERROR) << "Interface is not exist: " << if_name.c_str();
208 return false;
209 }
210 strlcpy(ifr.ifr_name, br_name.c_str(), IFNAMSIZ);
211
212 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
213 if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCBRADDIF, &ifr)) != 0) {
214 LOG(ERROR) << "Could not add interface " << if_name.c_str()
215 << " into bridge " << ifr.ifr_name
216 << " (" << strerror(errno) << ")";
217 return false;
218 }
219 return true;
220 }
221
removeIfaceFromBridge(const std::string & br_name,const std::string & if_name)222 bool InterfaceTool::removeIfaceFromBridge(const std::string& br_name, const std::string& if_name) {
223 struct ifreq ifr;
224 memset(&ifr, 0, sizeof(ifr));
225
226 ifr.ifr_ifindex = if_nametoindex(if_name.c_str());
227 if (ifr.ifr_ifindex == 0) {
228 LOG(ERROR) << "Interface is not exist: " << if_name.c_str();
229 return false;
230 }
231 strlcpy(ifr.ifr_name, br_name.c_str(), IFNAMSIZ);
232
233 base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
234 if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCBRDELIF, &ifr)) != 0) {
235 LOG(ERROR) << "Could not remove interface " << if_name.c_str()
236 << " from bridge " << ifr.ifr_name
237 << " (" << strerror(errno) << ")";
238 return false;
239 }
240
241 return true;
242 }
243 } // namespace wifi_system
244 } // namespace android
245