• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019, 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 "bridge.h"
18 
19 #include "log.h"
20 
21 #include <errno.h>
22 #include <net/if.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 
Bridge(const std::string & bridgeName)29 Bridge::Bridge(const std::string& bridgeName) : mBridgeName(bridgeName) {
30 }
31 
~Bridge()32 Bridge::~Bridge() {
33     if (mSocketFd != -1) {
34         ::close(mSocketFd);
35         mSocketFd = -1;
36     }
37 }
38 
init()39 Result Bridge::init() {
40     Result res = createSocket();
41     if (!res) {
42         return res;
43     }
44     res = createBridge();
45     if (!res) {
46         return res;
47     }
48     return Result::success();
49 }
50 
addInterface(const std::string & interfaceName)51 Result Bridge::addInterface(const std::string& interfaceName) {
52     return doInterfaceOperation(interfaceName, SIOCBRADDIF, "add");
53 }
54 
removeInterface(const std::string & interfaceName)55 Result Bridge::removeInterface(const std::string& interfaceName) {
56     return doInterfaceOperation(interfaceName, SIOCBRDELIF, "remove");
57 }
58 
createSocket()59 Result Bridge::createSocket() {
60     if (mSocketFd != -1) {
61         return Result::error("Bridge already initialized");
62     }
63     mSocketFd = ::socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
64     if (mSocketFd < 0) {
65         return Result::error("Unable to create socket for bridge: %s",
66                              strerror(errno));
67     }
68     return Result::success();
69 }
70 
createBridge()71 Result Bridge::createBridge() {
72     int res = ::ioctl(mSocketFd, SIOCBRADDBR, mBridgeName.c_str());
73     if (res < 0) {
74         // If the bridge already exists we just keep going, that's fine.
75         // Otherwise something went wrong.
76         if (errno != EEXIST) {
77             return Result::error("Cannot create bridge %s: %s",
78                                  mBridgeName.c_str(), strerror(errno));
79         }
80     }
81 
82     struct ifreq request;
83     memset(&request, 0, sizeof(request));
84     // Determine interface index of bridge
85     request.ifr_ifindex = if_nametoindex(mBridgeName.c_str());
86     if (request.ifr_ifindex == 0) {
87         return Result::error("Unable to get bridge %s interface index",
88                              mBridgeName.c_str());
89     }
90     // Get bridge interface flags
91     strlcpy(request.ifr_name, mBridgeName.c_str(), sizeof(request.ifr_name));
92     res = ::ioctl(mSocketFd, SIOCGIFFLAGS, &request);
93     if (res != 0) {
94         return Result::error("Unable to get interface flags for bridge %s: %s",
95                              mBridgeName.c_str(), strerror(errno));
96     }
97 
98     if ((request.ifr_flags & IFF_UP) != 0) {
99         // Bridge is already up, it's ready to go
100         return Result::success();
101     }
102 
103     // Bridge is not up, it needs to be up to work
104     request.ifr_flags |= IFF_UP;
105     res = ::ioctl(mSocketFd, SIOCSIFFLAGS, &request);
106     if (res != 0) {
107         return Result::error("Unable to set interface flags for bridge %s: %s",
108                              strerror(errno));
109     }
110 
111     return Result::success();
112 }
113 
doInterfaceOperation(const std::string & interfaceName,unsigned long operation,const char * operationName)114 Result Bridge::doInterfaceOperation(const std::string& interfaceName,
115                                     unsigned long operation,
116                                     const char* operationName) {
117     struct ifreq request;
118     memset(&request, 0, sizeof(request));
119 
120     request.ifr_ifindex = if_nametoindex(interfaceName.c_str());
121     if (request.ifr_ifindex == 0) {
122         return Result::error("Bridge unable to %s interface '%s', no such "
123                              "interface", operationName, interfaceName.c_str());
124     }
125     strlcpy(request.ifr_name, mBridgeName.c_str(), sizeof(request.ifr_name));
126     int res = ::ioctl(mSocketFd, operation, &request);
127     // An errno of EBUSY most likely indicates that the interface is already
128     // part of the bridge. Ignore this.
129     if (res < 0 && errno != EBUSY) {
130         return Result::error("Bridge unable to %s interface '%s': %s",
131                              operationName, interfaceName.c_str(),
132                              strerror(errno));
133     }
134     return Result::success();
135 }
136