blob: 4290ce757e349d5324621a6078f89377478f6c4b [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;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080029import android.net.wifi.WifiConfiguration;
30import android.net.wifi.WifiConfiguration.KeyMgmt;
San Mehat873f2142010-01-14 10:25:07 -080031import android.os.INetworkManagementService;
32import android.os.Handler;
Marco Nelissen62dbb222010-02-18 10:56:30 -080033import android.os.SystemProperties;
San Mehat873f2142010-01-14 10:25:07 -080034import android.text.TextUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080035import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080036import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080037import java.util.ArrayList;
Kenny Roota80ce062010-06-01 13:23:53 -070038import java.util.NoSuchElementException;
San Mehated4fc8a2010-01-22 12:28:36 -080039import java.util.StringTokenizer;
San Mehat873f2142010-01-14 10:25:07 -080040import android.provider.Settings;
41import android.content.ContentResolver;
42import android.database.ContentObserver;
43
44import java.io.File;
45import java.io.FileReader;
46import java.lang.IllegalStateException;
47
48import java.net.InetAddress;
49import java.net.UnknownHostException;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070050import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080051
52/**
53 * @hide
54 */
55class NetworkManagementService extends INetworkManagementService.Stub {
56
57 private static final String TAG = "NetworkManagmentService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070058 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070059 private static final String NETD_TAG = "NetdConnector";
60
San Mehat873f2142010-01-14 10:25:07 -080061 class NetdResponseCode {
62 public static final int InterfaceListResult = 110;
63 public static final int TetherInterfaceListResult = 111;
64 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080065 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080066
67 public static final int TetherStatusResult = 210;
68 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080069 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080070 public static final int SoftapStatusResult = 214;
71 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070072 public static final int InterfaceRxCounterResult = 216;
73 public static final int InterfaceTxCounterResult = 217;
74 public static final int InterfaceRxThrottleResult = 218;
75 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080076
77 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080078 }
79
80 /**
81 * Binder context for this service
82 */
83 private Context mContext;
84
85 /**
86 * connector object for communicating with netd
87 */
88 private NativeDaemonConnector mConnector;
89
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070090 private Thread mThread;
91 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
92
San Mehat4d02d002010-01-22 16:07:46 -080093 private ArrayList<INetworkManagementEventObserver> mObservers;
94
San Mehat873f2142010-01-14 10:25:07 -080095 /**
96 * Constructs a new NetworkManagementService instance
97 *
98 * @param context Binder context for this service
99 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700100 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800101 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800102 mObservers = new ArrayList<INetworkManagementEventObserver>();
103
Marco Nelissen62dbb222010-02-18 10:56:30 -0800104 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
105 return;
106 }
107
San Mehat873f2142010-01-14 10:25:07 -0800108 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700109 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700110 mThread = new Thread(mConnector, NETD_TAG);
111 }
112
113 public static NetworkManagementService create(Context context) throws InterruptedException {
114 NetworkManagementService service = new NetworkManagementService(context);
115 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
116 service.mThread.start();
117 if (DBG) Slog.d(TAG, "Awaiting socket connection");
118 service.mConnectedSignal.await();
119 if (DBG) Slog.d(TAG, "Connected");
120 return service;
San Mehat873f2142010-01-14 10:25:07 -0800121 }
122
San Mehat4d02d002010-01-22 16:07:46 -0800123 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800124 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800125 mObservers.add(obs);
126 }
127
128 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800129 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800130 mObservers.remove(mObservers.indexOf(obs));
131 }
132
133 /**
134 * Notify our observers of an interface link status change
135 */
136 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
137 for (INetworkManagementEventObserver obs : mObservers) {
138 try {
139 obs.interfaceLinkStatusChanged(iface, link);
140 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800141 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800142 }
143 }
144 }
145
146 /**
147 * Notify our observers of an interface addition.
148 */
149 private void notifyInterfaceAdded(String iface) {
150 for (INetworkManagementEventObserver obs : mObservers) {
151 try {
152 obs.interfaceAdded(iface);
153 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800154 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800155 }
156 }
157 }
158
159 /**
160 * Notify our observers of an interface removal.
161 */
162 private void notifyInterfaceRemoved(String iface) {
163 for (INetworkManagementEventObserver obs : mObservers) {
164 try {
165 obs.interfaceRemoved(iface);
166 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800167 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800168 }
169 }
170 }
171
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700172 /**
173 * Let us know the daemon is connected
174 */
175 protected void onConnected() {
176 if (DBG) Slog.d(TAG, "onConnected");
177 mConnectedSignal.countDown();
178 }
179
San Mehat4d02d002010-01-22 16:07:46 -0800180
San Mehat873f2142010-01-14 10:25:07 -0800181 //
182 // Netd Callback handling
183 //
184
185 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
186 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700187 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800188 new Thread() {
189 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800190 }
191 }.start();
192 }
193 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800194 if (code == NetdResponseCode.InterfaceChange) {
195 /*
196 * a network interface change occured
197 * Format: "NNN Iface added <name>"
198 * "NNN Iface removed <name>"
199 * "NNN Iface changed <name> <up/down>"
200 */
201 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
202 throw new IllegalStateException(
203 String.format("Invalid event from daemon (%s)", raw));
204 }
205 if (cooked[2].equals("added")) {
206 notifyInterfaceAdded(cooked[3]);
207 return true;
208 } else if (cooked[2].equals("removed")) {
209 notifyInterfaceRemoved(cooked[3]);
210 return true;
211 } else if (cooked[2].equals("changed") && cooked.length == 5) {
212 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
213 return true;
214 }
215 throw new IllegalStateException(
216 String.format("Invalid event from daemon (%s)", raw));
217 }
218 return false;
San Mehat873f2142010-01-14 10:25:07 -0800219 }
220 }
221
San Mehated4fc8a2010-01-22 12:28:36 -0800222
San Mehat873f2142010-01-14 10:25:07 -0800223 //
224 // INetworkManagementService members
225 //
226
227 public String[] listInterfaces() throws IllegalStateException {
228 mContext.enforceCallingOrSelfPermission(
229 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
230
Kenny Roota80ce062010-06-01 13:23:53 -0700231 try {
232 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
233 } catch (NativeDaemonConnectorException e) {
234 throw new IllegalStateException(
235 "Cannot communicate with native daemon to list interfaces");
236 }
San Mehated4fc8a2010-01-22 12:28:36 -0800237 }
238
239 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700240 String rsp;
241 try {
242 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
243 } catch (NativeDaemonConnectorException e) {
244 throw new IllegalStateException(
245 "Cannot communicate with native daemon to get interface config");
246 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800247 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800248
249 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
250 StringTokenizer st = new StringTokenizer(rsp);
251
Kenny Roota80ce062010-06-01 13:23:53 -0700252 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800253 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700254 try {
255 int code = Integer.parseInt(st.nextToken(" "));
256 if (code != NetdResponseCode.InterfaceGetCfgResult) {
257 throw new IllegalStateException(
258 String.format("Expected code %d, but got %d",
259 NetdResponseCode.InterfaceGetCfgResult, code));
260 }
261 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800262 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700263 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800264 }
Kenny Roota80ce062010-06-01 13:23:53 -0700265
266 cfg = new InterfaceConfiguration();
267 cfg.hwAddr = st.nextToken(" ");
268 try {
Robert Greenwalt04808c22010-12-13 17:01:41 -0800269 cfg.addr = InetAddress.getByName(st.nextToken(" "));
Kenny Roota80ce062010-06-01 13:23:53 -0700270 } catch (UnknownHostException uhe) {
271 Slog.e(TAG, "Failed to parse ipaddr", uhe);
Kenny Roota80ce062010-06-01 13:23:53 -0700272 }
273
274 try {
Robert Greenwalt04808c22010-12-13 17:01:41 -0800275 cfg.mask = InetAddress.getByName(st.nextToken(" "));
Kenny Roota80ce062010-06-01 13:23:53 -0700276 } catch (UnknownHostException uhe) {
277 Slog.e(TAG, "Failed to parse netmask", uhe);
Kenny Roota80ce062010-06-01 13:23:53 -0700278 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800279
Kenny Roota80ce062010-06-01 13:23:53 -0700280 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
281 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800282 throw new IllegalStateException(
283 String.format("Invalid response from daemon (%s)", rsp));
284 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800285 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800286 return cfg;
287 }
288
289 public void setInterfaceConfig(
290 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalt65ae29b2010-02-18 11:25:54 -0800291 String cmd = String.format("interface setcfg %s %s %s %s", iface,
Robert Greenwalt04808c22010-12-13 17:01:41 -0800292 cfg.addr.getHostAddress(), cfg.mask.getHostAddress(),
293 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700294 try {
295 mConnector.doCommand(cmd);
296 } catch (NativeDaemonConnectorException e) {
297 throw new IllegalStateException(
298 "Unable to communicate with native daemon to interface setcfg");
299 }
San Mehat873f2142010-01-14 10:25:07 -0800300 }
301
302 public void shutdown() {
303 if (mContext.checkCallingOrSelfPermission(
304 android.Manifest.permission.SHUTDOWN)
305 != PackageManager.PERMISSION_GRANTED) {
306 throw new SecurityException("Requires SHUTDOWN permission");
307 }
308
Joe Onorato8a9b2202010-02-26 18:56:32 -0800309 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800310 }
311
312 public boolean getIpForwardingEnabled() throws IllegalStateException{
313 mContext.enforceCallingOrSelfPermission(
314 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
315
Kenny Roota80ce062010-06-01 13:23:53 -0700316 ArrayList<String> rsp;
317 try {
318 rsp = mConnector.doCommand("ipfwd status");
319 } catch (NativeDaemonConnectorException e) {
320 throw new IllegalStateException(
321 "Unable to communicate with native daemon to ipfwd status");
322 }
San Mehat873f2142010-01-14 10:25:07 -0800323
324 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700325 String[] tok = line.split(" ");
326 if (tok.length < 3) {
327 Slog.e(TAG, "Malformed response from native daemon: " + line);
328 return false;
329 }
330
San Mehat873f2142010-01-14 10:25:07 -0800331 int code = Integer.parseInt(tok[0]);
332 if (code == NetdResponseCode.IpFwdStatusResult) {
333 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700334 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800335 } else {
336 throw new IllegalStateException(String.format("Unexpected response code %d", code));
337 }
338 }
339 throw new IllegalStateException("Got an empty response");
340 }
341
342 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
343 mContext.enforceCallingOrSelfPermission(
344 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
345 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
346 }
347
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700348 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800349 throws IllegalStateException {
350 mContext.enforceCallingOrSelfPermission(
351 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700352 // cmd is "tether start first_start first_stop second_start second_stop ..."
353 // an odd number of addrs will fail
354 String cmd = "tether start";
355 for (String d : dhcpRange) {
356 cmd += " " + d;
357 }
Kenny Roota80ce062010-06-01 13:23:53 -0700358
359 try {
360 mConnector.doCommand(cmd);
361 } catch (NativeDaemonConnectorException e) {
362 throw new IllegalStateException("Unable to communicate to native daemon");
363 }
San Mehat873f2142010-01-14 10:25:07 -0800364 }
365
366 public void stopTethering() throws IllegalStateException {
367 mContext.enforceCallingOrSelfPermission(
368 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700369 try {
370 mConnector.doCommand("tether stop");
371 } catch (NativeDaemonConnectorException e) {
372 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
373 }
San Mehat873f2142010-01-14 10:25:07 -0800374 }
375
376 public boolean isTetheringStarted() throws IllegalStateException {
377 mContext.enforceCallingOrSelfPermission(
378 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
379
Kenny Roota80ce062010-06-01 13:23:53 -0700380 ArrayList<String> rsp;
381 try {
382 rsp = mConnector.doCommand("tether status");
383 } catch (NativeDaemonConnectorException e) {
384 throw new IllegalStateException(
385 "Unable to communicate to native daemon to get tether status");
386 }
San Mehat873f2142010-01-14 10:25:07 -0800387
388 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700389 String[] tok = line.split(" ");
390 if (tok.length < 3) {
391 throw new IllegalStateException("Malformed response for tether status: " + line);
392 }
San Mehat873f2142010-01-14 10:25:07 -0800393 int code = Integer.parseInt(tok[0]);
394 if (code == NetdResponseCode.TetherStatusResult) {
395 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700396 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800397 } else {
398 throw new IllegalStateException(String.format("Unexpected response code %d", code));
399 }
400 }
401 throw new IllegalStateException("Got an empty response");
402 }
403
404 public void tetherInterface(String iface) throws IllegalStateException {
405 mContext.enforceCallingOrSelfPermission(
406 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700407 try {
408 mConnector.doCommand("tether interface add " + iface);
409 } catch (NativeDaemonConnectorException e) {
410 throw new IllegalStateException(
411 "Unable to communicate to native daemon for adding tether interface");
412 }
San Mehat873f2142010-01-14 10:25:07 -0800413 }
414
415 public void untetherInterface(String iface) {
416 mContext.enforceCallingOrSelfPermission(
417 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700418 try {
419 mConnector.doCommand("tether interface remove " + iface);
420 } catch (NativeDaemonConnectorException e) {
421 throw new IllegalStateException(
422 "Unable to communicate to native daemon for removing tether interface");
423 }
San Mehat873f2142010-01-14 10:25:07 -0800424 }
425
426 public String[] listTetheredInterfaces() throws IllegalStateException {
427 mContext.enforceCallingOrSelfPermission(
428 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700429 try {
430 return mConnector.doListCommand(
431 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
432 } catch (NativeDaemonConnectorException e) {
433 throw new IllegalStateException(
434 "Unable to communicate to native daemon for listing tether interfaces");
435 }
San Mehat873f2142010-01-14 10:25:07 -0800436 }
437
438 public void setDnsForwarders(String[] dns) throws IllegalStateException {
439 mContext.enforceCallingOrSelfPermission(
440 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
441 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800442 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800443 for (String s : dns) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800444 cmd += " " + InetAddress.getByName(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800445 }
Kenny Roota80ce062010-06-01 13:23:53 -0700446 try {
447 mConnector.doCommand(cmd);
448 } catch (NativeDaemonConnectorException e) {
449 throw new IllegalStateException(
450 "Unable to communicate to native daemon for setting tether dns");
451 }
San Mehat873f2142010-01-14 10:25:07 -0800452 } catch (UnknownHostException e) {
453 throw new IllegalStateException("Error resolving dns name", e);
454 }
455 }
456
457 public String[] getDnsForwarders() throws IllegalStateException {
458 mContext.enforceCallingOrSelfPermission(
459 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700460 try {
461 return mConnector.doListCommand(
462 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
463 } catch (NativeDaemonConnectorException e) {
464 throw new IllegalStateException(
465 "Unable to communicate to native daemon for listing tether dns");
466 }
San Mehat873f2142010-01-14 10:25:07 -0800467 }
468
469 public void enableNat(String internalInterface, String externalInterface)
470 throws IllegalStateException {
471 mContext.enforceCallingOrSelfPermission(
472 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700473 try {
474 mConnector.doCommand(
475 String.format("nat enable %s %s", internalInterface, externalInterface));
476 } catch (NativeDaemonConnectorException e) {
477 throw new IllegalStateException(
478 "Unable to communicate to native daemon for enabling NAT interface");
479 }
San Mehat873f2142010-01-14 10:25:07 -0800480 }
481
482 public void disableNat(String internalInterface, String externalInterface)
483 throws IllegalStateException {
484 mContext.enforceCallingOrSelfPermission(
485 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700486 try {
487 mConnector.doCommand(
488 String.format("nat disable %s %s", internalInterface, externalInterface));
489 } catch (NativeDaemonConnectorException e) {
490 throw new IllegalStateException(
491 "Unable to communicate to native daemon for disabling NAT interface");
492 }
San Mehat873f2142010-01-14 10:25:07 -0800493 }
San Mehat72759df2010-01-19 13:50:37 -0800494
495 public String[] listTtys() throws IllegalStateException {
496 mContext.enforceCallingOrSelfPermission(
497 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700498 try {
499 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
500 } catch (NativeDaemonConnectorException e) {
501 throw new IllegalStateException(
502 "Unable to communicate to native daemon for listing TTYs");
503 }
San Mehat72759df2010-01-19 13:50:37 -0800504 }
505
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800506 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
507 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800508 try {
509 mContext.enforceCallingOrSelfPermission(
510 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800511 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
512 InetAddress.getByName(localAddr).getHostAddress(),
513 InetAddress.getByName(remoteAddr).getHostAddress(),
514 InetAddress.getByName(dns1Addr).getHostAddress(),
515 InetAddress.getByName(dns2Addr).getHostAddress()));
San Mehat72759df2010-01-19 13:50:37 -0800516 } catch (UnknownHostException e) {
517 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700518 } catch (NativeDaemonConnectorException e) {
519 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800520 }
521 }
522
523 public void detachPppd(String tty) throws IllegalStateException {
524 mContext.enforceCallingOrSelfPermission(
525 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700526 try {
527 mConnector.doCommand(String.format("pppd detach %s", tty));
528 } catch (NativeDaemonConnectorException e) {
529 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
530 }
San Mehat72759df2010-01-19 13:50:37 -0800531 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800532
533 public void startUsbRNDIS() 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("usb startrndis");
538 } catch (NativeDaemonConnectorException e) {
539 throw new IllegalStateException(
540 "Error communicating to native daemon for starting RNDIS", e);
541 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800542 }
543
544 public void stopUsbRNDIS() throws IllegalStateException {
545 mContext.enforceCallingOrSelfPermission(
546 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700547 try {
548 mConnector.doCommand("usb stoprndis");
549 } catch (NativeDaemonConnectorException e) {
550 throw new IllegalStateException("Error communicating to native daemon", e);
551 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800552 }
553
554 public boolean isUsbRNDISStarted() throws IllegalStateException {
555 mContext.enforceCallingOrSelfPermission(
556 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700557 ArrayList<String> rsp;
558 try {
559 rsp = mConnector.doCommand("usb rndisstatus");
560 } catch (NativeDaemonConnectorException e) {
561 throw new IllegalStateException(
562 "Error communicating to native daemon to check RNDIS status", e);
563 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800564
565 for (String line : rsp) {
566 String []tok = line.split(" ");
567 int code = Integer.parseInt(tok[0]);
568 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500569 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800570 return true;
571 return false;
572 } else {
573 throw new IllegalStateException(String.format("Unexpected response code %d", code));
574 }
575 }
576 throw new IllegalStateException("Got an empty response");
577 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800578
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700579 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800580 throws IllegalStateException {
581 mContext.enforceCallingOrSelfPermission(
582 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
583 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700584 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700585 try {
586 mConnector.doCommand(String.format("softap stop " + wlanIface));
587 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
588 mConnector.doCommand(String.format("softap start " + wlanIface));
589 if (wifiConfig == null) {
590 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
591 } else {
592 /**
593 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
594 * argv1 - wlan interface
595 * argv2 - softap interface
596 * argv3 - SSID
597 * argv4 - Security
598 * argv5 - Key
599 * argv6 - Channel
600 * argv7 - Preamble
601 * argv8 - Max SCB
602 */
603 String str = String.format("softap set " + wlanIface + " " + softapIface +
604 " %s %s %s", convertQuotedString(wifiConfig.SSID),
605 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
606 "wpa2-psk" : "open",
607 convertQuotedString(wifiConfig.preSharedKey));
608 mConnector.doCommand(str);
609 }
610 mConnector.doCommand(String.format("softap startap"));
611 } catch (NativeDaemonConnectorException e) {
612 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800613 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800614 }
615
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700616 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700617 if (s == null) {
618 return s;
619 }
620 /* Replace \ with \\, then " with \" and add quotes at end */
621 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700622 }
623
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800624 public void stopAccessPoint() throws IllegalStateException {
625 mContext.enforceCallingOrSelfPermission(
626 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
627 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700628 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700629 try {
630 mConnector.doCommand("softap stopap");
631 } catch (NativeDaemonConnectorException e) {
632 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
633 e);
634 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800635 }
636
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700637 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
638 throws IllegalStateException {
639 mContext.enforceCallingOrSelfPermission(
640 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
641 mContext.enforceCallingOrSelfPermission(
642 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700643 try {
644 if (wifiConfig == null) {
645 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
646 } else {
647 String str = String.format("softap set " + wlanIface + " " + softapIface
648 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
649 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open",
650 convertQuotedString(wifiConfig.preSharedKey));
651 mConnector.doCommand(str);
652 }
653 } catch (NativeDaemonConnectorException e) {
654 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
655 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700656 }
657 }
San Mehat91cac642010-03-31 14:31:36 -0700658
659 private long getInterfaceCounter(String iface, boolean rx) {
660 mContext.enforceCallingOrSelfPermission(
661 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
662 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700663 String rsp;
664 try {
665 rsp = mConnector.doCommand(
666 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
667 } catch (NativeDaemonConnectorException e1) {
668 Slog.e(TAG, "Error communicating with native daemon", e1);
669 return -1;
670 }
671
672 String[] tok = rsp.split(" ");
673 if (tok.length < 2) {
674 Slog.e(TAG, String.format("Malformed response for reading %s interface",
675 (rx ? "rx" : "tx")));
676 return -1;
677 }
678
San Mehat91cac642010-03-31 14:31:36 -0700679 int code;
680 try {
681 code = Integer.parseInt(tok[0]);
682 } catch (NumberFormatException nfe) {
683 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
684 return -1;
685 }
686 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
687 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
688 Slog.e(TAG, String.format("Unexpected response code %d", code));
689 return -1;
690 }
691 return Long.parseLong(tok[1]);
692 } catch (Exception e) {
693 Slog.e(TAG, String.format(
694 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
695 }
696 return -1;
697 }
698
699 public long getInterfaceRxCounter(String iface) {
700 return getInterfaceCounter(iface, true);
701 }
702
703 public long getInterfaceTxCounter(String iface) {
704 return getInterfaceCounter(iface, false);
705 }
706
San Mehatf0db6e12010-04-07 15:22:10 -0700707 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700708 mContext.enforceCallingOrSelfPermission(
709 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700710 try {
711 mConnector.doCommand(String.format(
712 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
713 } catch (NativeDaemonConnectorException e) {
714 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
715 }
San Mehat91cac642010-03-31 14:31:36 -0700716 }
717
718 private int getInterfaceThrottle(String iface, boolean rx) {
719 mContext.enforceCallingOrSelfPermission(
720 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
721 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700722 String rsp;
723 try {
724 rsp = mConnector.doCommand(
725 String.format("interface getthrottle %s %s", iface,
726 (rx ? "rx" : "tx"))).get(0);
727 } catch (NativeDaemonConnectorException e) {
728 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
729 return -1;
730 }
731
732 String[] tok = rsp.split(" ");
733 if (tok.length < 2) {
734 Slog.e(TAG, "Malformed response to getthrottle command");
735 return -1;
736 }
737
San Mehat91cac642010-03-31 14:31:36 -0700738 int code;
739 try {
740 code = Integer.parseInt(tok[0]);
741 } catch (NumberFormatException nfe) {
742 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
743 return -1;
744 }
745 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
746 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
747 Slog.e(TAG, String.format("Unexpected response code %d", code));
748 return -1;
749 }
750 return Integer.parseInt(tok[1]);
751 } catch (Exception e) {
752 Slog.e(TAG, String.format(
753 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
754 }
755 return -1;
756 }
757
758 public int getInterfaceRxThrottle(String iface) {
759 return getInterfaceThrottle(iface, true);
760 }
761
762 public int getInterfaceTxThrottle(String iface) {
763 return getInterfaceThrottle(iface, false);
764 }
San Mehat873f2142010-01-14 10:25:07 -0800765}