blob: 4a69f2047e94533e47062aa26459be586a5c66ee [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;
50
51/**
52 * @hide
53 */
54class NetworkManagementService extends INetworkManagementService.Stub {
55
56 private static final String TAG = "NetworkManagmentService";
57
Kenny Root305bcbf2010-09-03 07:56:38 -070058 private static final String NETD_TAG = "NetdConnector";
59
San Mehat873f2142010-01-14 10:25:07 -080060 class NetdResponseCode {
61 public static final int InterfaceListResult = 110;
62 public static final int TetherInterfaceListResult = 111;
63 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080064 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080065
66 public static final int TetherStatusResult = 210;
67 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080068 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080069 public static final int SoftapStatusResult = 214;
70 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070071 public static final int InterfaceRxCounterResult = 216;
72 public static final int InterfaceTxCounterResult = 217;
73 public static final int InterfaceRxThrottleResult = 218;
74 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080075
76 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080077 }
78
79 /**
80 * Binder context for this service
81 */
82 private Context mContext;
83
84 /**
85 * connector object for communicating with netd
86 */
87 private NativeDaemonConnector mConnector;
88
San Mehat4d02d002010-01-22 16:07:46 -080089 private ArrayList<INetworkManagementEventObserver> mObservers;
90
San Mehat873f2142010-01-14 10:25:07 -080091 /**
92 * Constructs a new NetworkManagementService instance
93 *
94 * @param context Binder context for this service
95 */
San Mehatd1df8ac2010-01-26 06:17:26 -080096 public NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -080097 mContext = context;
98
San Mehat4d02d002010-01-22 16:07:46 -080099 mObservers = new ArrayList<INetworkManagementEventObserver>();
100
Marco Nelissen62dbb222010-02-18 10:56:30 -0800101 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
102 return;
103 }
104
San Mehat873f2142010-01-14 10:25:07 -0800105 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700106 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
107 Thread thread = new Thread(mConnector, NETD_TAG);
San Mehat873f2142010-01-14 10:25:07 -0800108 thread.start();
109 }
110
San Mehat4d02d002010-01-22 16:07:46 -0800111 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800112 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800113 mObservers.add(obs);
114 }
115
116 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800117 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800118 mObservers.remove(mObservers.indexOf(obs));
119 }
120
121 /**
122 * Notify our observers of an interface link status change
123 */
124 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
125 for (INetworkManagementEventObserver obs : mObservers) {
126 try {
127 obs.interfaceLinkStatusChanged(iface, link);
128 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800129 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800130 }
131 }
132 }
133
134 /**
135 * Notify our observers of an interface addition.
136 */
137 private void notifyInterfaceAdded(String iface) {
138 for (INetworkManagementEventObserver obs : mObservers) {
139 try {
140 obs.interfaceAdded(iface);
141 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800142 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800143 }
144 }
145 }
146
147 /**
148 * Notify our observers of an interface removal.
149 */
150 private void notifyInterfaceRemoved(String iface) {
151 for (INetworkManagementEventObserver obs : mObservers) {
152 try {
153 obs.interfaceRemoved(iface);
154 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800155 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800156 }
157 }
158 }
159
160
San Mehat873f2142010-01-14 10:25:07 -0800161 //
162 // Netd Callback handling
163 //
164
165 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
166 public void onDaemonConnected() {
167 new Thread() {
168 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800169 }
170 }.start();
171 }
172 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800173 if (code == NetdResponseCode.InterfaceChange) {
174 /*
175 * a network interface change occured
176 * Format: "NNN Iface added <name>"
177 * "NNN Iface removed <name>"
178 * "NNN Iface changed <name> <up/down>"
179 */
180 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
181 throw new IllegalStateException(
182 String.format("Invalid event from daemon (%s)", raw));
183 }
184 if (cooked[2].equals("added")) {
185 notifyInterfaceAdded(cooked[3]);
186 return true;
187 } else if (cooked[2].equals("removed")) {
188 notifyInterfaceRemoved(cooked[3]);
189 return true;
190 } else if (cooked[2].equals("changed") && cooked.length == 5) {
191 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
192 return true;
193 }
194 throw new IllegalStateException(
195 String.format("Invalid event from daemon (%s)", raw));
196 }
197 return false;
San Mehat873f2142010-01-14 10:25:07 -0800198 }
199 }
200
San Mehated4fc8a2010-01-22 12:28:36 -0800201 private static int stringToIpAddr(String addrString) throws UnknownHostException {
202 try {
203 String[] parts = addrString.split("\\.");
204 if (parts.length != 4) {
205 throw new UnknownHostException(addrString);
206 }
207
208 int a = Integer.parseInt(parts[0]) ;
209 int b = Integer.parseInt(parts[1]) << 8;
210 int c = Integer.parseInt(parts[2]) << 16;
211 int d = Integer.parseInt(parts[3]) << 24;
212
213 return a | b | c | d;
214 } catch (NumberFormatException ex) {
215 throw new UnknownHostException(addrString);
216 }
217 }
218
219 public static String intToIpString(int i) {
220 return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >> 8 ) & 0xFF) + "." +
221 (i & 0xFF);
222 }
223
San Mehat873f2142010-01-14 10:25:07 -0800224 //
225 // INetworkManagementService members
226 //
227
228 public String[] listInterfaces() throws IllegalStateException {
229 mContext.enforceCallingOrSelfPermission(
230 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
231
Kenny Roota80ce062010-06-01 13:23:53 -0700232 try {
233 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
234 } catch (NativeDaemonConnectorException e) {
235 throw new IllegalStateException(
236 "Cannot communicate with native daemon to list interfaces");
237 }
San Mehated4fc8a2010-01-22 12:28:36 -0800238 }
239
240 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700241 String rsp;
242 try {
243 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
244 } catch (NativeDaemonConnectorException e) {
245 throw new IllegalStateException(
246 "Cannot communicate with native daemon to get interface config");
247 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800248 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800249
250 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
251 StringTokenizer st = new StringTokenizer(rsp);
252
Kenny Roota80ce062010-06-01 13:23:53 -0700253 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800254 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700255 try {
256 int code = Integer.parseInt(st.nextToken(" "));
257 if (code != NetdResponseCode.InterfaceGetCfgResult) {
258 throw new IllegalStateException(
259 String.format("Expected code %d, but got %d",
260 NetdResponseCode.InterfaceGetCfgResult, code));
261 }
262 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800263 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700264 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800265 }
Kenny Roota80ce062010-06-01 13:23:53 -0700266
267 cfg = new InterfaceConfiguration();
268 cfg.hwAddr = st.nextToken(" ");
269 try {
270 cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
271 } catch (UnknownHostException uhe) {
272 Slog.e(TAG, "Failed to parse ipaddr", uhe);
273 cfg.ipAddr = 0;
274 }
275
276 try {
277 cfg.netmask = stringToIpAddr(st.nextToken(" "));
278 } catch (UnknownHostException uhe) {
279 Slog.e(TAG, "Failed to parse netmask", uhe);
280 cfg.netmask = 0;
281 }
282 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
283 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800284 throw new IllegalStateException(
285 String.format("Invalid response from daemon (%s)", rsp));
286 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800287 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800288 return cfg;
289 }
290
291 public void setInterfaceConfig(
292 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalt65ae29b2010-02-18 11:25:54 -0800293 String cmd = String.format("interface setcfg %s %s %s %s", iface,
San Mehated4fc8a2010-01-22 12:28:36 -0800294 intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700295 try {
296 mConnector.doCommand(cmd);
297 } catch (NativeDaemonConnectorException e) {
298 throw new IllegalStateException(
299 "Unable to communicate with native daemon to interface setcfg");
300 }
San Mehat873f2142010-01-14 10:25:07 -0800301 }
302
303 public void shutdown() {
304 if (mContext.checkCallingOrSelfPermission(
305 android.Manifest.permission.SHUTDOWN)
306 != PackageManager.PERMISSION_GRANTED) {
307 throw new SecurityException("Requires SHUTDOWN permission");
308 }
309
Joe Onorato8a9b2202010-02-26 18:56:32 -0800310 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800311 }
312
313 public boolean getIpForwardingEnabled() throws IllegalStateException{
314 mContext.enforceCallingOrSelfPermission(
315 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
316
Kenny Roota80ce062010-06-01 13:23:53 -0700317 ArrayList<String> rsp;
318 try {
319 rsp = mConnector.doCommand("ipfwd status");
320 } catch (NativeDaemonConnectorException e) {
321 throw new IllegalStateException(
322 "Unable to communicate with native daemon to ipfwd status");
323 }
San Mehat873f2142010-01-14 10:25:07 -0800324
325 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700326 String[] tok = line.split(" ");
327 if (tok.length < 3) {
328 Slog.e(TAG, "Malformed response from native daemon: " + line);
329 return false;
330 }
331
San Mehat873f2142010-01-14 10:25:07 -0800332 int code = Integer.parseInt(tok[0]);
333 if (code == NetdResponseCode.IpFwdStatusResult) {
334 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700335 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800336 } else {
337 throw new IllegalStateException(String.format("Unexpected response code %d", code));
338 }
339 }
340 throw new IllegalStateException("Got an empty response");
341 }
342
343 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
344 mContext.enforceCallingOrSelfPermission(
345 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
346 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
347 }
348
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700349 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800350 throws IllegalStateException {
351 mContext.enforceCallingOrSelfPermission(
352 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700353 // cmd is "tether start first_start first_stop second_start second_stop ..."
354 // an odd number of addrs will fail
355 String cmd = "tether start";
356 for (String d : dhcpRange) {
357 cmd += " " + d;
358 }
Kenny Roota80ce062010-06-01 13:23:53 -0700359
360 try {
361 mConnector.doCommand(cmd);
362 } catch (NativeDaemonConnectorException e) {
363 throw new IllegalStateException("Unable to communicate to native daemon");
364 }
San Mehat873f2142010-01-14 10:25:07 -0800365 }
366
367 public void stopTethering() throws IllegalStateException {
368 mContext.enforceCallingOrSelfPermission(
369 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700370 try {
371 mConnector.doCommand("tether stop");
372 } catch (NativeDaemonConnectorException e) {
373 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
374 }
San Mehat873f2142010-01-14 10:25:07 -0800375 }
376
377 public boolean isTetheringStarted() throws IllegalStateException {
378 mContext.enforceCallingOrSelfPermission(
379 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
380
Kenny Roota80ce062010-06-01 13:23:53 -0700381 ArrayList<String> rsp;
382 try {
383 rsp = mConnector.doCommand("tether status");
384 } catch (NativeDaemonConnectorException e) {
385 throw new IllegalStateException(
386 "Unable to communicate to native daemon to get tether status");
387 }
San Mehat873f2142010-01-14 10:25:07 -0800388
389 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700390 String[] tok = line.split(" ");
391 if (tok.length < 3) {
392 throw new IllegalStateException("Malformed response for tether status: " + line);
393 }
San Mehat873f2142010-01-14 10:25:07 -0800394 int code = Integer.parseInt(tok[0]);
395 if (code == NetdResponseCode.TetherStatusResult) {
396 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700397 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800398 } else {
399 throw new IllegalStateException(String.format("Unexpected response code %d", code));
400 }
401 }
402 throw new IllegalStateException("Got an empty response");
403 }
404
405 public void tetherInterface(String iface) throws IllegalStateException {
406 mContext.enforceCallingOrSelfPermission(
407 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700408 try {
409 mConnector.doCommand("tether interface add " + iface);
410 } catch (NativeDaemonConnectorException e) {
411 throw new IllegalStateException(
412 "Unable to communicate to native daemon for adding tether interface");
413 }
San Mehat873f2142010-01-14 10:25:07 -0800414 }
415
416 public void untetherInterface(String iface) {
417 mContext.enforceCallingOrSelfPermission(
418 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700419 try {
420 mConnector.doCommand("tether interface remove " + iface);
421 } catch (NativeDaemonConnectorException e) {
422 throw new IllegalStateException(
423 "Unable to communicate to native daemon for removing tether interface");
424 }
San Mehat873f2142010-01-14 10:25:07 -0800425 }
426
427 public String[] listTetheredInterfaces() throws IllegalStateException {
428 mContext.enforceCallingOrSelfPermission(
429 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700430 try {
431 return mConnector.doListCommand(
432 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
433 } catch (NativeDaemonConnectorException e) {
434 throw new IllegalStateException(
435 "Unable to communicate to native daemon for listing tether interfaces");
436 }
San Mehat873f2142010-01-14 10:25:07 -0800437 }
438
439 public void setDnsForwarders(String[] dns) throws IllegalStateException {
440 mContext.enforceCallingOrSelfPermission(
441 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
442 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800443 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800444 for (String s : dns) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800445 cmd += " " + InetAddress.getByName(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800446 }
Kenny Roota80ce062010-06-01 13:23:53 -0700447 try {
448 mConnector.doCommand(cmd);
449 } catch (NativeDaemonConnectorException e) {
450 throw new IllegalStateException(
451 "Unable to communicate to native daemon for setting tether dns");
452 }
San Mehat873f2142010-01-14 10:25:07 -0800453 } catch (UnknownHostException e) {
454 throw new IllegalStateException("Error resolving dns name", e);
455 }
456 }
457
458 public String[] getDnsForwarders() throws IllegalStateException {
459 mContext.enforceCallingOrSelfPermission(
460 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700461 try {
462 return mConnector.doListCommand(
463 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
464 } catch (NativeDaemonConnectorException e) {
465 throw new IllegalStateException(
466 "Unable to communicate to native daemon for listing tether dns");
467 }
San Mehat873f2142010-01-14 10:25:07 -0800468 }
469
470 public void enableNat(String internalInterface, String externalInterface)
471 throws IllegalStateException {
472 mContext.enforceCallingOrSelfPermission(
473 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700474 try {
475 mConnector.doCommand(
476 String.format("nat enable %s %s", internalInterface, externalInterface));
477 } catch (NativeDaemonConnectorException e) {
478 throw new IllegalStateException(
479 "Unable to communicate to native daemon for enabling NAT interface");
480 }
San Mehat873f2142010-01-14 10:25:07 -0800481 }
482
483 public void disableNat(String internalInterface, String externalInterface)
484 throws IllegalStateException {
485 mContext.enforceCallingOrSelfPermission(
486 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700487 try {
488 mConnector.doCommand(
489 String.format("nat disable %s %s", internalInterface, externalInterface));
490 } catch (NativeDaemonConnectorException e) {
491 throw new IllegalStateException(
492 "Unable to communicate to native daemon for disabling NAT interface");
493 }
San Mehat873f2142010-01-14 10:25:07 -0800494 }
San Mehat72759df2010-01-19 13:50:37 -0800495
496 public String[] listTtys() throws IllegalStateException {
497 mContext.enforceCallingOrSelfPermission(
498 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700499 try {
500 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
501 } catch (NativeDaemonConnectorException e) {
502 throw new IllegalStateException(
503 "Unable to communicate to native daemon for listing TTYs");
504 }
San Mehat72759df2010-01-19 13:50:37 -0800505 }
506
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800507 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
508 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800509 try {
510 mContext.enforceCallingOrSelfPermission(
511 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800512 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
513 InetAddress.getByName(localAddr).getHostAddress(),
514 InetAddress.getByName(remoteAddr).getHostAddress(),
515 InetAddress.getByName(dns1Addr).getHostAddress(),
516 InetAddress.getByName(dns2Addr).getHostAddress()));
San Mehat72759df2010-01-19 13:50:37 -0800517 } catch (UnknownHostException e) {
518 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700519 } catch (NativeDaemonConnectorException e) {
520 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800521 }
522 }
523
524 public void detachPppd(String tty) throws IllegalStateException {
525 mContext.enforceCallingOrSelfPermission(
526 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700527 try {
528 mConnector.doCommand(String.format("pppd detach %s", tty));
529 } catch (NativeDaemonConnectorException e) {
530 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
531 }
San Mehat72759df2010-01-19 13:50:37 -0800532 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800533
534 public void startUsbRNDIS() throws IllegalStateException {
535 mContext.enforceCallingOrSelfPermission(
536 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700537 try {
538 mConnector.doCommand("usb startrndis");
539 } catch (NativeDaemonConnectorException e) {
540 throw new IllegalStateException(
541 "Error communicating to native daemon for starting RNDIS", e);
542 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800543 }
544
545 public void stopUsbRNDIS() 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("usb stoprndis");
550 } catch (NativeDaemonConnectorException e) {
551 throw new IllegalStateException("Error communicating to native daemon", e);
552 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800553 }
554
555 public boolean isUsbRNDISStarted() throws IllegalStateException {
556 mContext.enforceCallingOrSelfPermission(
557 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700558 ArrayList<String> rsp;
559 try {
560 rsp = mConnector.doCommand("usb rndisstatus");
561 } catch (NativeDaemonConnectorException e) {
562 throw new IllegalStateException(
563 "Error communicating to native daemon to check RNDIS status", e);
564 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800565
566 for (String line : rsp) {
567 String []tok = line.split(" ");
568 int code = Integer.parseInt(tok[0]);
569 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500570 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800571 return true;
572 return false;
573 } else {
574 throw new IllegalStateException(String.format("Unexpected response code %d", code));
575 }
576 }
577 throw new IllegalStateException("Got an empty response");
578 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800579
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700580 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800581 throws IllegalStateException {
582 mContext.enforceCallingOrSelfPermission(
583 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
584 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700585 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700586 try {
587 mConnector.doCommand(String.format("softap stop " + wlanIface));
588 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
589 mConnector.doCommand(String.format("softap start " + wlanIface));
590 if (wifiConfig == null) {
591 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
592 } else {
593 /**
594 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
595 * argv1 - wlan interface
596 * argv2 - softap interface
597 * argv3 - SSID
598 * argv4 - Security
599 * argv5 - Key
600 * argv6 - Channel
601 * argv7 - Preamble
602 * argv8 - Max SCB
603 */
604 String str = String.format("softap set " + wlanIface + " " + softapIface +
605 " %s %s %s", convertQuotedString(wifiConfig.SSID),
606 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
607 "wpa2-psk" : "open",
608 convertQuotedString(wifiConfig.preSharedKey));
609 mConnector.doCommand(str);
610 }
611 mConnector.doCommand(String.format("softap startap"));
612 } catch (NativeDaemonConnectorException e) {
613 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800614 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800615 }
616
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700617 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700618 if (s == null) {
619 return s;
620 }
621 /* Replace \ with \\, then " with \" and add quotes at end */
622 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700623 }
624
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800625 public void stopAccessPoint() throws IllegalStateException {
626 mContext.enforceCallingOrSelfPermission(
627 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
628 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700629 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700630 try {
631 mConnector.doCommand("softap stopap");
632 } catch (NativeDaemonConnectorException e) {
633 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
634 e);
635 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800636 }
637
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700638 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
639 throws IllegalStateException {
640 mContext.enforceCallingOrSelfPermission(
641 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
642 mContext.enforceCallingOrSelfPermission(
643 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700644 try {
645 if (wifiConfig == null) {
646 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
647 } else {
648 String str = String.format("softap set " + wlanIface + " " + softapIface
649 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
650 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open",
651 convertQuotedString(wifiConfig.preSharedKey));
652 mConnector.doCommand(str);
653 }
654 } catch (NativeDaemonConnectorException e) {
655 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
656 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700657 }
658 }
San Mehat91cac642010-03-31 14:31:36 -0700659
660 private long getInterfaceCounter(String iface, boolean rx) {
661 mContext.enforceCallingOrSelfPermission(
662 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
663 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700664 String rsp;
665 try {
666 rsp = mConnector.doCommand(
667 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
668 } catch (NativeDaemonConnectorException e1) {
669 Slog.e(TAG, "Error communicating with native daemon", e1);
670 return -1;
671 }
672
673 String[] tok = rsp.split(" ");
674 if (tok.length < 2) {
675 Slog.e(TAG, String.format("Malformed response for reading %s interface",
676 (rx ? "rx" : "tx")));
677 return -1;
678 }
679
San Mehat91cac642010-03-31 14:31:36 -0700680 int code;
681 try {
682 code = Integer.parseInt(tok[0]);
683 } catch (NumberFormatException nfe) {
684 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
685 return -1;
686 }
687 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
688 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
689 Slog.e(TAG, String.format("Unexpected response code %d", code));
690 return -1;
691 }
692 return Long.parseLong(tok[1]);
693 } catch (Exception e) {
694 Slog.e(TAG, String.format(
695 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
696 }
697 return -1;
698 }
699
700 public long getInterfaceRxCounter(String iface) {
701 return getInterfaceCounter(iface, true);
702 }
703
704 public long getInterfaceTxCounter(String iface) {
705 return getInterfaceCounter(iface, false);
706 }
707
San Mehatf0db6e12010-04-07 15:22:10 -0700708 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700709 mContext.enforceCallingOrSelfPermission(
710 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700711 try {
712 mConnector.doCommand(String.format(
713 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
714 } catch (NativeDaemonConnectorException e) {
715 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
716 }
San Mehat91cac642010-03-31 14:31:36 -0700717 }
718
719 private int getInterfaceThrottle(String iface, boolean rx) {
720 mContext.enforceCallingOrSelfPermission(
721 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
722 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700723 String rsp;
724 try {
725 rsp = mConnector.doCommand(
726 String.format("interface getthrottle %s %s", iface,
727 (rx ? "rx" : "tx"))).get(0);
728 } catch (NativeDaemonConnectorException e) {
729 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
730 return -1;
731 }
732
733 String[] tok = rsp.split(" ");
734 if (tok.length < 2) {
735 Slog.e(TAG, "Malformed response to getthrottle command");
736 return -1;
737 }
738
San Mehat91cac642010-03-31 14:31:36 -0700739 int code;
740 try {
741 code = Integer.parseInt(tok[0]);
742 } catch (NumberFormatException nfe) {
743 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
744 return -1;
745 }
746 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
747 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
748 Slog.e(TAG, String.format("Unexpected response code %d", code));
749 return -1;
750 }
751 return Integer.parseInt(tok[1]);
752 } catch (Exception e) {
753 Slog.e(TAG, String.format(
754 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
755 }
756 return -1;
757 }
758
759 public int getInterfaceRxThrottle(String iface) {
760 return getInterfaceThrottle(iface, true);
761 }
762
763 public int getInterfaceTxThrottle(String iface) {
764 return getInterfaceThrottle(iface, false);
765 }
San Mehat873f2142010-01-14 10:25:07 -0800766}