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