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_arp.h>
20 #include <netinet/in.h>
21 #include <sys/socket.h>
22 
23 #include <linux/ethtool.h>
24 /* We need linux/if.h for flags like IFF_UP.  Sadly, it forward declares
25    struct sockaddr and must be included after sys/socket.h. */
26 #include <linux/if.h>
27 
28 #include <android-base/logging.h>
29 #include <android-base/unique_fd.h>
30 
31 namespace android {
32 namespace wifi_system {
33 namespace {
34 
35 const char kWlan0InterfaceName[] = "wlan0";
36 
GetIfState(const char * if_name,int sock,struct ifreq * ifr)37 bool GetIfState(const char* if_name, int sock, struct ifreq* ifr) {
38   memset(ifr, 0, sizeof(*ifr));
39   if (strlcpy(ifr->ifr_name, if_name, sizeof(ifr->ifr_name)) >=
40       sizeof(ifr->ifr_name)) {
41     LOG(ERROR) << "Interface name is too long: " << if_name;
42     return false;
43   }
44 
45   if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCGIFFLAGS, ifr)) != 0) {
46     LOG(ERROR) << "Could not read interface state for " << if_name
47                << " (" << strerror(errno) << ")";
48     return false;
49   }
50 
51   return true;
52 }
53 
54 }  // namespace
55 
GetUpState(const char * if_name)56 bool InterfaceTool::GetUpState(const char* if_name) {
57   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
58   if (sock.get() < 0) {
59     LOG(ERROR) << "Failed to open socket to set up/down state ("
60                << strerror(errno) << ")";
61     return false;
62   }
63 
64   struct ifreq ifr;
65   if (!GetIfState(if_name, sock.get(), &ifr)) {
66     return false;  // logging done internally
67   }
68 
69   return ifr.ifr_flags & IFF_UP;
70 }
71 
SetUpState(const char * if_name,bool request_up)72 bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
73   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
74   if (sock.get() < 0) {
75     LOG(ERROR) << "Failed to open socket to set up/down state ("
76                << strerror(errno) << ")";
77     return false;
78   }
79 
80   struct ifreq ifr;
81   if (!GetIfState(if_name, sock.get(), &ifr)) {
82     return false;  // logging done internally
83   }
84 
85   const bool currently_up = ifr.ifr_flags & IFF_UP;
86   if (currently_up == request_up) {
87     return true;
88   }
89 
90   if (request_up) {
91     ifr.ifr_flags |= IFF_UP;
92   } else {
93     ifr.ifr_flags &= ~IFF_UP;
94   }
95 
96   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
97     LOG(ERROR) << "Could not set interface flags for " << if_name
98                << " (" << strerror(errno) << ")";
99     return false;
100   }
101 
102   return true;
103 }
104 
SetWifiUpState(bool request_up)105 bool InterfaceTool::SetWifiUpState(bool request_up) {
106   return SetUpState(kWlan0InterfaceName, request_up);
107 }
108 
SetMacAddress(const char * if_name,const std::array<uint8_t,ETH_ALEN> & new_address)109 bool InterfaceTool::SetMacAddress(const char* if_name,
110     const std::array<uint8_t, ETH_ALEN>& new_address) {
111   struct ifreq ifr;
112   static_assert(ETH_ALEN <= sizeof(ifr.ifr_hwaddr.sa_data),
113     "new address is too long");
114 
115   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
116   if (sock.get() < 0) {
117     LOG(ERROR) << "Failed to open socket to set MAC address ("
118                << strerror(errno) << ")";
119     return false;
120   }
121 
122   if (!GetIfState(if_name, sock.get(), &ifr)) {
123     return false;  // logging done internally
124   }
125 
126   memset(&ifr.ifr_hwaddr, 0, sizeof(ifr.ifr_hwaddr));
127   ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
128   memcpy(ifr.ifr_hwaddr.sa_data, new_address.data(), new_address.size());
129   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFHWADDR, &ifr)) != 0) {
130     LOG(ERROR) << "Could not set interface MAC address for " << if_name
131                << " (" << strerror(errno) << ")";
132     return false;
133   }
134 
135   return true;
136 }
137 
GetFactoryMacAddress(const char * if_name)138 std::array<uint8_t, ETH_ALEN> InterfaceTool::GetFactoryMacAddress(const char* if_name) {
139   std::array<uint8_t, ETH_ALEN> paddr = {};
140   struct ifreq ifr;
141   struct ethtool_perm_addr *epaddr;
142 
143   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
144   if (sock.get() < 0) {
145     LOG(ERROR) << "Failed to open socket to get factory MAC address ("
146                << strerror(errno) << ")";
147     return paddr;
148   }
149 
150   if (!GetIfState(if_name, sock.get(), &ifr)) {
151     return paddr;  // logging done internally
152   }
153 
154   epaddr = (ethtool_perm_addr*) malloc(sizeof(struct ethtool_perm_addr) + ETH_ALEN);
155   if (!epaddr) {
156     LOG(ERROR) << "Failed to set memory for mac address ("
157                << strerror(errno) << ")";
158     return paddr;
159   }
160 
161   epaddr->cmd = ETHTOOL_GPERMADDR;
162   epaddr->size = ETH_ALEN;
163   ifr.ifr_data = epaddr;
164 
165   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCETHTOOL, &ifr)) != 0) {
166     LOG(ERROR) << "Could not get factory address MAC for " << if_name
167                << " (" << strerror(errno) << ")";
168   } else if (epaddr->size == ETH_ALEN) {
169     memcpy(paddr.data(), epaddr->data, ETH_ALEN);
170   }
171   return paddr;
172 }
173 
174 }  // namespace wifi_system
175 }  // namespace android
176