blob: 44eb2ef73601d685bde92a8f33c5f0d3646ac7c9 [file] [log] [blame]
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -05001/*
2 * Copyright (C) 2014 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
Sreeram Ramachandran72604072014-05-21 13:19:43 -070017// THREAD-SAFETY
18// -------------
19// The methods in this file are called from multiple threads (from CommandListener, FwmarkServer
20// and DnsProxyListener). So, all accesses to shared state are guarded by a lock.
21//
22// In some cases, a single non-const method acquires and releases the lock several times, like so:
23// if (isValidNetwork(...)) { // isValidNetwork() acquires and releases the lock.
24// setDefaultNetwork(...); // setDefaultNetwork() also acquires and releases the lock.
25//
26// It might seem that this allows races where the state changes between the two statements, but in
27// fact there are no races because:
28// 1. This pattern only occurs in non-const methods (i.e., those that mutate state).
29// 2. Only CommandListener calls these non-const methods. The others call only const methods.
30// 3. CommandListener only processes one command at a time. I.e., it's serialized.
31// Thus, no other mutation can occur in between the two statements above.
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050032
33#include "NetworkController.h"
34
Sreeram Ramachandran6a773532014-07-11 09:10:20 -070035#include "LocalNetwork.h"
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070036#include "PhysicalNetwork.h"
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070037#include "RouteController.h"
Sreeram Ramachandran4043f012014-06-23 12:41:37 -070038#include "VirtualNetwork.h"
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070039
Sreeram Ramachandraned4bd1f2014-07-05 12:31:05 -070040#include "cutils/misc.h"
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070041#define LOG_TAG "Netd"
42#include "log/log.h"
Sreeram Ramachandran72604072014-05-21 13:19:43 -070043#include "resolv_netid.h"
44
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070045namespace {
46
47// Keep these in sync with ConnectivityService.java.
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070048const unsigned MIN_NET_ID = 10;
49const unsigned MAX_NET_ID = 65535;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070050
51} // namespace
52
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070053NetworkController::NetworkController() : mDefaultNetId(NETID_UNSET) {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050054}
55
56unsigned NetworkController::getDefaultNetwork() const {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070057 android::RWLock::AutoRLock lock(mRWLock);
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050058 return mDefaultNetId;
59}
60
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070061int NetworkController::setDefaultNetwork(unsigned netId) {
62 android::RWLock::AutoWLock lock(mRWLock);
63
64 if (netId == mDefaultNetId) {
65 return 0;
Sreeram Ramachandran72604072014-05-21 13:19:43 -070066 }
67
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070068 if (netId != NETID_UNSET) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070069 Network* network = getNetworkLocked(netId);
70 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070071 ALOGE("invalid netId %u", netId);
72 return -EINVAL;
73 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070074 if (int ret = static_cast<PhysicalNetwork*>(network)->addAsDefault()) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070075 return ret;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070076 }
77 }
78
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070079 if (mDefaultNetId != NETID_UNSET) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070080 Network* network = getNetworkLocked(mDefaultNetId);
81 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070082 ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
83 return -ESRCH;
84 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070085 if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070086 return ret;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070087 }
88 }
89
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070090 mDefaultNetId = netId;
91 return 0;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050092}
93
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -070094unsigned NetworkController::getNetworkForUser(uid_t uid, unsigned requestedNetId,
95 bool forDns) const {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050096 android::RWLock::AutoRLock lock(mRWLock);
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -070097 VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
98 if (virtualNetwork && (!forDns || virtualNetwork->getHasDns())) {
99 return virtualNetwork->getNetId();
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500100 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700101 return getNetworkLocked(requestedNetId) ? requestedNetId : mDefaultNetId;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500102}
103
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700104unsigned NetworkController::getNetworkForInterface(const char* interface) const {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700105 android::RWLock::AutoRLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700106 for (const auto& entry : mNetworks) {
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700107 if (entry.second->hasInterface(interface)) {
108 return entry.first;
109 }
110 }
Paul Jensen35c77e32014-04-10 14:57:54 -0400111 return NETID_UNSET;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500112}
113
Sreeram Ramachandran070b2d22014-07-11 17:06:12 -0700114bool NetworkController::isVirtualNetwork(unsigned netId) const {
115 android::RWLock::AutoRLock lock(mRWLock);
116 Network* network = getNetworkLocked(netId);
117 return network && network->getType() == Network::VIRTUAL;
118}
119
Sreeram Ramachandran6a773532014-07-11 09:10:20 -0700120unsigned NetworkController::getNetIdForLocalNetwork() const {
121 return MIN_NET_ID - 1;
122}
123
124int NetworkController::createLocalNetwork(unsigned netId) {
125 // TODO: Enable this check after removing the getNetIdForLocalNetwork() hack.
126 if (false) {
127 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
128 ALOGE("invalid netId %u", netId);
129 return -EINVAL;
130 }
131 }
132
133 if (isValidNetwork(netId)) {
134 ALOGE("duplicate netId %u", netId);
135 return -EEXIST;
136 }
137
138 android::RWLock::AutoWLock lock(mRWLock);
139 mNetworks[netId] = new LocalNetwork(netId);
140 return 0;
141}
142
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700143int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700144 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
Paul Jensenae37e8a2014-04-28 10:35:51 -0400145 ALOGE("invalid netId %u", netId);
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900146 return -EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700147 }
148
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700149 if (isValidNetwork(netId)) {
150 ALOGE("duplicate netId %u", netId);
151 return -EEXIST;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700152 }
153
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700154 PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId);
155 if (int ret = physicalNetwork->setPermission(permission)) {
156 ALOGE("inconceivable! setPermission cannot fail on an empty network");
157 delete physicalNetwork;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900158 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700159 }
160
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700161 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700162 mNetworks[netId] = physicalNetwork;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900163 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700164}
165
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700166int NetworkController::createVirtualNetwork(unsigned netId, bool hasDns) {
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700167 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
168 ALOGE("invalid netId %u", netId);
169 return -EINVAL;
170 }
171
172 if (isValidNetwork(netId)) {
173 ALOGE("duplicate netId %u", netId);
174 return -EEXIST;
175 }
176
177 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700178 mNetworks[netId] = new VirtualNetwork(netId, hasDns);
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700179 return 0;
180}
181
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700182int NetworkController::destroyNetwork(unsigned netId) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700183 if (!isValidNetwork(netId)) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700184 ALOGE("invalid netId %u", netId);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700185 return -EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700186 }
187
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700188 // TODO: ioctl(SIOCKILLADDR, ...) to kill all sockets on the old network.
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700189
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700190 android::RWLock::AutoWLock lock(mRWLock);
191 Network* network = getNetworkLocked(netId);
192 if (int ret = network->clearInterfaces()) {
193 return ret;
194 }
195 if (mDefaultNetId == netId) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700196 if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700197 ALOGE("inconceivable! removeAsDefault cannot fail on an empty network");
198 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700199 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700200 mDefaultNetId = NETID_UNSET;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700201 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700202 mNetworks.erase(netId);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700203 delete network;
Sreeram Ramachandran3ced0692014-04-18 09:49:13 -0700204 _resolv_delete_cache_for_net(netId);
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900205 return 0;
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700206}
207
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700208int NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700209 if (!isValidNetwork(netId)) {
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700210 ALOGE("invalid netId %u", netId);
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900211 return -EINVAL;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700212 }
213
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700214 unsigned existingNetId = getNetworkForInterface(interface);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700215 if (existingNetId != NETID_UNSET && existingNetId != netId) {
216 ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
217 return -EBUSY;
218 }
219
220 android::RWLock::AutoWLock lock(mRWLock);
221 return getNetworkLocked(netId)->addInterface(interface);
222}
223
224int NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
225 if (!isValidNetwork(netId)) {
226 ALOGE("invalid netId %u", netId);
227 return -EINVAL;
228 }
229
230 android::RWLock::AutoWLock lock(mRWLock);
231 return getNetworkLocked(netId)->removeInterface(interface);
232}
233
234Permission NetworkController::getPermissionForUser(uid_t uid) const {
235 android::RWLock::AutoRLock lock(mRWLock);
Sreeram Ramachandraned4bd1f2014-07-05 12:31:05 -0700236 return getPermissionForUserLocked(uid);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700237}
238
239void NetworkController::setPermissionForUsers(Permission permission,
240 const std::vector<uid_t>& uids) {
241 android::RWLock::AutoWLock lock(mRWLock);
242 for (uid_t uid : uids) {
Sreeram Ramachandraned4bd1f2014-07-05 12:31:05 -0700243 mUsers[uid] = permission;
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700244 }
245}
246
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700247bool NetworkController::canUserSelectNetwork(uid_t uid, unsigned netId) const {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700248 android::RWLock::AutoRLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700249 Network* network = getNetworkLocked(netId);
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700250 if (!network || uid == INVALID_UID) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700251 return false;
252 }
Sreeram Ramachandraned4bd1f2014-07-05 12:31:05 -0700253 Permission userPermission = getPermissionForUserLocked(uid);
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700254 if ((userPermission & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
255 return true;
256 }
257 if (network->getType() == Network::VIRTUAL) {
258 return static_cast<VirtualNetwork*>(network)->appliesToUser(uid);
259 }
260 VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
261 if (virtualNetwork && mProtectableUsers.find(uid) == mProtectableUsers.end()) {
262 return false;
263 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700264 Permission networkPermission = static_cast<PhysicalNetwork*>(network)->getPermission();
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700265 return (userPermission & networkPermission) == networkPermission;
266}
267
268int NetworkController::setPermissionForNetworks(Permission permission,
269 const std::vector<unsigned>& netIds) {
270 android::RWLock::AutoWLock lock(mRWLock);
271 for (unsigned netId : netIds) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700272 Network* network = getNetworkLocked(netId);
273 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700274 ALOGE("invalid netId %u", netId);
275 return -EINVAL;
276 }
277
278 // TODO: ioctl(SIOCKILLADDR, ...) to kill socets on the network that don't have permission.
279
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700280 if (int ret = static_cast<PhysicalNetwork*>(network)->setPermission(permission)) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700281 return ret;
282 }
283 }
284 return 0;
285}
286
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700287int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
288 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700289 Network* network = getNetworkLocked(netId);
290 if (!network || network->getType() != Network::VIRTUAL) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700291 ALOGE("invalid netId %u", netId);
292 return -EINVAL;
293 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700294 if (int ret = static_cast<VirtualNetwork*>(network)->addUsers(uidRanges)) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700295 return ret;
296 }
297 return 0;
298}
299
300int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
301 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700302 Network* network = getNetworkLocked(netId);
303 if (!network || network->getType() != Network::VIRTUAL) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700304 ALOGE("invalid netId %u", netId);
305 return -EINVAL;
306 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700307 if (int ret = static_cast<VirtualNetwork*>(network)->removeUsers(uidRanges)) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700308 return ret;
309 }
310 return 0;
311}
312
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700313int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
314 const char* nexthop, bool legacy, uid_t uid) {
315 return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
316}
317
318int NetworkController::removeRoute(unsigned netId, const char* interface, const char* destination,
319 const char* nexthop, bool legacy, uid_t uid) {
320 return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
321}
322
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700323bool NetworkController::canProtect(uid_t uid) const {
324 android::RWLock::AutoRLock lock(mRWLock);
325 return ((getPermissionForUserLocked(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) ||
326 mProtectableUsers.find(uid) != mProtectableUsers.end();
327}
328
Sreeram Ramachandran89dad012014-07-02 10:09:49 -0700329void NetworkController::allowProtect(const std::vector<uid_t>& uids) {
330 android::RWLock::AutoWLock lock(mRWLock);
331 mProtectableUsers.insert(uids.begin(), uids.end());
332}
333
334void NetworkController::denyProtect(const std::vector<uid_t>& uids) {
335 android::RWLock::AutoWLock lock(mRWLock);
336 for (uid_t uid : uids) {
337 mProtectableUsers.erase(uid);
338 }
339}
340
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700341bool NetworkController::isValidNetwork(unsigned netId) const {
342 android::RWLock::AutoRLock lock(mRWLock);
343 return getNetworkLocked(netId);
344}
345
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700346Network* NetworkController::getNetworkLocked(unsigned netId) const {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700347 auto iter = mNetworks.find(netId);
348 return iter == mNetworks.end() ? NULL : iter->second;
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700349}
350
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700351VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
352 for (const auto& entry : mNetworks) {
353 if (entry.second->getType() == Network::VIRTUAL) {
354 VirtualNetwork* virtualNetwork = static_cast<VirtualNetwork*>(entry.second);
355 if (virtualNetwork->appliesToUser(uid)) {
356 return virtualNetwork;
357 }
358 }
359 }
360 return NULL;
361}
362
Sreeram Ramachandraned4bd1f2014-07-05 12:31:05 -0700363Permission NetworkController::getPermissionForUserLocked(uid_t uid) const {
364 auto iter = mUsers.find(uid);
365 if (iter != mUsers.end()) {
366 return iter->second;
367 }
368 return uid < FIRST_APPLICATION_UID ? PERMISSION_SYSTEM : PERMISSION_NONE;
369}
370
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700371int NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
372 const char* nexthop, bool add, bool legacy, uid_t uid) {
Sreeram Ramachandrane09b20a2014-07-05 17:15:14 -0700373 unsigned existingNetId = getNetworkForInterface(interface);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700374 if (netId == NETID_UNSET || existingNetId != netId) {
375 ALOGE("interface %s assigned to netId %u, not %u", interface, existingNetId, netId);
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900376 return -ENOENT;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700377 }
378
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700379 RouteController::TableType tableType;
380 if (legacy) {
Sreeram Ramachandraned4bd1f2014-07-05 12:31:05 -0700381 if ((getPermissionForUser(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
Sreeram Ramachandran5009d5e2014-07-03 12:20:48 -0700382 tableType = RouteController::LEGACY_SYSTEM;
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700383 } else {
Sreeram Ramachandran5009d5e2014-07-03 12:20:48 -0700384 tableType = RouteController::LEGACY_NETWORK;
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700385 }
386 } else {
387 tableType = RouteController::INTERFACE;
388 }
389
Sreeram Ramachandraneb27b7e2014-07-01 14:30:30 -0700390 return add ? RouteController::addRoute(interface, destination, nexthop, tableType) :
391 RouteController::removeRoute(interface, destination, nexthop, tableType);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700392}