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 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 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 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 104 bool InterfaceTool::SetWifiUpState(bool request_up) { 105 return SetUpState(kWlan0InterfaceName, request_up); 106 } 107 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