blob: f71087624e4b64fad9e5c0adfb1f845d489fa0a3 [file] [log] [blame]
San Mehat9d10b342010-01-18 09:51:02 -08001/*
2 * Copyright (C) 2008 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 <stdlib.h>
18#include <errno.h>
San Mehat18737842010-01-21 09:22:43 -080019#include <fcntl.h>
Olivier Baillyff2c0d82010-11-17 11:45:07 -080020#include <string.h>
San Mehat18737842010-01-21 09:22:43 -080021
San Mehat9d10b342010-01-18 09:51:02 -080022#include <sys/socket.h>
23#include <sys/stat.h>
San Mehat18737842010-01-21 09:22:43 -080024#include <sys/types.h>
25#include <sys/wait.h>
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -060026#include <linux/capability.h>
San Mehat18737842010-01-21 09:22:43 -080027
San Mehat9d10b342010-01-18 09:51:02 -080028#include <netinet/in.h>
29#include <arpa/inet.h>
30
31#define LOG_TAG "TetherController"
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -060032#define LOG_NDEBUG 0
33#define LOG_NDDEBUG 0
34#define LOG_NIDEBUG 0
San Mehat9d10b342010-01-18 09:51:02 -080035#include <cutils/log.h>
Kazuhiro Ondo6b858eb2011-06-24 20:31:03 -050036#include <cutils/properties.h>
San Mehat9d10b342010-01-18 09:51:02 -080037
Lorenzo Colitti667c4772014-08-26 14:13:07 -070038#include "Fwmark.h"
JP Abgrall69261cb2014-06-19 18:35:24 -070039#include "NetdConstants.h"
Lorenzo Colitti667c4772014-08-26 14:13:07 -070040#include "Permission.h"
San Mehat9d10b342010-01-18 09:51:02 -080041#include "TetherController.h"
42
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -060043#include <private/android_filesystem_config.h>
44#include <unistd.h>
45
46#define RTRADVDAEMON "/system/bin/radish"
47#define IP4_CFG_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
48#define IP6_CFG_ALL_PROXY_NDP "/proc/sys/net/ipv6/conf/all/proxy_ndp"
49#define IP6_CFG_ALL_FORWARDING "/proc/sys/net/ipv6/conf/all/forwarding"
50#define IP6_IFACE_CFG_ACCEPT_RA "/proc/sys/net/ipv6/conf/%s/accept_ra"
51#define PROC_PATH_SIZE 255
52
53
Sreeram Ramachandran87475a12014-07-15 16:20:28 -070054TetherController::TetherController() {
San Mehat9d10b342010-01-18 09:51:02 -080055 mInterfaces = new InterfaceCollection();
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -060056 mUpstreamInterfaces = new InterfaceCollection();
San Mehat9d10b342010-01-18 09:51:02 -080057 mDnsForwarders = new NetAddressCollection();
58 mDaemonFd = -1;
59 mDaemonPid = 0;
60}
61
62TetherController::~TetherController() {
63 InterfaceCollection::iterator it;
64
65 for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
66 free(*it);
67 }
68 mInterfaces->clear();
69
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -060070 for (it = mUpstreamInterfaces->begin(); it != mUpstreamInterfaces->end(); ++it) {
71 free(*it);
72 }
73 mUpstreamInterfaces->clear();
74
San Mehat9d10b342010-01-18 09:51:02 -080075 mDnsForwarders->clear();
76}
77
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -060078static int config_write_setting(const char *path, const char *value)
79{
80 int fd = open(path, O_WRONLY);
81
82 ALOGD("config_write_setting(%s, %s)", path, value);
83 if (fd < 0) {
84 ALOGE("Failed to open %s (%s)", path, strerror(errno));
85 return -1;
86 }
87 if (write(fd, value, strlen(value)) != (int)strlen(value)) {
88 ALOGE("Failed to write to %s (%s)", path, strerror(errno));
89 close(fd);
90 return -1;
91 }
92 close(fd);
93 return 0;
94}
95
San Mehat9d10b342010-01-18 09:51:02 -080096int TetherController::setIpFwdEnabled(bool enable) {
97
Steve Block7b984e32011-12-20 16:22:42 +000098 ALOGD("Setting IP forward enable = %d", enable);
Kazuhiro Ondo6b858eb2011-06-24 20:31:03 -050099
100 // In BP tools mode, do not disable IP forwarding
101 char bootmode[PROPERTY_VALUE_MAX] = {0};
102 property_get("ro.bootmode", bootmode, "unknown");
103 if ((enable == false) && (0 == strcmp("bp-tools", bootmode))) {
104 return 0;
105 }
106
San Mehat9d10b342010-01-18 09:51:02 -0800107 int fd = open("/proc/sys/net/ipv4/ip_forward", O_WRONLY);
108 if (fd < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000109 ALOGE("Failed to open ip_forward (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800110 return -1;
111 }
112
113 if (write(fd, (enable ? "1" : "0"), 1) != 1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000114 ALOGE("Failed to write ip_forward (%s)", strerror(errno));
Robert Greenwalt37dc4a52010-04-28 16:05:04 -0700115 close(fd);
San Mehat9d10b342010-01-18 09:51:02 -0800116 return -1;
117 }
118 close(fd);
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -0600119 if (config_write_setting(
120 IP6_CFG_ALL_PROXY_NDP, enable ? "2" : "0")) {
121 ALOGE("Failed to write proxy_ndp (%s)", strerror(errno));
122 return -1;
123 }
124 if (config_write_setting(
125 IP6_CFG_ALL_FORWARDING, enable ? "2" : "0")) {
126 ALOGE("Failed to write ip6 forwarding (%s)", strerror(errno));
127 return -1;
128 }
129
San Mehat9d10b342010-01-18 09:51:02 -0800130 return 0;
131}
132
133bool TetherController::getIpFwdEnabled() {
134 int fd = open("/proc/sys/net/ipv4/ip_forward", O_RDONLY);
135
136 if (fd < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000137 ALOGE("Failed to open ip_forward (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800138 return false;
139 }
140
141 char enabled;
142 if (read(fd, &enabled, 1) != 1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000143 ALOGE("Failed to read ip_forward (%s)", strerror(errno));
Robert Greenwalt37dc4a52010-04-28 16:05:04 -0700144 close(fd);
San Mehat9d10b342010-01-18 09:51:02 -0800145 return -1;
146 }
147
148 close(fd);
San Mehat9d10b342010-01-18 09:51:02 -0800149 return (enabled == '1' ? true : false);
150}
151
Dmitry Shmidtbc775ed2013-12-12 16:41:16 -0800152#define TETHER_START_CONST_ARG 8
153
Robert Greenwalt3208ea02010-03-24 16:32:55 -0700154int TetherController::startTethering(int num_addrs, struct in_addr* addrs) {
San Mehat9d10b342010-01-18 09:51:02 -0800155 if (mDaemonPid != 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000156 ALOGE("Tethering already started");
San Mehat9d10b342010-01-18 09:51:02 -0800157 errno = EBUSY;
158 return -1;
159 }
160
Steve Block7b984e32011-12-20 16:22:42 +0000161 ALOGD("Starting tethering services");
San Mehat9d10b342010-01-18 09:51:02 -0800162
163 pid_t pid;
164 int pipefd[2];
165
166 if (pipe(pipefd) < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000167 ALOGE("pipe failed (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800168 return -1;
169 }
170
171 /*
172 * TODO: Create a monitoring thread to handle and restart
173 * the daemon if it exits prematurely
174 */
175 if ((pid = fork()) < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000176 ALOGE("fork failed (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800177 close(pipefd[0]);
178 close(pipefd[1]);
179 return -1;
180 }
181
182 if (!pid) {
183 close(pipefd[1]);
184 if (pipefd[0] != STDIN_FILENO) {
185 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
Steve Block5ea0c052012-01-06 19:18:11 +0000186 ALOGE("dup2 failed (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800187 return -1;
188 }
189 close(pipefd[0]);
190 }
San Mehat9d10b342010-01-18 09:51:02 -0800191
Dmitry Shmidtbc775ed2013-12-12 16:41:16 -0800192 int num_processed_args = TETHER_START_CONST_ARG + (num_addrs/2) + 1;
Robert Greenwalt3208ea02010-03-24 16:32:55 -0700193 char **args = (char **)malloc(sizeof(char *) * num_processed_args);
194 args[num_processed_args - 1] = NULL;
195 args[0] = (char *)"/system/bin/dnsmasq";
Peter Nilssonb756f692011-09-08 09:48:31 -0700196 args[1] = (char *)"--keep-in-foreground";
Robert Greenwalt3208ea02010-03-24 16:32:55 -0700197 args[2] = (char *)"--no-resolv";
198 args[3] = (char *)"--no-poll";
Dmitry Shmidtbc775ed2013-12-12 16:41:16 -0800199 args[4] = (char *)"--dhcp-authoritative";
Jeff Sharkey6df79da2012-04-18 21:53:35 -0700200 // TODO: pipe through metered status from ConnService
Dmitry Shmidtbc775ed2013-12-12 16:41:16 -0800201 args[5] = (char *)"--dhcp-option-force=43,ANDROID_METERED";
202 args[6] = (char *)"--pid-file";
203 args[7] = (char *)"";
San Mehat9d10b342010-01-18 09:51:02 -0800204
Dmitry Shmidtbc775ed2013-12-12 16:41:16 -0800205 int nextArg = TETHER_START_CONST_ARG;
Robert Greenwalt3208ea02010-03-24 16:32:55 -0700206 for (int addrIndex=0; addrIndex < num_addrs;) {
207 char *start = strdup(inet_ntoa(addrs[addrIndex++]));
208 char *end = strdup(inet_ntoa(addrs[addrIndex++]));
209 asprintf(&(args[nextArg++]),"--dhcp-range=%s,%s,1h", start, end);
210 }
211
212 if (execv(args[0], args)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000213 ALOGE("execl failed (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800214 }
Steve Block5ea0c052012-01-06 19:18:11 +0000215 ALOGE("Should never get here!");
JP Abgrallce4f3792012-08-06 13:44:44 -0700216 _exit(-1);
San Mehat9d10b342010-01-18 09:51:02 -0800217 } else {
218 close(pipefd[0]);
219 mDaemonPid = pid;
220 mDaemonFd = pipefd[1];
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800221 applyDnsInterfaces();
Steve Block7b984e32011-12-20 16:22:42 +0000222 ALOGD("Tethering services running");
San Mehat9d10b342010-01-18 09:51:02 -0800223 }
224
225 return 0;
226}
227
228int TetherController::stopTethering() {
229
230 if (mDaemonPid == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000231 ALOGE("Tethering already stopped");
San Mehat9d10b342010-01-18 09:51:02 -0800232 return 0;
233 }
234
Steve Block7b984e32011-12-20 16:22:42 +0000235 ALOGD("Stopping tethering services");
San Mehat9d10b342010-01-18 09:51:02 -0800236
237 kill(mDaemonPid, SIGTERM);
San Mehat18737842010-01-21 09:22:43 -0800238 waitpid(mDaemonPid, NULL, 0);
San Mehat9d10b342010-01-18 09:51:02 -0800239 mDaemonPid = 0;
240 close(mDaemonFd);
241 mDaemonFd = -1;
Steve Block7b984e32011-12-20 16:22:42 +0000242 ALOGD("Tethering services stopped");
San Mehat9d10b342010-01-18 09:51:02 -0800243 return 0;
244}
Matthew Xie19944102012-07-12 16:42:07 -0700245
San Mehat9d10b342010-01-18 09:51:02 -0800246bool TetherController::isTetheringStarted() {
247 return (mDaemonPid == 0 ? false : true);
248}
249
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -0600250int TetherController::startV6RtrAdv(int num_ifaces, char **ifaces) {
251 int pid;
252 int num_processed_args = 1;
253 gid_t groups [] = { AID_NET_ADMIN, AID_NET_RAW, AID_INET };
254
255 if (num_ifaces < 2) {
256 ALOGD("Need atleast two interfaces to start Router advertisement daemon");
257 return 0;
258 }
259
260 if ((pid = fork()) < 0) {
261 ALOGE("%s: fork failed (%s)", __func__, strerror(errno));
262 return -1;
263 }
264 if (!pid) {
265 char **args;
266 const char *cmd = RTRADVDAEMON;
267
268 args = (char **)calloc(num_ifaces * 3 + 2, sizeof(char *));
269
270 args[0] = strdup(RTRADVDAEMON);
271 for (int i=0; i < num_ifaces; i++) {
272 int aidx = 3 * i + num_processed_args;
273 args[aidx] = (char *)"-i";
274 args[aidx + 1] = ifaces[i];
275 args[aidx + 2] = (char *)"-x";
276 }
277
278
279 setgroups(sizeof(groups)/sizeof(groups[0]), groups);
280 setresgid(AID_RADIO, AID_RADIO, AID_RADIO);
281 setresuid(AID_RADIO, AID_RADIO, AID_RADIO);
282
283 if (execv(cmd, args)) {
284 ALOGE("Unable to exec %s: (%s)" , cmd, strerror(errno));
285 }
286 free(args[0]);
287 free(args);
288 exit(0);
289 } else {
290 mRtrAdvPid = pid;
291 ALOGD("Router advertisement daemon running");
292 }
293 return 0;
294}
295
296int TetherController::stopV6RtrAdv() {
297 if (!mRtrAdvPid) {
298 ALOGD("Router advertisement daemon already stopped");
299 return 0;
300 }
301
302 kill(mRtrAdvPid, SIGTERM);
303 waitpid(mRtrAdvPid, NULL, 0);
304 mRtrAdvPid = 0;
305 ALOGD("Router advertisement daemon stopped");
306 return 0;
307}
308
309int TetherController::addV6RtrAdvIface(const char *iface) {
310 char **args;
311 int i;
312 int len;
313 InterfaceCollection::iterator it;
314 /* For now, just stop and start the daemon with the new interface list */
315
316 len = mInterfaces->size() + mUpstreamInterfaces->size();
317 ALOGD("addV6RtrAdvIface: len = %d. Iface: %s\n", len, iface);
318 args = (char **)calloc(len, sizeof(char *));
319
320 if (!args) {
321 errno = ENOMEM;
322 return -1;
323 }
324
325 for (i = 0, it = mInterfaces->begin(); it != mInterfaces->end(); it++, i++) {
326 args[i] = *it;
327 }
328
329 for (it = mUpstreamInterfaces->begin(); i < len && it != mUpstreamInterfaces->end(); it++, i++) {
330 args[i] = *it;
331 }
332
333 stopV6RtrAdv();
334 startV6RtrAdv(i, args);
335
336 free(args);
337
338 return 0;
339}
340
341int TetherController::removeV6RtrAdvIface(const char *iface) {
342 /* For now, just call addV6RtrAdvIface, since that will stop and
343 * start the daemon with the updated interfaces
344 */
345 return addV6RtrAdvIface(iface);
346}
347bool TetherController::isV6RtrAdvStarted() {
348 return (mRtrAdvPid == 0 ? false : true);
349}
350
Kenny Rootcf52faf2010-02-18 09:59:55 -0800351#define MAX_CMD_SIZE 1024
352
Lorenzo Colitti667c4772014-08-26 14:13:07 -0700353int TetherController::setDnsForwarders(unsigned netId, char **servers, int numServers) {
San Mehat9d10b342010-01-18 09:51:02 -0800354 int i;
Kenny Rootcf52faf2010-02-18 09:59:55 -0800355 char daemonCmd[MAX_CMD_SIZE];
San Mehat9d10b342010-01-18 09:51:02 -0800356
Lorenzo Colitti667c4772014-08-26 14:13:07 -0700357 Fwmark fwmark;
358 fwmark.netId = netId;
359 fwmark.explicitlySelected = true;
360 fwmark.protectedFromVpn = true;
361 fwmark.permission = PERMISSION_SYSTEM;
362
363 snprintf(daemonCmd, sizeof(daemonCmd), "update_dns:0x%x", fwmark.intValue);
Kenny Rootcf52faf2010-02-18 09:59:55 -0800364 int cmdLen = strlen(daemonCmd);
San Mehat9d10b342010-01-18 09:51:02 -0800365
366 mDnsForwarders->clear();
367 for (i = 0; i < numServers; i++) {
Lorenzo Colitti667c4772014-08-26 14:13:07 -0700368 ALOGD("setDnsForwarders(0x%x %d = '%s')", fwmark.intValue, i, servers[i]);
San Mehat9d10b342010-01-18 09:51:02 -0800369
370 struct in_addr a;
371
372 if (!inet_aton(servers[i], &a)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000373 ALOGE("Failed to parse DNS server '%s'", servers[i]);
San Mehat9d10b342010-01-18 09:51:02 -0800374 mDnsForwarders->clear();
375 return -1;
376 }
Kenny Rootcf52faf2010-02-18 09:59:55 -0800377
Nick Kralevichad5b41f2012-07-19 18:48:05 -0700378 cmdLen += (strlen(servers[i]) + 1);
379 if (cmdLen + 1 >= MAX_CMD_SIZE) {
Steve Block7b984e32011-12-20 16:22:42 +0000380 ALOGD("Too many DNS servers listed");
Kenny Rootcf52faf2010-02-18 09:59:55 -0800381 break;
382 }
383
San Mehat9d10b342010-01-18 09:51:02 -0800384 strcat(daemonCmd, ":");
385 strcat(daemonCmd, servers[i]);
386 mDnsForwarders->push_back(a);
387 }
388
Lorenzo Colitti667c4772014-08-26 14:13:07 -0700389 mDnsNetId = netId;
San Mehat9d10b342010-01-18 09:51:02 -0800390 if (mDaemonFd != -1) {
Steve Block7b984e32011-12-20 16:22:42 +0000391 ALOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
San Mehat9d10b342010-01-18 09:51:02 -0800392 if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000393 ALOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
San Mehat9d10b342010-01-18 09:51:02 -0800394 mDnsForwarders->clear();
395 return -1;
396 }
397 }
398 return 0;
399}
400
Lorenzo Colitti667c4772014-08-26 14:13:07 -0700401unsigned TetherController::getDnsNetId() {
402 return mDnsNetId;
403}
404
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -0600405int TetherController::addUpstreamInterface(char *iface)
406{
407 InterfaceCollection::iterator it;
408
409 ALOGD("addUpstreamInterface(%s)\n", iface);
410
411 if (!iface) {
412 ALOGE("addUpstreamInterface: received null interface");
413 return 0;
414 }
415 for (it = mUpstreamInterfaces->begin(); it != mUpstreamInterfaces->end(); ++it) {
416 ALOGD(".");
417 if (*it && !strcmp(iface, *it)) {
418 ALOGD("addUpstreamInterface: interface %s already present", iface);
419 return 0;
420 }
421 }
422 mUpstreamInterfaces->push_back(strdup(iface));
423
424 return addV6RtrAdvIface(iface);
425}
426
427int TetherController::removeUpstreamInterface(char *iface)
428{
429 InterfaceCollection::iterator it;
430
431 if (!iface) {
432 ALOGE("removeUpstreamInterface: Null interface name received");
433 return 0;
434 }
435 for (it = mUpstreamInterfaces->begin(); it != mUpstreamInterfaces->end(); ++it) {
436 if (*it && !strcmp(iface, *it)) {
437 free(*it);
438 mUpstreamInterfaces->erase(it);
439 return removeV6RtrAdvIface(iface);
440 }
441 }
442
443 ALOGW("Couldn't find interface %s to remove", iface);
444 return 0;
445}
446
San Mehat9d10b342010-01-18 09:51:02 -0800447NetAddressCollection *TetherController::getDnsForwarders() {
448 return mDnsForwarders;
449}
450
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800451int TetherController::applyDnsInterfaces() {
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800452 char daemonCmd[MAX_CMD_SIZE];
453
454 strcpy(daemonCmd, "update_ifaces");
455 int cmdLen = strlen(daemonCmd);
456 InterfaceCollection::iterator it;
457 bool haveInterfaces = false;
458
459 for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
460 cmdLen += (strlen(*it) + 1);
461 if (cmdLen + 1 >= MAX_CMD_SIZE) {
462 ALOGD("Too many DNS ifaces listed");
463 break;
464 }
465
466 strcat(daemonCmd, ":");
467 strcat(daemonCmd, *it);
468 haveInterfaces = true;
469 }
470
471 if ((mDaemonFd != -1) && haveInterfaces) {
472 ALOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
473 if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) {
474 ALOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
475 return -1;
476 }
477 }
San Mehat9d10b342010-01-18 09:51:02 -0800478 return 0;
479}
480
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800481int TetherController::tetherInterface(const char *interface) {
482 ALOGD("tetherInterface(%s)", interface);
JP Abgrall69261cb2014-06-19 18:35:24 -0700483 if (!isIfaceName(interface)) {
484 errno = ENOENT;
485 return -1;
486 }
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800487 mInterfaces->push_back(strdup(interface));
488
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -0600489 addV6RtrAdvIface(interface);
490
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800491 if (applyDnsInterfaces()) {
492 InterfaceCollection::iterator it;
493 for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
494 if (!strcmp(interface, *it)) {
495 free(*it);
496 mInterfaces->erase(it);
497 break;
498 }
499 }
500 return -1;
501 } else {
502 return 0;
503 }
504}
505
San Mehat9d10b342010-01-18 09:51:02 -0800506int TetherController::untetherInterface(const char *interface) {
507 InterfaceCollection::iterator it;
508
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800509 ALOGD("untetherInterface(%s)", interface);
510
San Mehat9d10b342010-01-18 09:51:02 -0800511 for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
512 if (!strcmp(interface, *it)) {
513 free(*it);
514 mInterfaces->erase(it);
Subash Abhinov Kasiviswanathan0e217b52014-07-15 00:08:40 -0600515 removeV6RtrAdvIface(NULL);
Robert Greenwalt3d4c7582012-12-11 12:33:37 -0800516 return applyDnsInterfaces();
San Mehat9d10b342010-01-18 09:51:02 -0800517 }
518 }
519 errno = ENOENT;
520 return -1;
521}
522
523InterfaceCollection *TetherController::getTetheredInterfaceList() {
524 return mInterfaces;
525}