• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, 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 "interface.h"
18 
19 #include <errno.h>
20 #include <linux/if.h>
21 #include <linux/if_ether.h>
22 #include <linux/route.h>
23 #include <string.h>
24 #include <unistd.h>
25 
Interface()26 Interface::Interface() : mSocketFd(-1) {
27 }
28 
~Interface()29 Interface::~Interface() {
30     if (mSocketFd != -1) {
31         close(mSocketFd);
32         mSocketFd = -1;
33     }
34 }
35 
init(const char * interfaceName)36 Result Interface::init(const char* interfaceName) {
37     mInterfaceName = interfaceName;
38 
39     if (mSocketFd != -1) {
40         return Result::error("Interface initialized more than once");
41     }
42 
43     mSocketFd = ::socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP);
44     if (mSocketFd == -1) {
45         return Result::error("Failed to create interface socket for '%s': %s",
46                              interfaceName, strerror(errno));
47     }
48 
49     Result res = populateIndex();
50     if (!res) {
51         return res;
52     }
53 
54     res = populateMacAddress();
55     if (!res) {
56         return res;
57     }
58 
59     res = bringUp();
60     if (!res) {
61         return res;
62     }
63 
64     res = setAddress(0);
65     if (!res) {
66         return res;
67     }
68 
69     return Result::success();
70 }
71 
bringUp()72 Result Interface::bringUp() {
73     return setInterfaceUp(true);
74 }
75 
bringDown()76 Result Interface::bringDown() {
77     return setInterfaceUp(false);
78 }
79 
setMtu(uint16_t mtu)80 Result Interface::setMtu(uint16_t mtu) {
81     struct ifreq request = createRequest();
82 
83     strncpy(request.ifr_name, mInterfaceName.c_str(), sizeof(request.ifr_name));
84     request.ifr_mtu = mtu;
85     int status = ::ioctl(mSocketFd, SIOCSIFMTU, &request);
86     if (status != 0) {
87         return Result::error("Failed to set interface MTU %u for '%s': %s",
88                              static_cast<unsigned int>(mtu),
89                              mInterfaceName.c_str(),
90                              strerror(errno));
91     }
92 
93     return Result::success();
94 }
95 
setAddress(in_addr_t address)96 Result Interface::setAddress(in_addr_t address) {
97     struct ifreq request = createRequest();
98 
99     auto requestAddr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr);
100     requestAddr->sin_family = AF_INET;
101     requestAddr->sin_port = 0;
102     requestAddr->sin_addr.s_addr = address;
103 
104     int status = ::ioctl(mSocketFd, SIOCSIFADDR, &request);
105     if (status != 0) {
106         return Result::error("Failed to set interface address for '%s': %s",
107                              mInterfaceName.c_str(), strerror(errno));
108     }
109 
110     return Result::success();
111 }
112 
setSubnetMask(in_addr_t subnetMask)113 Result Interface::setSubnetMask(in_addr_t subnetMask) {
114     struct ifreq request = createRequest();
115 
116     auto addr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr);
117     addr->sin_family = AF_INET;
118     addr->sin_port = 0;
119     addr->sin_addr.s_addr = subnetMask;
120 
121     int status = ::ioctl(mSocketFd, SIOCSIFNETMASK, &request);
122     if (status != 0) {
123         return Result::error("Failed to set subnet mask for '%s': %s",
124                              mInterfaceName.c_str(), strerror(errno));
125     }
126 
127     return Result::success();
128 }
129 
createRequest() const130 struct ifreq Interface::createRequest() const {
131     struct ifreq request;
132     memset(&request, 0, sizeof(request));
133     strncpy(request.ifr_name, mInterfaceName.c_str(), sizeof(request.ifr_name));
134     request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
135 
136     return request;
137 }
138 
populateIndex()139 Result Interface::populateIndex() {
140     struct ifreq request = createRequest();
141 
142     int status = ::ioctl(mSocketFd, SIOCGIFINDEX, &request);
143     if (status != 0) {
144         return Result::error("Failed to get interface index for '%s': %s",
145                              mInterfaceName.c_str(), strerror(errno));
146     }
147     mIndex = request.ifr_ifindex;
148     return Result::success();
149 }
150 
populateMacAddress()151 Result Interface::populateMacAddress() {
152     struct ifreq request = createRequest();
153 
154     int status = ::ioctl(mSocketFd, SIOCGIFHWADDR, &request);
155     if (status != 0) {
156         return Result::error("Failed to get MAC address for '%s': %s",
157                              mInterfaceName.c_str(), strerror(errno));
158     }
159     memcpy(mMacAddress, &request.ifr_hwaddr.sa_data, ETH_ALEN);
160     return Result::success();
161 }
162 
setInterfaceUp(bool shouldBeUp)163 Result Interface::setInterfaceUp(bool shouldBeUp) {
164     struct ifreq request = createRequest();
165 
166     int status = ::ioctl(mSocketFd, SIOCGIFFLAGS, &request);
167     if (status != 0) {
168         return Result::error("Failed to get interface flags for '%s': %s",
169                              mInterfaceName.c_str(), strerror(errno));
170     }
171 
172     bool isUp = (request.ifr_flags & IFF_UP) != 0;
173     if (isUp != shouldBeUp) {
174         // Toggle the up flag
175         request.ifr_flags ^= IFF_UP;
176     } else {
177         // Interface is already in desired state, do nothing
178         return Result::success();
179     }
180 
181     status = ::ioctl(mSocketFd, SIOCSIFFLAGS, &request);
182     if (status != 0) {
183         return Result::error("Failed to set interface flags for '%s': %s",
184                              mInterfaceName.c_str(), strerror(errno));
185     }
186 
187     return Result::success();
188 }
189 
190