blob: 33b19d6f82cd833a986391cd0b478f45306f8571 [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";
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070058 private static final boolean DBG = true;
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 private static int stringToIpAddr(String addrString) throws UnknownHostException {
223 try {
224 String[] parts = addrString.split("\\.");
225 if (parts.length != 4) {
226 throw new UnknownHostException(addrString);
227 }
228
229 int a = Integer.parseInt(parts[0]) ;
230 int b = Integer.parseInt(parts[1]) << 8;
231 int c = Integer.parseInt(parts[2]) << 16;
232 int d = Integer.parseInt(parts[3]) << 24;
233
234 return a | b | c | d;
235 } catch (NumberFormatException ex) {
236 throw new UnknownHostException(addrString);
237 }
238 }
239
240 public static String intToIpString(int i) {
241 return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >> 8 ) & 0xFF) + "." +
242 (i & 0xFF);
243 }
244
San Mehat873f2142010-01-14 10:25:07 -0800245 //
246 // INetworkManagementService members
247 //
248
249 public String[] listInterfaces() throws IllegalStateException {
250 mContext.enforceCallingOrSelfPermission(
251 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
252
Kenny Roota80ce062010-06-01 13:23:53 -0700253 try {
254 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
255 } catch (NativeDaemonConnectorException e) {
256 throw new IllegalStateException(
257 "Cannot communicate with native daemon to list interfaces");
258 }
San Mehated4fc8a2010-01-22 12:28:36 -0800259 }
260
261 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700262 String rsp;
263 try {
264 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
265 } catch (NativeDaemonConnectorException e) {
266 throw new IllegalStateException(
267 "Cannot communicate with native daemon to get interface config");
268 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800269 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800270
271 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
272 StringTokenizer st = new StringTokenizer(rsp);
273
Kenny Roota80ce062010-06-01 13:23:53 -0700274 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800275 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700276 try {
277 int code = Integer.parseInt(st.nextToken(" "));
278 if (code != NetdResponseCode.InterfaceGetCfgResult) {
279 throw new IllegalStateException(
280 String.format("Expected code %d, but got %d",
281 NetdResponseCode.InterfaceGetCfgResult, code));
282 }
283 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800284 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700285 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800286 }
Kenny Roota80ce062010-06-01 13:23:53 -0700287
288 cfg = new InterfaceConfiguration();
289 cfg.hwAddr = st.nextToken(" ");
290 try {
291 cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
292 } catch (UnknownHostException uhe) {
293 Slog.e(TAG, "Failed to parse ipaddr", uhe);
294 cfg.ipAddr = 0;
295 }
296
297 try {
298 cfg.netmask = stringToIpAddr(st.nextToken(" "));
299 } catch (UnknownHostException uhe) {
300 Slog.e(TAG, "Failed to parse netmask", uhe);
301 cfg.netmask = 0;
302 }
303 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
304 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800305 throw new IllegalStateException(
306 String.format("Invalid response from daemon (%s)", rsp));
307 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800308 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800309 return cfg;
310 }
311
312 public void setInterfaceConfig(
313 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalt65ae29b2010-02-18 11:25:54 -0800314 String cmd = String.format("interface setcfg %s %s %s %s", iface,
San Mehated4fc8a2010-01-22 12:28:36 -0800315 intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700316 try {
317 mConnector.doCommand(cmd);
318 } catch (NativeDaemonConnectorException e) {
319 throw new IllegalStateException(
320 "Unable to communicate with native daemon to interface setcfg");
321 }
San Mehat873f2142010-01-14 10:25:07 -0800322 }
323
324 public void shutdown() {
325 if (mContext.checkCallingOrSelfPermission(
326 android.Manifest.permission.SHUTDOWN)
327 != PackageManager.PERMISSION_GRANTED) {
328 throw new SecurityException("Requires SHUTDOWN permission");
329 }
330
Joe Onorato8a9b2202010-02-26 18:56:32 -0800331 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800332 }
333
334 public boolean getIpForwardingEnabled() throws IllegalStateException{
335 mContext.enforceCallingOrSelfPermission(
336 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
337
Kenny Roota80ce062010-06-01 13:23:53 -0700338 ArrayList<String> rsp;
339 try {
340 rsp = mConnector.doCommand("ipfwd status");
341 } catch (NativeDaemonConnectorException e) {
342 throw new IllegalStateException(
343 "Unable to communicate with native daemon to ipfwd status");
344 }
San Mehat873f2142010-01-14 10:25:07 -0800345
346 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700347 String[] tok = line.split(" ");
348 if (tok.length < 3) {
349 Slog.e(TAG, "Malformed response from native daemon: " + line);
350 return false;
351 }
352
San Mehat873f2142010-01-14 10:25:07 -0800353 int code = Integer.parseInt(tok[0]);
354 if (code == NetdResponseCode.IpFwdStatusResult) {
355 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700356 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800357 } else {
358 throw new IllegalStateException(String.format("Unexpected response code %d", code));
359 }
360 }
361 throw new IllegalStateException("Got an empty response");
362 }
363
364 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
365 mContext.enforceCallingOrSelfPermission(
366 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
367 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
368 }
369
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700370 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800371 throws IllegalStateException {
372 mContext.enforceCallingOrSelfPermission(
373 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700374 // cmd is "tether start first_start first_stop second_start second_stop ..."
375 // an odd number of addrs will fail
376 String cmd = "tether start";
377 for (String d : dhcpRange) {
378 cmd += " " + d;
379 }
Kenny Roota80ce062010-06-01 13:23:53 -0700380
381 try {
382 mConnector.doCommand(cmd);
383 } catch (NativeDaemonConnectorException e) {
384 throw new IllegalStateException("Unable to communicate to native daemon");
385 }
San Mehat873f2142010-01-14 10:25:07 -0800386 }
387
388 public void stopTethering() throws IllegalStateException {
389 mContext.enforceCallingOrSelfPermission(
390 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700391 try {
392 mConnector.doCommand("tether stop");
393 } catch (NativeDaemonConnectorException e) {
394 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
395 }
San Mehat873f2142010-01-14 10:25:07 -0800396 }
397
398 public boolean isTetheringStarted() throws IllegalStateException {
399 mContext.enforceCallingOrSelfPermission(
400 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
401
Kenny Roota80ce062010-06-01 13:23:53 -0700402 ArrayList<String> rsp;
403 try {
404 rsp = mConnector.doCommand("tether status");
405 } catch (NativeDaemonConnectorException e) {
406 throw new IllegalStateException(
407 "Unable to communicate to native daemon to get tether status");
408 }
San Mehat873f2142010-01-14 10:25:07 -0800409
410 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700411 String[] tok = line.split(" ");
412 if (tok.length < 3) {
413 throw new IllegalStateException("Malformed response for tether status: " + line);
414 }
San Mehat873f2142010-01-14 10:25:07 -0800415 int code = Integer.parseInt(tok[0]);
416 if (code == NetdResponseCode.TetherStatusResult) {
417 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700418 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800419 } else {
420 throw new IllegalStateException(String.format("Unexpected response code %d", code));
421 }
422 }
423 throw new IllegalStateException("Got an empty response");
424 }
425
426 public void tetherInterface(String iface) throws IllegalStateException {
427 mContext.enforceCallingOrSelfPermission(
428 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700429 try {
430 mConnector.doCommand("tether interface add " + iface);
431 } catch (NativeDaemonConnectorException e) {
432 throw new IllegalStateException(
433 "Unable to communicate to native daemon for adding tether interface");
434 }
San Mehat873f2142010-01-14 10:25:07 -0800435 }
436
437 public void untetherInterface(String iface) {
438 mContext.enforceCallingOrSelfPermission(
439 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700440 try {
441 mConnector.doCommand("tether interface remove " + iface);
442 } catch (NativeDaemonConnectorException e) {
443 throw new IllegalStateException(
444 "Unable to communicate to native daemon for removing tether interface");
445 }
San Mehat873f2142010-01-14 10:25:07 -0800446 }
447
448 public String[] listTetheredInterfaces() throws IllegalStateException {
449 mContext.enforceCallingOrSelfPermission(
450 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700451 try {
452 return mConnector.doListCommand(
453 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
454 } catch (NativeDaemonConnectorException e) {
455 throw new IllegalStateException(
456 "Unable to communicate to native daemon for listing tether interfaces");
457 }
San Mehat873f2142010-01-14 10:25:07 -0800458 }
459
460 public void setDnsForwarders(String[] dns) throws IllegalStateException {
461 mContext.enforceCallingOrSelfPermission(
462 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
463 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800464 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800465 for (String s : dns) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800466 cmd += " " + InetAddress.getByName(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800467 }
Kenny Roota80ce062010-06-01 13:23:53 -0700468 try {
469 mConnector.doCommand(cmd);
470 } catch (NativeDaemonConnectorException e) {
471 throw new IllegalStateException(
472 "Unable to communicate to native daemon for setting tether dns");
473 }
San Mehat873f2142010-01-14 10:25:07 -0800474 } catch (UnknownHostException e) {
475 throw new IllegalStateException("Error resolving dns name", e);
476 }
477 }
478
479 public String[] getDnsForwarders() throws IllegalStateException {
480 mContext.enforceCallingOrSelfPermission(
481 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700482 try {
483 return mConnector.doListCommand(
484 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
485 } catch (NativeDaemonConnectorException e) {
486 throw new IllegalStateException(
487 "Unable to communicate to native daemon for listing tether dns");
488 }
San Mehat873f2142010-01-14 10:25:07 -0800489 }
490
491 public void enableNat(String internalInterface, String externalInterface)
492 throws IllegalStateException {
493 mContext.enforceCallingOrSelfPermission(
494 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700495 try {
496 mConnector.doCommand(
497 String.format("nat enable %s %s", internalInterface, externalInterface));
498 } catch (NativeDaemonConnectorException e) {
499 throw new IllegalStateException(
500 "Unable to communicate to native daemon for enabling NAT interface");
501 }
San Mehat873f2142010-01-14 10:25:07 -0800502 }
503
504 public void disableNat(String internalInterface, String externalInterface)
505 throws IllegalStateException {
506 mContext.enforceCallingOrSelfPermission(
507 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700508 try {
509 mConnector.doCommand(
510 String.format("nat disable %s %s", internalInterface, externalInterface));
511 } catch (NativeDaemonConnectorException e) {
512 throw new IllegalStateException(
513 "Unable to communicate to native daemon for disabling NAT interface");
514 }
San Mehat873f2142010-01-14 10:25:07 -0800515 }
San Mehat72759df2010-01-19 13:50:37 -0800516
517 public String[] listTtys() throws IllegalStateException {
518 mContext.enforceCallingOrSelfPermission(
519 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700520 try {
521 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
522 } catch (NativeDaemonConnectorException e) {
523 throw new IllegalStateException(
524 "Unable to communicate to native daemon for listing TTYs");
525 }
San Mehat72759df2010-01-19 13:50:37 -0800526 }
527
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800528 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
529 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800530 try {
531 mContext.enforceCallingOrSelfPermission(
532 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800533 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
534 InetAddress.getByName(localAddr).getHostAddress(),
535 InetAddress.getByName(remoteAddr).getHostAddress(),
536 InetAddress.getByName(dns1Addr).getHostAddress(),
537 InetAddress.getByName(dns2Addr).getHostAddress()));
San Mehat72759df2010-01-19 13:50:37 -0800538 } catch (UnknownHostException e) {
539 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700540 } catch (NativeDaemonConnectorException e) {
541 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800542 }
543 }
544
545 public void detachPppd(String tty) throws IllegalStateException {
546 mContext.enforceCallingOrSelfPermission(
547 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700548 try {
549 mConnector.doCommand(String.format("pppd detach %s", tty));
550 } catch (NativeDaemonConnectorException e) {
551 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
552 }
San Mehat72759df2010-01-19 13:50:37 -0800553 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800554
555 public void startUsbRNDIS() throws IllegalStateException {
556 mContext.enforceCallingOrSelfPermission(
557 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700558 try {
559 mConnector.doCommand("usb startrndis");
560 } catch (NativeDaemonConnectorException e) {
561 throw new IllegalStateException(
562 "Error communicating to native daemon for starting RNDIS", e);
563 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800564 }
565
566 public void stopUsbRNDIS() throws IllegalStateException {
567 mContext.enforceCallingOrSelfPermission(
568 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700569 try {
570 mConnector.doCommand("usb stoprndis");
571 } catch (NativeDaemonConnectorException e) {
572 throw new IllegalStateException("Error communicating to native daemon", e);
573 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800574 }
575
576 public boolean isUsbRNDISStarted() throws IllegalStateException {
577 mContext.enforceCallingOrSelfPermission(
578 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700579 ArrayList<String> rsp;
580 try {
581 rsp = mConnector.doCommand("usb rndisstatus");
582 } catch (NativeDaemonConnectorException e) {
583 throw new IllegalStateException(
584 "Error communicating to native daemon to check RNDIS status", e);
585 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800586
587 for (String line : rsp) {
588 String []tok = line.split(" ");
589 int code = Integer.parseInt(tok[0]);
590 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500591 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800592 return true;
593 return false;
594 } else {
595 throw new IllegalStateException(String.format("Unexpected response code %d", code));
596 }
597 }
598 throw new IllegalStateException("Got an empty response");
599 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800600
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700601 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800602 throws IllegalStateException {
603 mContext.enforceCallingOrSelfPermission(
604 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
605 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700606 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700607 try {
608 mConnector.doCommand(String.format("softap stop " + wlanIface));
609 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
610 mConnector.doCommand(String.format("softap start " + wlanIface));
611 if (wifiConfig == null) {
612 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
613 } else {
614 /**
615 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
616 * argv1 - wlan interface
617 * argv2 - softap interface
618 * argv3 - SSID
619 * argv4 - Security
620 * argv5 - Key
621 * argv6 - Channel
622 * argv7 - Preamble
623 * argv8 - Max SCB
624 */
625 String str = String.format("softap set " + wlanIface + " " + softapIface +
626 " %s %s %s", convertQuotedString(wifiConfig.SSID),
627 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
628 "wpa2-psk" : "open",
629 convertQuotedString(wifiConfig.preSharedKey));
630 mConnector.doCommand(str);
631 }
632 mConnector.doCommand(String.format("softap startap"));
633 } catch (NativeDaemonConnectorException e) {
634 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800635 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800636 }
637
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700638 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700639 if (s == null) {
640 return s;
641 }
642 /* Replace \ with \\, then " with \" and add quotes at end */
643 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700644 }
645
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800646 public void stopAccessPoint() throws IllegalStateException {
647 mContext.enforceCallingOrSelfPermission(
648 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
649 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700650 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700651 try {
652 mConnector.doCommand("softap stopap");
653 } catch (NativeDaemonConnectorException e) {
654 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
655 e);
656 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800657 }
658
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700659 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
660 throws IllegalStateException {
661 mContext.enforceCallingOrSelfPermission(
662 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
663 mContext.enforceCallingOrSelfPermission(
664 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700665 try {
666 if (wifiConfig == null) {
667 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
668 } else {
669 String str = String.format("softap set " + wlanIface + " " + softapIface
670 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
671 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open",
672 convertQuotedString(wifiConfig.preSharedKey));
673 mConnector.doCommand(str);
674 }
675 } catch (NativeDaemonConnectorException e) {
676 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
677 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700678 }
679 }
San Mehat91cac642010-03-31 14:31:36 -0700680
681 private long getInterfaceCounter(String iface, boolean rx) {
682 mContext.enforceCallingOrSelfPermission(
683 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
684 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700685 String rsp;
686 try {
687 rsp = mConnector.doCommand(
688 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
689 } catch (NativeDaemonConnectorException e1) {
690 Slog.e(TAG, "Error communicating with native daemon", e1);
691 return -1;
692 }
693
694 String[] tok = rsp.split(" ");
695 if (tok.length < 2) {
696 Slog.e(TAG, String.format("Malformed response for reading %s interface",
697 (rx ? "rx" : "tx")));
698 return -1;
699 }
700
San Mehat91cac642010-03-31 14:31:36 -0700701 int code;
702 try {
703 code = Integer.parseInt(tok[0]);
704 } catch (NumberFormatException nfe) {
705 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
706 return -1;
707 }
708 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
709 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
710 Slog.e(TAG, String.format("Unexpected response code %d", code));
711 return -1;
712 }
713 return Long.parseLong(tok[1]);
714 } catch (Exception e) {
715 Slog.e(TAG, String.format(
716 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
717 }
718 return -1;
719 }
720
721 public long getInterfaceRxCounter(String iface) {
722 return getInterfaceCounter(iface, true);
723 }
724
725 public long getInterfaceTxCounter(String iface) {
726 return getInterfaceCounter(iface, false);
727 }
728
San Mehatf0db6e12010-04-07 15:22:10 -0700729 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700730 mContext.enforceCallingOrSelfPermission(
731 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700732 try {
733 mConnector.doCommand(String.format(
734 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
735 } catch (NativeDaemonConnectorException e) {
736 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
737 }
San Mehat91cac642010-03-31 14:31:36 -0700738 }
739
740 private int getInterfaceThrottle(String iface, boolean rx) {
741 mContext.enforceCallingOrSelfPermission(
742 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
743 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700744 String rsp;
745 try {
746 rsp = mConnector.doCommand(
747 String.format("interface getthrottle %s %s", iface,
748 (rx ? "rx" : "tx"))).get(0);
749 } catch (NativeDaemonConnectorException e) {
750 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
751 return -1;
752 }
753
754 String[] tok = rsp.split(" ");
755 if (tok.length < 2) {
756 Slog.e(TAG, "Malformed response to getthrottle command");
757 return -1;
758 }
759
San Mehat91cac642010-03-31 14:31:36 -0700760 int code;
761 try {
762 code = Integer.parseInt(tok[0]);
763 } catch (NumberFormatException nfe) {
764 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
765 return -1;
766 }
767 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
768 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
769 Slog.e(TAG, String.format("Unexpected response code %d", code));
770 return -1;
771 }
772 return Integer.parseInt(tok[1]);
773 } catch (Exception e) {
774 Slog.e(TAG, String.format(
775 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
776 }
777 return -1;
778 }
779
780 public int getInterfaceRxThrottle(String iface) {
781 return getInterfaceThrottle(iface, true);
782 }
783
784 public int getInterfaceTxThrottle(String iface) {
785 return getInterfaceThrottle(iface, false);
786 }
San Mehat873f2142010-01-14 10:25:07 -0800787}