interface_tool.cpp revision c60674412a64bc43733404628d840ce0cde35e60
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
30namespace android {
31namespace wifi_system {
32namespace {
33
34const char kWlan0InterfaceName[] = "wlan0";
35
36bool 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
55bool 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
71bool 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
104bool InterfaceTool::SetWifiUpState(bool request_up) {
105  return SetUpState(kWlan0InterfaceName, request_up);
106}
107
108bool 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