blob: 0b4b95893254f2b6c0a95e2dc9716d07876ebccf [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;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070031import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080032import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiConfiguration.KeyMgmt;
San Mehat873f2142010-01-14 10:25:07 -080034import android.os.INetworkManagementService;
35import android.os.Handler;
Marco Nelissen62dbb222010-02-18 10:56:30 -080036import android.os.SystemProperties;
San Mehat873f2142010-01-14 10:25:07 -080037import android.text.TextUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080038import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080039import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080040import java.util.ArrayList;
Kenny Roota80ce062010-06-01 13:23:53 -070041import java.util.NoSuchElementException;
San Mehated4fc8a2010-01-22 12:28:36 -080042import java.util.StringTokenizer;
San Mehat873f2142010-01-14 10:25:07 -080043import android.provider.Settings;
44import android.content.ContentResolver;
45import android.database.ContentObserver;
46
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070047import java.io.BufferedReader;
48import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080049import java.io.File;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070050import java.io.FileInputStream;
San Mehat873f2142010-01-14 10:25:07 -080051import java.io.FileReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070052import java.io.InputStreamReader;
53import java.io.IOException;
San Mehat873f2142010-01-14 10:25:07 -080054import java.lang.IllegalStateException;
San Mehat873f2142010-01-14 10:25:07 -080055import java.net.InetAddress;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070056import java.net.Inet4Address;
San Mehat873f2142010-01-14 10:25:07 -080057import java.net.UnknownHostException;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070058import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080059
60/**
61 * @hide
62 */
63class NetworkManagementService extends INetworkManagementService.Stub {
64
65 private static final String TAG = "NetworkManagmentService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070066 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070067 private static final String NETD_TAG = "NetdConnector";
68
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070069 private static final int ADD = 1;
70 private static final int REMOVE = 2;
71
San Mehat873f2142010-01-14 10:25:07 -080072 class NetdResponseCode {
73 public static final int InterfaceListResult = 110;
74 public static final int TetherInterfaceListResult = 111;
75 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080076 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080077
78 public static final int TetherStatusResult = 210;
79 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080080 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080081 public static final int SoftapStatusResult = 214;
82 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070083 public static final int InterfaceRxCounterResult = 216;
84 public static final int InterfaceTxCounterResult = 217;
85 public static final int InterfaceRxThrottleResult = 218;
86 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080087
88 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080089 }
90
91 /**
92 * Binder context for this service
93 */
94 private Context mContext;
95
96 /**
97 * connector object for communicating with netd
98 */
99 private NativeDaemonConnector mConnector;
100
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700101 private Thread mThread;
102 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
103
San Mehat4d02d002010-01-22 16:07:46 -0800104 private ArrayList<INetworkManagementEventObserver> mObservers;
105
San Mehat873f2142010-01-14 10:25:07 -0800106 /**
107 * Constructs a new NetworkManagementService instance
108 *
109 * @param context Binder context for this service
110 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700111 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800112 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800113 mObservers = new ArrayList<INetworkManagementEventObserver>();
114
Marco Nelissen62dbb222010-02-18 10:56:30 -0800115 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
116 return;
117 }
118
San Mehat873f2142010-01-14 10:25:07 -0800119 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700120 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700121 mThread = new Thread(mConnector, NETD_TAG);
122 }
123
124 public static NetworkManagementService create(Context context) throws InterruptedException {
125 NetworkManagementService service = new NetworkManagementService(context);
126 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
127 service.mThread.start();
128 if (DBG) Slog.d(TAG, "Awaiting socket connection");
129 service.mConnectedSignal.await();
130 if (DBG) Slog.d(TAG, "Connected");
131 return service;
San Mehat873f2142010-01-14 10:25:07 -0800132 }
133
San Mehat4d02d002010-01-22 16:07:46 -0800134 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800135 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800136 mObservers.add(obs);
137 }
138
139 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800140 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800141 mObservers.remove(mObservers.indexOf(obs));
142 }
143
144 /**
Wink Saville1a7e6712011-01-09 12:16:38 -0800145 * Notify our observers of an interface link status change
San Mehat4d02d002010-01-22 16:07:46 -0800146 */
Wink Saville1a7e6712011-01-09 12:16:38 -0800147 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
San Mehat4d02d002010-01-22 16:07:46 -0800148 for (INetworkManagementEventObserver obs : mObservers) {
149 try {
Wink Saville1a7e6712011-01-09 12:16:38 -0800150 obs.interfaceLinkStatusChanged(iface, link);
San Mehat4d02d002010-01-22 16:07:46 -0800151 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800152 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800153 }
154 }
155 }
156
157 /**
158 * Notify our observers of an interface addition.
159 */
160 private void notifyInterfaceAdded(String iface) {
161 for (INetworkManagementEventObserver obs : mObservers) {
162 try {
163 obs.interfaceAdded(iface);
164 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800165 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800166 }
167 }
168 }
169
170 /**
171 * Notify our observers of an interface removal.
172 */
173 private void notifyInterfaceRemoved(String iface) {
174 for (INetworkManagementEventObserver obs : mObservers) {
175 try {
176 obs.interfaceRemoved(iface);
177 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800178 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800179 }
180 }
181 }
182
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700183 /**
184 * Let us know the daemon is connected
185 */
186 protected void onConnected() {
187 if (DBG) Slog.d(TAG, "onConnected");
188 mConnectedSignal.countDown();
189 }
190
San Mehat4d02d002010-01-22 16:07:46 -0800191
San Mehat873f2142010-01-14 10:25:07 -0800192 //
193 // Netd Callback handling
194 //
195
196 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
197 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700198 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800199 new Thread() {
200 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800201 }
202 }.start();
203 }
204 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800205 if (code == NetdResponseCode.InterfaceChange) {
206 /*
207 * a network interface change occured
208 * Format: "NNN Iface added <name>"
209 * "NNN Iface removed <name>"
210 * "NNN Iface changed <name> <up/down>"
211 */
212 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
213 throw new IllegalStateException(
214 String.format("Invalid event from daemon (%s)", raw));
215 }
216 if (cooked[2].equals("added")) {
217 notifyInterfaceAdded(cooked[3]);
218 return true;
219 } else if (cooked[2].equals("removed")) {
220 notifyInterfaceRemoved(cooked[3]);
221 return true;
222 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Wink Saville1a7e6712011-01-09 12:16:38 -0800223 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800224 return true;
225 }
226 throw new IllegalStateException(
227 String.format("Invalid event from daemon (%s)", raw));
228 }
229 return false;
San Mehat873f2142010-01-14 10:25:07 -0800230 }
231 }
232
San Mehated4fc8a2010-01-22 12:28:36 -0800233
San Mehat873f2142010-01-14 10:25:07 -0800234 //
235 // INetworkManagementService members
236 //
237
238 public String[] listInterfaces() throws IllegalStateException {
239 mContext.enforceCallingOrSelfPermission(
240 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
241
Kenny Roota80ce062010-06-01 13:23:53 -0700242 try {
243 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
244 } catch (NativeDaemonConnectorException e) {
245 throw new IllegalStateException(
246 "Cannot communicate with native daemon to list interfaces");
247 }
San Mehated4fc8a2010-01-22 12:28:36 -0800248 }
249
250 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700251 String rsp;
252 try {
253 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
254 } catch (NativeDaemonConnectorException e) {
255 throw new IllegalStateException(
256 "Cannot communicate with native daemon to get interface config");
257 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800258 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800259
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800260 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800261 StringTokenizer st = new StringTokenizer(rsp);
262
Kenny Roota80ce062010-06-01 13:23:53 -0700263 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800264 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700265 try {
266 int code = Integer.parseInt(st.nextToken(" "));
267 if (code != NetdResponseCode.InterfaceGetCfgResult) {
268 throw new IllegalStateException(
269 String.format("Expected code %d, but got %d",
270 NetdResponseCode.InterfaceGetCfgResult, code));
271 }
272 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800273 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700274 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800275 }
Kenny Roota80ce062010-06-01 13:23:53 -0700276
277 cfg = new InterfaceConfiguration();
278 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800279 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800280 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700281 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800282 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
283 } catch (IllegalArgumentException iae) {
284 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700285 }
286
287 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800288 prefixLength = Integer.parseInt(st.nextToken(" "));
289 } catch (NumberFormatException nfe) {
290 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700291 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800292
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800293 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700294 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
295 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800296 throw new IllegalStateException(
297 String.format("Invalid response from daemon (%s)", rsp));
298 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800299 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800300 return cfg;
301 }
302
303 public void setInterfaceConfig(
304 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800305 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800306 if (linkAddr == null || linkAddr.getAddress() == null) {
307 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800308 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800309 String cmd = String.format("interface setcfg %s %s %d %s", iface,
310 linkAddr.getAddress().getHostAddress(),
311 linkAddr.getNetworkPrefixLength(),
312 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700313 try {
314 mConnector.doCommand(cmd);
315 } catch (NativeDaemonConnectorException e) {
316 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800317 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700318 }
San Mehat873f2142010-01-14 10:25:07 -0800319 }
320
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700321 public void addRoute(String interfaceName, RouteInfo route) {
322 modifyRoute(interfaceName, ADD, route);
323 }
324
325 public void removeRoute(String interfaceName, RouteInfo route) {
326 modifyRoute(interfaceName, REMOVE, route);
327 }
328
329 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
330 ArrayList<String> rsp;
331
332 StringBuilder cmd;
333
334 switch (action) {
335 case ADD:
336 {
337 cmd = new StringBuilder("interface route add " + interfaceName);
338 break;
339 }
340 case REMOVE:
341 {
342 cmd = new StringBuilder("interface route remove " + interfaceName);
343 break;
344 }
345 default:
346 throw new IllegalStateException("Unknown action type " + action);
347 }
348
349 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
350 LinkAddress la = route.getDestination();
351 cmd.append(' ');
352 cmd.append(la.getAddress().getHostAddress());
353 cmd.append(' ');
354 cmd.append(la.getNetworkPrefixLength());
355 cmd.append(' ');
356 if (route.getGateway() == null) {
357 if (la.getAddress() instanceof Inet4Address) {
358 cmd.append("0.0.0.0");
359 } else {
360 cmd.append ("::0");
361 }
362 } else {
363 cmd.append(route.getGateway().getHostAddress());
364 }
365 try {
366 rsp = mConnector.doCommand(cmd.toString());
367 } catch (NativeDaemonConnectorException e) {
368 throw new IllegalStateException(
369 "Unable to communicate with native dameon to add routes - "
370 + e);
371 }
372
373 for (String line : rsp) {
374 Log.v(TAG, "add route response is " + line);
375 }
376 }
377
378 private ArrayList<String> readRouteList(String filename) {
379 FileInputStream fstream = null;
380 ArrayList<String> list = new ArrayList<String>();
381
382 try {
383 fstream = new FileInputStream(filename);
384 DataInputStream in = new DataInputStream(fstream);
385 BufferedReader br = new BufferedReader(new InputStreamReader(in));
386 String s;
387
388 // throw away the title line
389
390 while (((s = br.readLine()) != null) && (s.length() != 0)) {
391 list.add(s);
392 }
393 } catch (IOException ex) {
394 // return current list, possibly empty
395 } finally {
396 if (fstream != null) {
397 try {
398 fstream.close();
399 } catch (IOException ex) {}
400 }
401 }
402
403 return list;
404 }
405
406 public RouteInfo[] getRoutes(String interfaceName) {
407 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
408
409 // v4 routes listed as:
410 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
411 for (String s : readRouteList("/proc/net/route")) {
412 String[] fields = s.split("\t");
413
414 if (fields.length > 7) {
415 String iface = fields[0];
416
417 if (interfaceName.equals(iface)) {
418 String dest = fields[1];
419 String gate = fields[2];
420 String flags = fields[3]; // future use?
421 String mask = fields[7];
422 try {
423 // address stored as a hex string, ex: 0014A8C0
424 InetAddress destAddr =
425 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
426 int prefixLength =
427 NetworkUtils.netmaskIntToPrefixLength(
428 (int)Long.parseLong(mask, 16));
429 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
430
431 // address stored as a hex string, ex 0014A8C0
432 InetAddress gatewayAddr =
433 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
434
435 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
436 routes.add(route);
437 } catch (Exception e) {
438 Log.e(TAG, "Error parsing route " + s + " : " + e);
439 continue;
440 }
441 }
442 }
443 }
444
445 // v6 routes listed as:
446 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
447 for (String s : readRouteList("/proc/net/ipv6_route")) {
448 String[]fields = s.split("\\s+");
449 if (fields.length > 9) {
450 String iface = fields[9].trim();
451 if (interfaceName.equals(iface)) {
452 String dest = fields[0];
453 String prefix = fields[1];
454 String gate = fields[4];
455
456 try {
457 // prefix length stored as a hex string, ex 40
458 int prefixLength = Integer.parseInt(prefix, 16);
459
460 // address stored as a 32 char hex string
461 // ex fe800000000000000000000000000000
462 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
463 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
464
465 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
466
467 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
468 routes.add(route);
469 } catch (Exception e) {
470 Log.e(TAG, "Error parsing route " + s + " : " + e);
471 continue;
472 }
473 }
474 }
475 }
476 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
477 }
478
San Mehat873f2142010-01-14 10:25:07 -0800479 public void shutdown() {
480 if (mContext.checkCallingOrSelfPermission(
481 android.Manifest.permission.SHUTDOWN)
482 != PackageManager.PERMISSION_GRANTED) {
483 throw new SecurityException("Requires SHUTDOWN permission");
484 }
485
Joe Onorato8a9b2202010-02-26 18:56:32 -0800486 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800487 }
488
489 public boolean getIpForwardingEnabled() throws IllegalStateException{
490 mContext.enforceCallingOrSelfPermission(
491 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
492
Kenny Roota80ce062010-06-01 13:23:53 -0700493 ArrayList<String> rsp;
494 try {
495 rsp = mConnector.doCommand("ipfwd status");
496 } catch (NativeDaemonConnectorException e) {
497 throw new IllegalStateException(
498 "Unable to communicate with native daemon to ipfwd status");
499 }
San Mehat873f2142010-01-14 10:25:07 -0800500
501 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700502 String[] tok = line.split(" ");
503 if (tok.length < 3) {
504 Slog.e(TAG, "Malformed response from native daemon: " + line);
505 return false;
506 }
507
San Mehat873f2142010-01-14 10:25:07 -0800508 int code = Integer.parseInt(tok[0]);
509 if (code == NetdResponseCode.IpFwdStatusResult) {
510 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700511 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800512 } else {
513 throw new IllegalStateException(String.format("Unexpected response code %d", code));
514 }
515 }
516 throw new IllegalStateException("Got an empty response");
517 }
518
519 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
520 mContext.enforceCallingOrSelfPermission(
521 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
522 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
523 }
524
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700525 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800526 throws IllegalStateException {
527 mContext.enforceCallingOrSelfPermission(
528 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700529 // cmd is "tether start first_start first_stop second_start second_stop ..."
530 // an odd number of addrs will fail
531 String cmd = "tether start";
532 for (String d : dhcpRange) {
533 cmd += " " + d;
534 }
Kenny Roota80ce062010-06-01 13:23:53 -0700535
536 try {
537 mConnector.doCommand(cmd);
538 } catch (NativeDaemonConnectorException e) {
539 throw new IllegalStateException("Unable to communicate to native daemon");
540 }
San Mehat873f2142010-01-14 10:25:07 -0800541 }
542
543 public void stopTethering() 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("tether stop");
548 } catch (NativeDaemonConnectorException e) {
549 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
550 }
San Mehat873f2142010-01-14 10:25:07 -0800551 }
552
553 public boolean isTetheringStarted() throws IllegalStateException {
554 mContext.enforceCallingOrSelfPermission(
555 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
556
Kenny Roota80ce062010-06-01 13:23:53 -0700557 ArrayList<String> rsp;
558 try {
559 rsp = mConnector.doCommand("tether status");
560 } catch (NativeDaemonConnectorException e) {
561 throw new IllegalStateException(
562 "Unable to communicate to native daemon to get tether status");
563 }
San Mehat873f2142010-01-14 10:25:07 -0800564
565 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700566 String[] tok = line.split(" ");
567 if (tok.length < 3) {
568 throw new IllegalStateException("Malformed response for tether status: " + line);
569 }
San Mehat873f2142010-01-14 10:25:07 -0800570 int code = Integer.parseInt(tok[0]);
571 if (code == NetdResponseCode.TetherStatusResult) {
572 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700573 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800574 } else {
575 throw new IllegalStateException(String.format("Unexpected response code %d", code));
576 }
577 }
578 throw new IllegalStateException("Got an empty response");
579 }
580
581 public void tetherInterface(String iface) throws IllegalStateException {
582 mContext.enforceCallingOrSelfPermission(
583 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700584 try {
585 mConnector.doCommand("tether interface add " + iface);
586 } catch (NativeDaemonConnectorException e) {
587 throw new IllegalStateException(
588 "Unable to communicate to native daemon for adding tether interface");
589 }
San Mehat873f2142010-01-14 10:25:07 -0800590 }
591
592 public void untetherInterface(String iface) {
593 mContext.enforceCallingOrSelfPermission(
594 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700595 try {
596 mConnector.doCommand("tether interface remove " + iface);
597 } catch (NativeDaemonConnectorException e) {
598 throw new IllegalStateException(
599 "Unable to communicate to native daemon for removing tether interface");
600 }
San Mehat873f2142010-01-14 10:25:07 -0800601 }
602
603 public String[] listTetheredInterfaces() throws IllegalStateException {
604 mContext.enforceCallingOrSelfPermission(
605 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700606 try {
607 return mConnector.doListCommand(
608 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
609 } catch (NativeDaemonConnectorException e) {
610 throw new IllegalStateException(
611 "Unable to communicate to native daemon for listing tether interfaces");
612 }
San Mehat873f2142010-01-14 10:25:07 -0800613 }
614
615 public void setDnsForwarders(String[] dns) throws IllegalStateException {
616 mContext.enforceCallingOrSelfPermission(
617 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
618 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800619 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800620 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800621 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800622 }
Kenny Roota80ce062010-06-01 13:23:53 -0700623 try {
624 mConnector.doCommand(cmd);
625 } catch (NativeDaemonConnectorException e) {
626 throw new IllegalStateException(
627 "Unable to communicate to native daemon for setting tether dns");
628 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800629 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800630 throw new IllegalStateException("Error resolving dns name", e);
631 }
632 }
633
634 public String[] getDnsForwarders() throws IllegalStateException {
635 mContext.enforceCallingOrSelfPermission(
636 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700637 try {
638 return mConnector.doListCommand(
639 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
640 } catch (NativeDaemonConnectorException e) {
641 throw new IllegalStateException(
642 "Unable to communicate to native daemon for listing tether dns");
643 }
San Mehat873f2142010-01-14 10:25:07 -0800644 }
645
646 public void enableNat(String internalInterface, String externalInterface)
647 throws IllegalStateException {
648 mContext.enforceCallingOrSelfPermission(
649 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700650 try {
651 mConnector.doCommand(
652 String.format("nat enable %s %s", internalInterface, externalInterface));
653 } catch (NativeDaemonConnectorException e) {
654 throw new IllegalStateException(
655 "Unable to communicate to native daemon for enabling NAT interface");
656 }
San Mehat873f2142010-01-14 10:25:07 -0800657 }
658
659 public void disableNat(String internalInterface, String externalInterface)
660 throws IllegalStateException {
661 mContext.enforceCallingOrSelfPermission(
662 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700663 try {
664 mConnector.doCommand(
665 String.format("nat disable %s %s", internalInterface, externalInterface));
666 } catch (NativeDaemonConnectorException e) {
667 throw new IllegalStateException(
668 "Unable to communicate to native daemon for disabling NAT interface");
669 }
San Mehat873f2142010-01-14 10:25:07 -0800670 }
San Mehat72759df2010-01-19 13:50:37 -0800671
672 public String[] listTtys() throws IllegalStateException {
673 mContext.enforceCallingOrSelfPermission(
674 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700675 try {
676 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
677 } catch (NativeDaemonConnectorException e) {
678 throw new IllegalStateException(
679 "Unable to communicate to native daemon for listing TTYs");
680 }
San Mehat72759df2010-01-19 13:50:37 -0800681 }
682
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800683 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
684 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800685 try {
686 mContext.enforceCallingOrSelfPermission(
687 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800688 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800689 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
690 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
691 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
692 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
693 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800694 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700695 } catch (NativeDaemonConnectorException e) {
696 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800697 }
698 }
699
700 public void detachPppd(String tty) throws IllegalStateException {
701 mContext.enforceCallingOrSelfPermission(
702 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700703 try {
704 mConnector.doCommand(String.format("pppd detach %s", tty));
705 } catch (NativeDaemonConnectorException e) {
706 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
707 }
San Mehat72759df2010-01-19 13:50:37 -0800708 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800709
710 public void startUsbRNDIS() throws IllegalStateException {
711 mContext.enforceCallingOrSelfPermission(
712 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700713 try {
714 mConnector.doCommand("usb startrndis");
715 } catch (NativeDaemonConnectorException e) {
716 throw new IllegalStateException(
717 "Error communicating to native daemon for starting RNDIS", e);
718 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800719 }
720
721 public void stopUsbRNDIS() throws IllegalStateException {
722 mContext.enforceCallingOrSelfPermission(
723 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700724 try {
725 mConnector.doCommand("usb stoprndis");
726 } catch (NativeDaemonConnectorException e) {
727 throw new IllegalStateException("Error communicating to native daemon", e);
728 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800729 }
730
731 public boolean isUsbRNDISStarted() throws IllegalStateException {
732 mContext.enforceCallingOrSelfPermission(
733 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700734 ArrayList<String> rsp;
735 try {
736 rsp = mConnector.doCommand("usb rndisstatus");
737 } catch (NativeDaemonConnectorException e) {
738 throw new IllegalStateException(
739 "Error communicating to native daemon to check RNDIS status", e);
740 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800741
742 for (String line : rsp) {
743 String []tok = line.split(" ");
744 int code = Integer.parseInt(tok[0]);
745 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500746 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800747 return true;
748 return false;
749 } else {
750 throw new IllegalStateException(String.format("Unexpected response code %d", code));
751 }
752 }
753 throw new IllegalStateException("Got an empty response");
754 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800755
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700756 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800757 throws IllegalStateException {
758 mContext.enforceCallingOrSelfPermission(
759 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
760 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700761 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700762 try {
763 mConnector.doCommand(String.format("softap stop " + wlanIface));
764 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
765 mConnector.doCommand(String.format("softap start " + wlanIface));
766 if (wifiConfig == null) {
767 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
768 } else {
769 /**
770 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
771 * argv1 - wlan interface
772 * argv2 - softap interface
773 * argv3 - SSID
774 * argv4 - Security
775 * argv5 - Key
776 * argv6 - Channel
777 * argv7 - Preamble
778 * argv8 - Max SCB
779 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800780 String str = String.format("softap set " + wlanIface + " " + softapIface +
781 " %s %s %s", convertQuotedString(wifiConfig.SSID),
782 getSecurityType(wifiConfig),
783 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700784 mConnector.doCommand(str);
785 }
786 mConnector.doCommand(String.format("softap startap"));
787 } catch (NativeDaemonConnectorException e) {
788 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800789 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800790 }
791
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700792 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700793 if (s == null) {
794 return s;
795 }
796 /* Replace \ with \\, then " with \" and add quotes at end */
797 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700798 }
799
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800800 private String getSecurityType(WifiConfiguration wifiConfig) {
801 switch (wifiConfig.getAuthType()) {
802 case KeyMgmt.WPA_PSK:
803 return "wpa-psk";
804 case KeyMgmt.WPA2_PSK:
805 return "wpa2-psk";
806 default:
807 return "open";
808 }
809 }
810
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800811 public void stopAccessPoint() throws IllegalStateException {
812 mContext.enforceCallingOrSelfPermission(
813 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
814 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700815 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700816 try {
817 mConnector.doCommand("softap stopap");
818 } catch (NativeDaemonConnectorException e) {
819 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
820 e);
821 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800822 }
823
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700824 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
825 throws IllegalStateException {
826 mContext.enforceCallingOrSelfPermission(
827 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
828 mContext.enforceCallingOrSelfPermission(
829 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700830 try {
831 if (wifiConfig == null) {
832 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
833 } else {
834 String str = String.format("softap set " + wlanIface + " " + softapIface
835 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800836 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700837 convertQuotedString(wifiConfig.preSharedKey));
838 mConnector.doCommand(str);
839 }
840 } catch (NativeDaemonConnectorException e) {
841 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
842 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700843 }
844 }
San Mehat91cac642010-03-31 14:31:36 -0700845
846 private long getInterfaceCounter(String iface, boolean rx) {
847 mContext.enforceCallingOrSelfPermission(
848 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
849 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700850 String rsp;
851 try {
852 rsp = mConnector.doCommand(
853 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
854 } catch (NativeDaemonConnectorException e1) {
855 Slog.e(TAG, "Error communicating with native daemon", e1);
856 return -1;
857 }
858
859 String[] tok = rsp.split(" ");
860 if (tok.length < 2) {
861 Slog.e(TAG, String.format("Malformed response for reading %s interface",
862 (rx ? "rx" : "tx")));
863 return -1;
864 }
865
San Mehat91cac642010-03-31 14:31:36 -0700866 int code;
867 try {
868 code = Integer.parseInt(tok[0]);
869 } catch (NumberFormatException nfe) {
870 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
871 return -1;
872 }
873 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
874 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
875 Slog.e(TAG, String.format("Unexpected response code %d", code));
876 return -1;
877 }
878 return Long.parseLong(tok[1]);
879 } catch (Exception e) {
880 Slog.e(TAG, String.format(
881 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
882 }
883 return -1;
884 }
885
886 public long getInterfaceRxCounter(String iface) {
887 return getInterfaceCounter(iface, true);
888 }
889
890 public long getInterfaceTxCounter(String iface) {
891 return getInterfaceCounter(iface, false);
892 }
893
San Mehatf0db6e12010-04-07 15:22:10 -0700894 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700895 mContext.enforceCallingOrSelfPermission(
896 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700897 try {
898 mConnector.doCommand(String.format(
899 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
900 } catch (NativeDaemonConnectorException e) {
901 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
902 }
San Mehat91cac642010-03-31 14:31:36 -0700903 }
904
905 private int getInterfaceThrottle(String iface, boolean rx) {
906 mContext.enforceCallingOrSelfPermission(
907 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
908 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700909 String rsp;
910 try {
911 rsp = mConnector.doCommand(
912 String.format("interface getthrottle %s %s", iface,
913 (rx ? "rx" : "tx"))).get(0);
914 } catch (NativeDaemonConnectorException e) {
915 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
916 return -1;
917 }
918
919 String[] tok = rsp.split(" ");
920 if (tok.length < 2) {
921 Slog.e(TAG, "Malformed response to getthrottle command");
922 return -1;
923 }
924
San Mehat91cac642010-03-31 14:31:36 -0700925 int code;
926 try {
927 code = Integer.parseInt(tok[0]);
928 } catch (NumberFormatException nfe) {
929 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
930 return -1;
931 }
932 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
933 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
934 Slog.e(TAG, String.format("Unexpected response code %d", code));
935 return -1;
936 }
937 return Integer.parseInt(tok[1]);
938 } catch (Exception e) {
939 Slog.e(TAG, String.format(
940 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
941 }
942 return -1;
943 }
944
945 public int getInterfaceRxThrottle(String iface) {
946 return getInterfaceThrottle(iface, true);
947 }
948
949 public int getInterfaceTxThrottle(String iface) {
950 return getInterfaceThrottle(iface, false);
951 }
San Mehat873f2142010-01-14 10:25:07 -0800952}