blob: 44f5df2cf1bc6e947e0239aad15edc1f303389f5 [file] [log] [blame]
San Mehat873f2142010-01-14 10:25:07 -08001/*
2 * Copyright (C) 2007 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
17package com.android.server;
18
19import android.app.PendingIntent;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.res.Resources;
25import android.content.pm.PackageManager;
26import android.net.Uri;
San Mehated4fc8a2010-01-22 12:28:36 -080027import android.net.InterfaceConfiguration;
San Mehat4d02d002010-01-22 16:07:46 -080028import android.net.INetworkManagementEventObserver;
Robert Greenwalted126402011-01-28 15:34:55 -080029import android.net.LinkAddress;
30import android.net.NetworkUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080031import android.net.wifi.WifiConfiguration;
32import android.net.wifi.WifiConfiguration.KeyMgmt;
San Mehat873f2142010-01-14 10:25:07 -080033import android.os.INetworkManagementService;
34import android.os.Handler;
Marco Nelissen62dbb222010-02-18 10:56:30 -080035import android.os.SystemProperties;
San Mehat873f2142010-01-14 10:25:07 -080036import android.text.TextUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080037import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080038import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080039import java.util.ArrayList;
Kenny Roota80ce062010-06-01 13:23:53 -070040import java.util.NoSuchElementException;
San Mehated4fc8a2010-01-22 12:28:36 -080041import java.util.StringTokenizer;
San Mehat873f2142010-01-14 10:25:07 -080042import android.provider.Settings;
43import android.content.ContentResolver;
44import android.database.ContentObserver;
45
46import java.io.File;
47import java.io.FileReader;
48import java.lang.IllegalStateException;
49
50import java.net.InetAddress;
51import java.net.UnknownHostException;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070052import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080053
54/**
55 * @hide
56 */
57class NetworkManagementService extends INetworkManagementService.Stub {
58
59 private static final String TAG = "NetworkManagmentService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070060 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070061 private static final String NETD_TAG = "NetdConnector";
62
San Mehat873f2142010-01-14 10:25:07 -080063 class NetdResponseCode {
64 public static final int InterfaceListResult = 110;
65 public static final int TetherInterfaceListResult = 111;
66 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080067 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080068
69 public static final int TetherStatusResult = 210;
70 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080071 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080072 public static final int SoftapStatusResult = 214;
73 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070074 public static final int InterfaceRxCounterResult = 216;
75 public static final int InterfaceTxCounterResult = 217;
76 public static final int InterfaceRxThrottleResult = 218;
77 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080078
79 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080080 }
81
82 /**
83 * Binder context for this service
84 */
85 private Context mContext;
86
87 /**
88 * connector object for communicating with netd
89 */
90 private NativeDaemonConnector mConnector;
91
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070092 private Thread mThread;
93 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
94
San Mehat4d02d002010-01-22 16:07:46 -080095 private ArrayList<INetworkManagementEventObserver> mObservers;
96
San Mehat873f2142010-01-14 10:25:07 -080097 /**
98 * Constructs a new NetworkManagementService instance
99 *
100 * @param context Binder context for this service
101 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700102 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800103 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800104 mObservers = new ArrayList<INetworkManagementEventObserver>();
105
Marco Nelissen62dbb222010-02-18 10:56:30 -0800106 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
107 return;
108 }
109
San Mehat873f2142010-01-14 10:25:07 -0800110 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700111 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700112 mThread = new Thread(mConnector, NETD_TAG);
113 }
114
115 public static NetworkManagementService create(Context context) throws InterruptedException {
116 NetworkManagementService service = new NetworkManagementService(context);
117 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
118 service.mThread.start();
119 if (DBG) Slog.d(TAG, "Awaiting socket connection");
120 service.mConnectedSignal.await();
121 if (DBG) Slog.d(TAG, "Connected");
122 return service;
San Mehat873f2142010-01-14 10:25:07 -0800123 }
124
San Mehat4d02d002010-01-22 16:07:46 -0800125 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800126 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800127 mObservers.add(obs);
128 }
129
130 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800131 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800132 mObservers.remove(mObservers.indexOf(obs));
133 }
134
135 /**
Wink Saville1a7e6712011-01-09 12:16:38 -0800136 * Notify our observers of an interface link status change
San Mehat4d02d002010-01-22 16:07:46 -0800137 */
Wink Saville1a7e6712011-01-09 12:16:38 -0800138 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
San Mehat4d02d002010-01-22 16:07:46 -0800139 for (INetworkManagementEventObserver obs : mObservers) {
140 try {
Wink Saville1a7e6712011-01-09 12:16:38 -0800141 obs.interfaceLinkStatusChanged(iface, link);
San Mehat4d02d002010-01-22 16:07:46 -0800142 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800143 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800144 }
145 }
146 }
147
148 /**
149 * Notify our observers of an interface addition.
150 */
151 private void notifyInterfaceAdded(String iface) {
152 for (INetworkManagementEventObserver obs : mObservers) {
153 try {
154 obs.interfaceAdded(iface);
155 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800156 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800157 }
158 }
159 }
160
161 /**
162 * Notify our observers of an interface removal.
163 */
164 private void notifyInterfaceRemoved(String iface) {
165 for (INetworkManagementEventObserver obs : mObservers) {
166 try {
167 obs.interfaceRemoved(iface);
168 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800169 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800170 }
171 }
172 }
173
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700174 /**
175 * Let us know the daemon is connected
176 */
177 protected void onConnected() {
178 if (DBG) Slog.d(TAG, "onConnected");
179 mConnectedSignal.countDown();
180 }
181
San Mehat4d02d002010-01-22 16:07:46 -0800182
San Mehat873f2142010-01-14 10:25:07 -0800183 //
184 // Netd Callback handling
185 //
186
187 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
188 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700189 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800190 new Thread() {
191 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800192 }
193 }.start();
194 }
195 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800196 if (code == NetdResponseCode.InterfaceChange) {
197 /*
198 * a network interface change occured
199 * Format: "NNN Iface added <name>"
200 * "NNN Iface removed <name>"
201 * "NNN Iface changed <name> <up/down>"
202 */
203 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
204 throw new IllegalStateException(
205 String.format("Invalid event from daemon (%s)", raw));
206 }
207 if (cooked[2].equals("added")) {
208 notifyInterfaceAdded(cooked[3]);
209 return true;
210 } else if (cooked[2].equals("removed")) {
211 notifyInterfaceRemoved(cooked[3]);
212 return true;
213 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Wink Saville1a7e6712011-01-09 12:16:38 -0800214 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800215 return true;
216 }
217 throw new IllegalStateException(
218 String.format("Invalid event from daemon (%s)", raw));
219 }
220 return false;
San Mehat873f2142010-01-14 10:25:07 -0800221 }
222 }
223
San Mehated4fc8a2010-01-22 12:28:36 -0800224
San Mehat873f2142010-01-14 10:25:07 -0800225 //
226 // INetworkManagementService members
227 //
228
229 public String[] listInterfaces() throws IllegalStateException {
230 mContext.enforceCallingOrSelfPermission(
231 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
232
Kenny Roota80ce062010-06-01 13:23:53 -0700233 try {
234 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
235 } catch (NativeDaemonConnectorException e) {
236 throw new IllegalStateException(
237 "Cannot communicate with native daemon to list interfaces");
238 }
San Mehated4fc8a2010-01-22 12:28:36 -0800239 }
240
241 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700242 String rsp;
243 try {
244 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
245 } catch (NativeDaemonConnectorException e) {
246 throw new IllegalStateException(
247 "Cannot communicate with native daemon to get interface config");
248 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800249 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800250
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800251 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800252 StringTokenizer st = new StringTokenizer(rsp);
253
Kenny Roota80ce062010-06-01 13:23:53 -0700254 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800255 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700256 try {
257 int code = Integer.parseInt(st.nextToken(" "));
258 if (code != NetdResponseCode.InterfaceGetCfgResult) {
259 throw new IllegalStateException(
260 String.format("Expected code %d, but got %d",
261 NetdResponseCode.InterfaceGetCfgResult, code));
262 }
263 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800264 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700265 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800266 }
Kenny Roota80ce062010-06-01 13:23:53 -0700267
268 cfg = new InterfaceConfiguration();
269 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800270 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800271 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700272 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800273 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
274 } catch (IllegalArgumentException iae) {
275 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700276 }
277
278 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800279 prefixLength = Integer.parseInt(st.nextToken(" "));
280 } catch (NumberFormatException nfe) {
281 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700282 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800283
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800284 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700285 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
286 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800287 throw new IllegalStateException(
288 String.format("Invalid response from daemon (%s)", rsp));
289 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800290 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800291 return cfg;
292 }
293
294 public void setInterfaceConfig(
295 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800296 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800297 if (linkAddr == null || linkAddr.getAddress() == null) {
298 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800299 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800300 String cmd = String.format("interface setcfg %s %s %d %s", iface,
301 linkAddr.getAddress().getHostAddress(),
302 linkAddr.getNetworkPrefixLength(),
303 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700304 try {
305 mConnector.doCommand(cmd);
306 } catch (NativeDaemonConnectorException e) {
307 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800308 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700309 }
San Mehat873f2142010-01-14 10:25:07 -0800310 }
311
312 public void shutdown() {
313 if (mContext.checkCallingOrSelfPermission(
314 android.Manifest.permission.SHUTDOWN)
315 != PackageManager.PERMISSION_GRANTED) {
316 throw new SecurityException("Requires SHUTDOWN permission");
317 }
318
Joe Onorato8a9b2202010-02-26 18:56:32 -0800319 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800320 }
321
322 public boolean getIpForwardingEnabled() throws IllegalStateException{
323 mContext.enforceCallingOrSelfPermission(
324 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
325
Kenny Roota80ce062010-06-01 13:23:53 -0700326 ArrayList<String> rsp;
327 try {
328 rsp = mConnector.doCommand("ipfwd status");
329 } catch (NativeDaemonConnectorException e) {
330 throw new IllegalStateException(
331 "Unable to communicate with native daemon to ipfwd status");
332 }
San Mehat873f2142010-01-14 10:25:07 -0800333
334 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700335 String[] tok = line.split(" ");
336 if (tok.length < 3) {
337 Slog.e(TAG, "Malformed response from native daemon: " + line);
338 return false;
339 }
340
San Mehat873f2142010-01-14 10:25:07 -0800341 int code = Integer.parseInt(tok[0]);
342 if (code == NetdResponseCode.IpFwdStatusResult) {
343 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700344 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800345 } else {
346 throw new IllegalStateException(String.format("Unexpected response code %d", code));
347 }
348 }
349 throw new IllegalStateException("Got an empty response");
350 }
351
352 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
353 mContext.enforceCallingOrSelfPermission(
354 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
355 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
356 }
357
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700358 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800359 throws IllegalStateException {
360 mContext.enforceCallingOrSelfPermission(
361 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700362 // cmd is "tether start first_start first_stop second_start second_stop ..."
363 // an odd number of addrs will fail
364 String cmd = "tether start";
365 for (String d : dhcpRange) {
366 cmd += " " + d;
367 }
Kenny Roota80ce062010-06-01 13:23:53 -0700368
369 try {
370 mConnector.doCommand(cmd);
371 } catch (NativeDaemonConnectorException e) {
372 throw new IllegalStateException("Unable to communicate to native daemon");
373 }
San Mehat873f2142010-01-14 10:25:07 -0800374 }
375
376 public void stopTethering() throws IllegalStateException {
377 mContext.enforceCallingOrSelfPermission(
378 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700379 try {
380 mConnector.doCommand("tether stop");
381 } catch (NativeDaemonConnectorException e) {
382 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
383 }
San Mehat873f2142010-01-14 10:25:07 -0800384 }
385
386 public boolean isTetheringStarted() throws IllegalStateException {
387 mContext.enforceCallingOrSelfPermission(
388 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
389
Kenny Roota80ce062010-06-01 13:23:53 -0700390 ArrayList<String> rsp;
391 try {
392 rsp = mConnector.doCommand("tether status");
393 } catch (NativeDaemonConnectorException e) {
394 throw new IllegalStateException(
395 "Unable to communicate to native daemon to get tether status");
396 }
San Mehat873f2142010-01-14 10:25:07 -0800397
398 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700399 String[] tok = line.split(" ");
400 if (tok.length < 3) {
401 throw new IllegalStateException("Malformed response for tether status: " + line);
402 }
San Mehat873f2142010-01-14 10:25:07 -0800403 int code = Integer.parseInt(tok[0]);
404 if (code == NetdResponseCode.TetherStatusResult) {
405 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700406 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800407 } else {
408 throw new IllegalStateException(String.format("Unexpected response code %d", code));
409 }
410 }
411 throw new IllegalStateException("Got an empty response");
412 }
413
414 public void tetherInterface(String iface) throws IllegalStateException {
415 mContext.enforceCallingOrSelfPermission(
416 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700417 try {
418 mConnector.doCommand("tether interface add " + iface);
419 } catch (NativeDaemonConnectorException e) {
420 throw new IllegalStateException(
421 "Unable to communicate to native daemon for adding tether interface");
422 }
San Mehat873f2142010-01-14 10:25:07 -0800423 }
424
425 public void untetherInterface(String iface) {
426 mContext.enforceCallingOrSelfPermission(
427 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700428 try {
429 mConnector.doCommand("tether interface remove " + iface);
430 } catch (NativeDaemonConnectorException e) {
431 throw new IllegalStateException(
432 "Unable to communicate to native daemon for removing tether interface");
433 }
San Mehat873f2142010-01-14 10:25:07 -0800434 }
435
436 public String[] listTetheredInterfaces() throws IllegalStateException {
437 mContext.enforceCallingOrSelfPermission(
438 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700439 try {
440 return mConnector.doListCommand(
441 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
442 } catch (NativeDaemonConnectorException e) {
443 throw new IllegalStateException(
444 "Unable to communicate to native daemon for listing tether interfaces");
445 }
San Mehat873f2142010-01-14 10:25:07 -0800446 }
447
448 public void setDnsForwarders(String[] dns) throws IllegalStateException {
449 mContext.enforceCallingOrSelfPermission(
450 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
451 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800452 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800453 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800454 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800455 }
Kenny Roota80ce062010-06-01 13:23:53 -0700456 try {
457 mConnector.doCommand(cmd);
458 } catch (NativeDaemonConnectorException e) {
459 throw new IllegalStateException(
460 "Unable to communicate to native daemon for setting tether dns");
461 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800462 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800463 throw new IllegalStateException("Error resolving dns name", e);
464 }
465 }
466
467 public String[] getDnsForwarders() throws IllegalStateException {
468 mContext.enforceCallingOrSelfPermission(
469 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700470 try {
471 return mConnector.doListCommand(
472 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
473 } catch (NativeDaemonConnectorException e) {
474 throw new IllegalStateException(
475 "Unable to communicate to native daemon for listing tether dns");
476 }
San Mehat873f2142010-01-14 10:25:07 -0800477 }
478
479 public void enableNat(String internalInterface, String externalInterface)
480 throws IllegalStateException {
481 mContext.enforceCallingOrSelfPermission(
482 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700483 try {
484 mConnector.doCommand(
485 String.format("nat enable %s %s", internalInterface, externalInterface));
486 } catch (NativeDaemonConnectorException e) {
487 throw new IllegalStateException(
488 "Unable to communicate to native daemon for enabling NAT interface");
489 }
San Mehat873f2142010-01-14 10:25:07 -0800490 }
491
492 public void disableNat(String internalInterface, String externalInterface)
493 throws IllegalStateException {
494 mContext.enforceCallingOrSelfPermission(
495 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700496 try {
497 mConnector.doCommand(
498 String.format("nat disable %s %s", internalInterface, externalInterface));
499 } catch (NativeDaemonConnectorException e) {
500 throw new IllegalStateException(
501 "Unable to communicate to native daemon for disabling NAT interface");
502 }
San Mehat873f2142010-01-14 10:25:07 -0800503 }
San Mehat72759df2010-01-19 13:50:37 -0800504
505 public String[] listTtys() throws IllegalStateException {
506 mContext.enforceCallingOrSelfPermission(
507 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700508 try {
509 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
510 } catch (NativeDaemonConnectorException e) {
511 throw new IllegalStateException(
512 "Unable to communicate to native daemon for listing TTYs");
513 }
San Mehat72759df2010-01-19 13:50:37 -0800514 }
515
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800516 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
517 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800518 try {
519 mContext.enforceCallingOrSelfPermission(
520 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800521 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800522 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
523 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
524 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
525 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
526 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800527 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700528 } catch (NativeDaemonConnectorException e) {
529 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800530 }
531 }
532
533 public void detachPppd(String tty) throws IllegalStateException {
534 mContext.enforceCallingOrSelfPermission(
535 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700536 try {
537 mConnector.doCommand(String.format("pppd detach %s", tty));
538 } catch (NativeDaemonConnectorException e) {
539 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
540 }
San Mehat72759df2010-01-19 13:50:37 -0800541 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800542
543 public void startUsbRNDIS() throws IllegalStateException {
544 mContext.enforceCallingOrSelfPermission(
545 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700546 try {
547 mConnector.doCommand("usb startrndis");
548 } catch (NativeDaemonConnectorException e) {
549 throw new IllegalStateException(
550 "Error communicating to native daemon for starting RNDIS", e);
551 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800552 }
553
554 public void stopUsbRNDIS() throws IllegalStateException {
555 mContext.enforceCallingOrSelfPermission(
556 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700557 try {
558 mConnector.doCommand("usb stoprndis");
559 } catch (NativeDaemonConnectorException e) {
560 throw new IllegalStateException("Error communicating to native daemon", e);
561 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800562 }
563
564 public boolean isUsbRNDISStarted() throws IllegalStateException {
565 mContext.enforceCallingOrSelfPermission(
566 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700567 ArrayList<String> rsp;
568 try {
569 rsp = mConnector.doCommand("usb rndisstatus");
570 } catch (NativeDaemonConnectorException e) {
571 throw new IllegalStateException(
572 "Error communicating to native daemon to check RNDIS status", e);
573 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800574
575 for (String line : rsp) {
576 String []tok = line.split(" ");
577 int code = Integer.parseInt(tok[0]);
578 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500579 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800580 return true;
581 return false;
582 } else {
583 throw new IllegalStateException(String.format("Unexpected response code %d", code));
584 }
585 }
586 throw new IllegalStateException("Got an empty response");
587 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800588
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700589 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800590 throws IllegalStateException {
591 mContext.enforceCallingOrSelfPermission(
592 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
593 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700594 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700595 try {
596 mConnector.doCommand(String.format("softap stop " + wlanIface));
597 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
598 mConnector.doCommand(String.format("softap start " + wlanIface));
599 if (wifiConfig == null) {
600 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
601 } else {
602 /**
603 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
604 * argv1 - wlan interface
605 * argv2 - softap interface
606 * argv3 - SSID
607 * argv4 - Security
608 * argv5 - Key
609 * argv6 - Channel
610 * argv7 - Preamble
611 * argv8 - Max SCB
612 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800613 String str = String.format("softap set " + wlanIface + " " + softapIface +
614 " %s %s %s", convertQuotedString(wifiConfig.SSID),
615 getSecurityType(wifiConfig),
616 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700617 mConnector.doCommand(str);
618 }
619 mConnector.doCommand(String.format("softap startap"));
620 } catch (NativeDaemonConnectorException e) {
621 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800622 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800623 }
624
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700625 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700626 if (s == null) {
627 return s;
628 }
629 /* Replace \ with \\, then " with \" and add quotes at end */
630 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700631 }
632
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800633 private String getSecurityType(WifiConfiguration wifiConfig) {
634 switch (wifiConfig.getAuthType()) {
635 case KeyMgmt.WPA_PSK:
636 return "wpa-psk";
637 case KeyMgmt.WPA2_PSK:
638 return "wpa2-psk";
639 default:
640 return "open";
641 }
642 }
643
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800644 public void stopAccessPoint() throws IllegalStateException {
645 mContext.enforceCallingOrSelfPermission(
646 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
647 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700648 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700649 try {
650 mConnector.doCommand("softap stopap");
651 } catch (NativeDaemonConnectorException e) {
652 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
653 e);
654 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800655 }
656
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700657 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
658 throws IllegalStateException {
659 mContext.enforceCallingOrSelfPermission(
660 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
661 mContext.enforceCallingOrSelfPermission(
662 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700663 try {
664 if (wifiConfig == null) {
665 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
666 } else {
667 String str = String.format("softap set " + wlanIface + " " + softapIface
668 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800669 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700670 convertQuotedString(wifiConfig.preSharedKey));
671 mConnector.doCommand(str);
672 }
673 } catch (NativeDaemonConnectorException e) {
674 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
675 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700676 }
677 }
San Mehat91cac642010-03-31 14:31:36 -0700678
679 private long getInterfaceCounter(String iface, boolean rx) {
680 mContext.enforceCallingOrSelfPermission(
681 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
682 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700683 String rsp;
684 try {
685 rsp = mConnector.doCommand(
686 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
687 } catch (NativeDaemonConnectorException e1) {
688 Slog.e(TAG, "Error communicating with native daemon", e1);
689 return -1;
690 }
691
692 String[] tok = rsp.split(" ");
693 if (tok.length < 2) {
694 Slog.e(TAG, String.format("Malformed response for reading %s interface",
695 (rx ? "rx" : "tx")));
696 return -1;
697 }
698
San Mehat91cac642010-03-31 14:31:36 -0700699 int code;
700 try {
701 code = Integer.parseInt(tok[0]);
702 } catch (NumberFormatException nfe) {
703 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
704 return -1;
705 }
706 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
707 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
708 Slog.e(TAG, String.format("Unexpected response code %d", code));
709 return -1;
710 }
711 return Long.parseLong(tok[1]);
712 } catch (Exception e) {
713 Slog.e(TAG, String.format(
714 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
715 }
716 return -1;
717 }
718
719 public long getInterfaceRxCounter(String iface) {
720 return getInterfaceCounter(iface, true);
721 }
722
723 public long getInterfaceTxCounter(String iface) {
724 return getInterfaceCounter(iface, false);
725 }
726
San Mehatf0db6e12010-04-07 15:22:10 -0700727 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700728 mContext.enforceCallingOrSelfPermission(
729 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700730 try {
731 mConnector.doCommand(String.format(
732 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
733 } catch (NativeDaemonConnectorException e) {
734 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
735 }
San Mehat91cac642010-03-31 14:31:36 -0700736 }
737
738 private int getInterfaceThrottle(String iface, boolean rx) {
739 mContext.enforceCallingOrSelfPermission(
740 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
741 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700742 String rsp;
743 try {
744 rsp = mConnector.doCommand(
745 String.format("interface getthrottle %s %s", iface,
746 (rx ? "rx" : "tx"))).get(0);
747 } catch (NativeDaemonConnectorException e) {
748 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
749 return -1;
750 }
751
752 String[] tok = rsp.split(" ");
753 if (tok.length < 2) {
754 Slog.e(TAG, "Malformed response to getthrottle command");
755 return -1;
756 }
757
San Mehat91cac642010-03-31 14:31:36 -0700758 int code;
759 try {
760 code = Integer.parseInt(tok[0]);
761 } catch (NumberFormatException nfe) {
762 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
763 return -1;
764 }
765 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
766 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
767 Slog.e(TAG, String.format("Unexpected response code %d", code));
768 return -1;
769 }
770 return Integer.parseInt(tok[1]);
771 } catch (Exception e) {
772 Slog.e(TAG, String.format(
773 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
774 }
775 return -1;
776 }
777
778 public int getInterfaceRxThrottle(String iface) {
779 return getInterfaceThrottle(iface, true);
780 }
781
782 public int getInterfaceTxThrottle(String iface) {
783 return getInterfaceThrottle(iface, false);
784 }
San Mehat873f2142010-01-14 10:25:07 -0800785}