blob: 91a030245e984f0ca8921cf99edebb5bad411fa3 [file] [log] [blame]
San Mehat873f2142010-01-14 10:25:07 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.PendingIntent;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.res.Resources;
25import android.content.pm.PackageManager;
26import android.net.Uri;
San Mehated4fc8a2010-01-22 12:28:36 -080027import android.net.InterfaceConfiguration;
San Mehat4d02d002010-01-22 16:07:46 -080028import android.net.INetworkManagementEventObserver;
Robert Greenwalted126402011-01-28 15:34:55 -080029import android.net.LinkAddress;
30import android.net.NetworkUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080031import android.net.wifi.WifiConfiguration;
32import android.net.wifi.WifiConfiguration.KeyMgmt;
San Mehat873f2142010-01-14 10:25:07 -080033import android.os.INetworkManagementService;
34import android.os.Handler;
Marco Nelissen62dbb222010-02-18 10:56:30 -080035import android.os.SystemProperties;
San Mehat873f2142010-01-14 10:25:07 -080036import android.text.TextUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080037import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080038import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080039import java.util.ArrayList;
Kenny Roota80ce062010-06-01 13:23:53 -070040import java.util.NoSuchElementException;
San Mehated4fc8a2010-01-22 12:28:36 -080041import java.util.StringTokenizer;
San Mehat873f2142010-01-14 10:25:07 -080042import android.provider.Settings;
43import android.content.ContentResolver;
44import android.database.ContentObserver;
45
46import java.io.File;
47import java.io.FileReader;
48import java.lang.IllegalStateException;
49
50import java.net.InetAddress;
51import java.net.UnknownHostException;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070052import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080053
54/**
55 * @hide
56 */
57class NetworkManagementService extends INetworkManagementService.Stub {
58
59 private static final String TAG = "NetworkManagmentService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070060 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070061 private static final String NETD_TAG = "NetdConnector";
62
San Mehat873f2142010-01-14 10:25:07 -080063 class NetdResponseCode {
64 public static final int InterfaceListResult = 110;
65 public static final int TetherInterfaceListResult = 111;
66 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080067 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080068
69 public static final int TetherStatusResult = 210;
70 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080071 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080072 public static final int SoftapStatusResult = 214;
73 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070074 public static final int InterfaceRxCounterResult = 216;
75 public static final int InterfaceTxCounterResult = 217;
76 public static final int InterfaceRxThrottleResult = 218;
77 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080078
79 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080080 }
81
82 /**
83 * Binder context for this service
84 */
85 private Context mContext;
86
87 /**
88 * connector object for communicating with netd
89 */
90 private NativeDaemonConnector mConnector;
91
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070092 private Thread mThread;
93 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
94
San Mehat4d02d002010-01-22 16:07:46 -080095 private ArrayList<INetworkManagementEventObserver> mObservers;
96
San Mehat873f2142010-01-14 10:25:07 -080097 /**
98 * Constructs a new NetworkManagementService instance
99 *
100 * @param context Binder context for this service
101 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700102 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800103 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800104 mObservers = new ArrayList<INetworkManagementEventObserver>();
105
Marco Nelissen62dbb222010-02-18 10:56:30 -0800106 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
107 return;
108 }
109
San Mehat873f2142010-01-14 10:25:07 -0800110 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700111 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700112 mThread = new Thread(mConnector, NETD_TAG);
113 }
114
115 public static NetworkManagementService create(Context context) throws InterruptedException {
116 NetworkManagementService service = new NetworkManagementService(context);
117 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
118 service.mThread.start();
119 if (DBG) Slog.d(TAG, "Awaiting socket connection");
120 service.mConnectedSignal.await();
121 if (DBG) Slog.d(TAG, "Connected");
122 return service;
San Mehat873f2142010-01-14 10:25:07 -0800123 }
124
San Mehat4d02d002010-01-22 16:07:46 -0800125 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800126 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800127 mObservers.add(obs);
128 }
129
130 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800131 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800132 mObservers.remove(mObservers.indexOf(obs));
133 }
134
135 /**
Wink Saville1a7e6712011-01-09 12:16:38 -0800136 * Notify our observers of an interface link status change
San Mehat4d02d002010-01-22 16:07:46 -0800137 */
Wink Saville1a7e6712011-01-09 12:16:38 -0800138 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
San Mehat4d02d002010-01-22 16:07:46 -0800139 for (INetworkManagementEventObserver obs : mObservers) {
140 try {
Wink Saville1a7e6712011-01-09 12:16:38 -0800141 obs.interfaceLinkStatusChanged(iface, link);
San Mehat4d02d002010-01-22 16:07:46 -0800142 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800143 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800144 }
145 }
146 }
147
148 /**
149 * Notify our observers of an interface addition.
150 */
151 private void notifyInterfaceAdded(String iface) {
152 for (INetworkManagementEventObserver obs : mObservers) {
153 try {
154 obs.interfaceAdded(iface);
155 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800156 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800157 }
158 }
159 }
160
161 /**
162 * Notify our observers of an interface removal.
163 */
164 private void notifyInterfaceRemoved(String iface) {
165 for (INetworkManagementEventObserver obs : mObservers) {
166 try {
167 obs.interfaceRemoved(iface);
168 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800169 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800170 }
171 }
172 }
173
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700174 /**
175 * Let us know the daemon is connected
176 */
177 protected void onConnected() {
178 if (DBG) Slog.d(TAG, "onConnected");
179 mConnectedSignal.countDown();
180 }
181
San Mehat4d02d002010-01-22 16:07:46 -0800182
San Mehat873f2142010-01-14 10:25:07 -0800183 //
184 // Netd Callback handling
185 //
186
187 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
188 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700189 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800190 new Thread() {
191 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800192 }
193 }.start();
194 }
195 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800196 if (code == NetdResponseCode.InterfaceChange) {
197 /*
198 * a network interface change occured
199 * Format: "NNN Iface added <name>"
200 * "NNN Iface removed <name>"
201 * "NNN Iface changed <name> <up/down>"
202 */
203 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
204 throw new IllegalStateException(
205 String.format("Invalid event from daemon (%s)", raw));
206 }
207 if (cooked[2].equals("added")) {
208 notifyInterfaceAdded(cooked[3]);
209 return true;
210 } else if (cooked[2].equals("removed")) {
211 notifyInterfaceRemoved(cooked[3]);
212 return true;
213 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Wink Saville1a7e6712011-01-09 12:16:38 -0800214 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800215 return true;
216 }
217 throw new IllegalStateException(
218 String.format("Invalid event from daemon (%s)", raw));
219 }
220 return false;
San Mehat873f2142010-01-14 10:25:07 -0800221 }
222 }
223
San Mehated4fc8a2010-01-22 12:28:36 -0800224
San Mehat873f2142010-01-14 10:25:07 -0800225 //
226 // INetworkManagementService members
227 //
228
229 public String[] listInterfaces() throws IllegalStateException {
230 mContext.enforceCallingOrSelfPermission(
231 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
232
Kenny Roota80ce062010-06-01 13:23:53 -0700233 try {
234 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
235 } catch (NativeDaemonConnectorException e) {
236 throw new IllegalStateException(
237 "Cannot communicate with native daemon to list interfaces");
238 }
San Mehated4fc8a2010-01-22 12:28:36 -0800239 }
240
241 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700242 String rsp;
243 try {
244 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
245 } catch (NativeDaemonConnectorException e) {
246 throw new IllegalStateException(
247 "Cannot communicate with native daemon to get interface config");
248 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800249 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800250
251 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
252 StringTokenizer st = new StringTokenizer(rsp);
253
Kenny Roota80ce062010-06-01 13:23:53 -0700254 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800255 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700256 try {
257 int code = Integer.parseInt(st.nextToken(" "));
258 if (code != NetdResponseCode.InterfaceGetCfgResult) {
259 throw new IllegalStateException(
260 String.format("Expected code %d, but got %d",
261 NetdResponseCode.InterfaceGetCfgResult, code));
262 }
263 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800264 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700265 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800266 }
Kenny Roota80ce062010-06-01 13:23:53 -0700267
268 cfg = new InterfaceConfiguration();
269 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800270 InetAddress addr = null;
271 InetAddress mask = null;
Kenny Roota80ce062010-06-01 13:23:53 -0700272 try {
Robert Greenwalted126402011-01-28 15:34:55 -0800273 addr = InetAddress.getByName(st.nextToken(" "));
Kenny Roota80ce062010-06-01 13:23:53 -0700274 } catch (UnknownHostException uhe) {
275 Slog.e(TAG, "Failed to parse ipaddr", uhe);
Kenny Roota80ce062010-06-01 13:23:53 -0700276 }
277
278 try {
Robert Greenwalted126402011-01-28 15:34:55 -0800279 mask = InetAddress.getByName(st.nextToken(" "));
Kenny Roota80ce062010-06-01 13:23:53 -0700280 } catch (UnknownHostException uhe) {
281 Slog.e(TAG, "Failed to parse netmask", uhe);
Kenny Roota80ce062010-06-01 13:23:53 -0700282 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800283
Robert Greenwalted126402011-01-28 15:34:55 -0800284 cfg.addr = new LinkAddress(addr, mask);
Kenny Roota80ce062010-06-01 13:23:53 -0700285 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
286 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800287 throw new IllegalStateException(
288 String.format("Invalid response from daemon (%s)", rsp));
289 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800290 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800291 return cfg;
292 }
293
294 public void setInterfaceConfig(
295 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800296 LinkAddress linkAddr = cfg.addr;
297 if (linkAddr == null) throw new IllegalStateException("Null LinkAddress given");
298 InetAddress addr = linkAddr.getAddress();
299 // TODO - fix this to pass prefixlength and be v6 capapble
300 InetAddress mask = null;
301 try {
302 mask = NetworkUtils.intToInetAddress(NetworkUtils.prefixLengthToNetmaskInt(
303 linkAddr.getNetworkPrefixLength()));
304 } catch (IllegalArgumentException e) {
305 throw new IllegalStateException(e);
306 }
307 if (addr == null || mask == null) throw new IllegalStateException("Null Address given");
Robert Greenwalt65ae29b2010-02-18 11:25:54 -0800308 String cmd = String.format("interface setcfg %s %s %s %s", iface,
Robert Greenwalted126402011-01-28 15:34:55 -0800309 addr.getHostAddress(), mask.getHostAddress(), cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700310 try {
311 mConnector.doCommand(cmd);
312 } catch (NativeDaemonConnectorException e) {
313 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800314 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700315 }
San Mehat873f2142010-01-14 10:25:07 -0800316 }
317
318 public void shutdown() {
319 if (mContext.checkCallingOrSelfPermission(
320 android.Manifest.permission.SHUTDOWN)
321 != PackageManager.PERMISSION_GRANTED) {
322 throw new SecurityException("Requires SHUTDOWN permission");
323 }
324
Joe Onorato8a9b2202010-02-26 18:56:32 -0800325 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800326 }
327
328 public boolean getIpForwardingEnabled() throws IllegalStateException{
329 mContext.enforceCallingOrSelfPermission(
330 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
331
Kenny Roota80ce062010-06-01 13:23:53 -0700332 ArrayList<String> rsp;
333 try {
334 rsp = mConnector.doCommand("ipfwd status");
335 } catch (NativeDaemonConnectorException e) {
336 throw new IllegalStateException(
337 "Unable to communicate with native daemon to ipfwd status");
338 }
San Mehat873f2142010-01-14 10:25:07 -0800339
340 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700341 String[] tok = line.split(" ");
342 if (tok.length < 3) {
343 Slog.e(TAG, "Malformed response from native daemon: " + line);
344 return false;
345 }
346
San Mehat873f2142010-01-14 10:25:07 -0800347 int code = Integer.parseInt(tok[0]);
348 if (code == NetdResponseCode.IpFwdStatusResult) {
349 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700350 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800351 } else {
352 throw new IllegalStateException(String.format("Unexpected response code %d", code));
353 }
354 }
355 throw new IllegalStateException("Got an empty response");
356 }
357
358 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
359 mContext.enforceCallingOrSelfPermission(
360 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
361 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
362 }
363
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700364 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800365 throws IllegalStateException {
366 mContext.enforceCallingOrSelfPermission(
367 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700368 // cmd is "tether start first_start first_stop second_start second_stop ..."
369 // an odd number of addrs will fail
370 String cmd = "tether start";
371 for (String d : dhcpRange) {
372 cmd += " " + d;
373 }
Kenny Roota80ce062010-06-01 13:23:53 -0700374
375 try {
376 mConnector.doCommand(cmd);
377 } catch (NativeDaemonConnectorException e) {
378 throw new IllegalStateException("Unable to communicate to native daemon");
379 }
San Mehat873f2142010-01-14 10:25:07 -0800380 }
381
382 public void stopTethering() throws IllegalStateException {
383 mContext.enforceCallingOrSelfPermission(
384 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700385 try {
386 mConnector.doCommand("tether stop");
387 } catch (NativeDaemonConnectorException e) {
388 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
389 }
San Mehat873f2142010-01-14 10:25:07 -0800390 }
391
392 public boolean isTetheringStarted() throws IllegalStateException {
393 mContext.enforceCallingOrSelfPermission(
394 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
395
Kenny Roota80ce062010-06-01 13:23:53 -0700396 ArrayList<String> rsp;
397 try {
398 rsp = mConnector.doCommand("tether status");
399 } catch (NativeDaemonConnectorException e) {
400 throw new IllegalStateException(
401 "Unable to communicate to native daemon to get tether status");
402 }
San Mehat873f2142010-01-14 10:25:07 -0800403
404 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700405 String[] tok = line.split(" ");
406 if (tok.length < 3) {
407 throw new IllegalStateException("Malformed response for tether status: " + line);
408 }
San Mehat873f2142010-01-14 10:25:07 -0800409 int code = Integer.parseInt(tok[0]);
410 if (code == NetdResponseCode.TetherStatusResult) {
411 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700412 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800413 } else {
414 throw new IllegalStateException(String.format("Unexpected response code %d", code));
415 }
416 }
417 throw new IllegalStateException("Got an empty response");
418 }
419
420 public void tetherInterface(String iface) throws IllegalStateException {
421 mContext.enforceCallingOrSelfPermission(
422 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700423 try {
424 mConnector.doCommand("tether interface add " + iface);
425 } catch (NativeDaemonConnectorException e) {
426 throw new IllegalStateException(
427 "Unable to communicate to native daemon for adding tether interface");
428 }
San Mehat873f2142010-01-14 10:25:07 -0800429 }
430
431 public void untetherInterface(String iface) {
432 mContext.enforceCallingOrSelfPermission(
433 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700434 try {
435 mConnector.doCommand("tether interface remove " + iface);
436 } catch (NativeDaemonConnectorException e) {
437 throw new IllegalStateException(
438 "Unable to communicate to native daemon for removing tether interface");
439 }
San Mehat873f2142010-01-14 10:25:07 -0800440 }
441
442 public String[] listTetheredInterfaces() throws IllegalStateException {
443 mContext.enforceCallingOrSelfPermission(
444 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700445 try {
446 return mConnector.doListCommand(
447 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
448 } catch (NativeDaemonConnectorException e) {
449 throw new IllegalStateException(
450 "Unable to communicate to native daemon for listing tether interfaces");
451 }
San Mehat873f2142010-01-14 10:25:07 -0800452 }
453
454 public void setDnsForwarders(String[] dns) throws IllegalStateException {
455 mContext.enforceCallingOrSelfPermission(
456 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
457 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800458 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800459 for (String s : dns) {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800460 cmd += " " + InetAddress.getByName(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800461 }
Kenny Roota80ce062010-06-01 13:23:53 -0700462 try {
463 mConnector.doCommand(cmd);
464 } catch (NativeDaemonConnectorException e) {
465 throw new IllegalStateException(
466 "Unable to communicate to native daemon for setting tether dns");
467 }
San Mehat873f2142010-01-14 10:25:07 -0800468 } catch (UnknownHostException e) {
469 throw new IllegalStateException("Error resolving dns name", e);
470 }
471 }
472
473 public String[] getDnsForwarders() throws IllegalStateException {
474 mContext.enforceCallingOrSelfPermission(
475 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700476 try {
477 return mConnector.doListCommand(
478 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
479 } catch (NativeDaemonConnectorException e) {
480 throw new IllegalStateException(
481 "Unable to communicate to native daemon for listing tether dns");
482 }
San Mehat873f2142010-01-14 10:25:07 -0800483 }
484
485 public void enableNat(String internalInterface, String externalInterface)
486 throws IllegalStateException {
487 mContext.enforceCallingOrSelfPermission(
488 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700489 try {
490 mConnector.doCommand(
491 String.format("nat enable %s %s", internalInterface, externalInterface));
492 } catch (NativeDaemonConnectorException e) {
493 throw new IllegalStateException(
494 "Unable to communicate to native daemon for enabling NAT interface");
495 }
San Mehat873f2142010-01-14 10:25:07 -0800496 }
497
498 public void disableNat(String internalInterface, String externalInterface)
499 throws IllegalStateException {
500 mContext.enforceCallingOrSelfPermission(
501 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700502 try {
503 mConnector.doCommand(
504 String.format("nat disable %s %s", internalInterface, externalInterface));
505 } catch (NativeDaemonConnectorException e) {
506 throw new IllegalStateException(
507 "Unable to communicate to native daemon for disabling NAT interface");
508 }
San Mehat873f2142010-01-14 10:25:07 -0800509 }
San Mehat72759df2010-01-19 13:50:37 -0800510
511 public String[] listTtys() throws IllegalStateException {
512 mContext.enforceCallingOrSelfPermission(
513 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700514 try {
515 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
516 } catch (NativeDaemonConnectorException e) {
517 throw new IllegalStateException(
518 "Unable to communicate to native daemon for listing TTYs");
519 }
San Mehat72759df2010-01-19 13:50:37 -0800520 }
521
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800522 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
523 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800524 try {
525 mContext.enforceCallingOrSelfPermission(
526 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800527 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
528 InetAddress.getByName(localAddr).getHostAddress(),
529 InetAddress.getByName(remoteAddr).getHostAddress(),
530 InetAddress.getByName(dns1Addr).getHostAddress(),
531 InetAddress.getByName(dns2Addr).getHostAddress()));
San Mehat72759df2010-01-19 13:50:37 -0800532 } catch (UnknownHostException e) {
533 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700534 } catch (NativeDaemonConnectorException e) {
535 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800536 }
537 }
538
539 public void detachPppd(String tty) throws IllegalStateException {
540 mContext.enforceCallingOrSelfPermission(
541 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700542 try {
543 mConnector.doCommand(String.format("pppd detach %s", tty));
544 } catch (NativeDaemonConnectorException e) {
545 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
546 }
San Mehat72759df2010-01-19 13:50:37 -0800547 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800548
549 public void startUsbRNDIS() throws IllegalStateException {
550 mContext.enforceCallingOrSelfPermission(
551 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700552 try {
553 mConnector.doCommand("usb startrndis");
554 } catch (NativeDaemonConnectorException e) {
555 throw new IllegalStateException(
556 "Error communicating to native daemon for starting RNDIS", e);
557 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800558 }
559
560 public void stopUsbRNDIS() throws IllegalStateException {
561 mContext.enforceCallingOrSelfPermission(
562 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700563 try {
564 mConnector.doCommand("usb stoprndis");
565 } catch (NativeDaemonConnectorException e) {
566 throw new IllegalStateException("Error communicating to native daemon", e);
567 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800568 }
569
570 public boolean isUsbRNDISStarted() throws IllegalStateException {
571 mContext.enforceCallingOrSelfPermission(
572 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700573 ArrayList<String> rsp;
574 try {
575 rsp = mConnector.doCommand("usb rndisstatus");
576 } catch (NativeDaemonConnectorException e) {
577 throw new IllegalStateException(
578 "Error communicating to native daemon to check RNDIS status", e);
579 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800580
581 for (String line : rsp) {
582 String []tok = line.split(" ");
583 int code = Integer.parseInt(tok[0]);
584 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500585 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800586 return true;
587 return false;
588 } else {
589 throw new IllegalStateException(String.format("Unexpected response code %d", code));
590 }
591 }
592 throw new IllegalStateException("Got an empty response");
593 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800594
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700595 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800596 throws IllegalStateException {
597 mContext.enforceCallingOrSelfPermission(
598 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
599 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700600 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700601 try {
602 mConnector.doCommand(String.format("softap stop " + wlanIface));
603 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
604 mConnector.doCommand(String.format("softap start " + wlanIface));
605 if (wifiConfig == null) {
606 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
607 } else {
608 /**
609 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
610 * argv1 - wlan interface
611 * argv2 - softap interface
612 * argv3 - SSID
613 * argv4 - Security
614 * argv5 - Key
615 * argv6 - Channel
616 * argv7 - Preamble
617 * argv8 - Max SCB
618 */
619 String str = String.format("softap set " + wlanIface + " " + softapIface +
620 " %s %s %s", convertQuotedString(wifiConfig.SSID),
621 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
622 "wpa2-psk" : "open",
623 convertQuotedString(wifiConfig.preSharedKey));
624 mConnector.doCommand(str);
625 }
626 mConnector.doCommand(String.format("softap startap"));
627 } catch (NativeDaemonConnectorException e) {
628 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800629 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800630 }
631
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700632 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700633 if (s == null) {
634 return s;
635 }
636 /* Replace \ with \\, then " with \" and add quotes at end */
637 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700638 }
639
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800640 public void stopAccessPoint() throws IllegalStateException {
641 mContext.enforceCallingOrSelfPermission(
642 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
643 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700644 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700645 try {
646 mConnector.doCommand("softap stopap");
647 } catch (NativeDaemonConnectorException e) {
648 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
649 e);
650 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800651 }
652
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700653 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
654 throws IllegalStateException {
655 mContext.enforceCallingOrSelfPermission(
656 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
657 mContext.enforceCallingOrSelfPermission(
658 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700659 try {
660 if (wifiConfig == null) {
661 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
662 } else {
663 String str = String.format("softap set " + wlanIface + " " + softapIface
664 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
665 wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open",
666 convertQuotedString(wifiConfig.preSharedKey));
667 mConnector.doCommand(str);
668 }
669 } catch (NativeDaemonConnectorException e) {
670 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
671 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700672 }
673 }
San Mehat91cac642010-03-31 14:31:36 -0700674
675 private long getInterfaceCounter(String iface, boolean rx) {
676 mContext.enforceCallingOrSelfPermission(
677 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
678 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700679 String rsp;
680 try {
681 rsp = mConnector.doCommand(
682 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
683 } catch (NativeDaemonConnectorException e1) {
684 Slog.e(TAG, "Error communicating with native daemon", e1);
685 return -1;
686 }
687
688 String[] tok = rsp.split(" ");
689 if (tok.length < 2) {
690 Slog.e(TAG, String.format("Malformed response for reading %s interface",
691 (rx ? "rx" : "tx")));
692 return -1;
693 }
694
San Mehat91cac642010-03-31 14:31:36 -0700695 int code;
696 try {
697 code = Integer.parseInt(tok[0]);
698 } catch (NumberFormatException nfe) {
699 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
700 return -1;
701 }
702 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
703 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
704 Slog.e(TAG, String.format("Unexpected response code %d", code));
705 return -1;
706 }
707 return Long.parseLong(tok[1]);
708 } catch (Exception e) {
709 Slog.e(TAG, String.format(
710 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
711 }
712 return -1;
713 }
714
715 public long getInterfaceRxCounter(String iface) {
716 return getInterfaceCounter(iface, true);
717 }
718
719 public long getInterfaceTxCounter(String iface) {
720 return getInterfaceCounter(iface, false);
721 }
722
San Mehatf0db6e12010-04-07 15:22:10 -0700723 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700724 mContext.enforceCallingOrSelfPermission(
725 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700726 try {
727 mConnector.doCommand(String.format(
728 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
729 } catch (NativeDaemonConnectorException e) {
730 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
731 }
San Mehat91cac642010-03-31 14:31:36 -0700732 }
733
734 private int getInterfaceThrottle(String iface, boolean rx) {
735 mContext.enforceCallingOrSelfPermission(
736 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
737 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700738 String rsp;
739 try {
740 rsp = mConnector.doCommand(
741 String.format("interface getthrottle %s %s", iface,
742 (rx ? "rx" : "tx"))).get(0);
743 } catch (NativeDaemonConnectorException e) {
744 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
745 return -1;
746 }
747
748 String[] tok = rsp.split(" ");
749 if (tok.length < 2) {
750 Slog.e(TAG, "Malformed response to getthrottle command");
751 return -1;
752 }
753
San Mehat91cac642010-03-31 14:31:36 -0700754 int code;
755 try {
756 code = Integer.parseInt(tok[0]);
757 } catch (NumberFormatException nfe) {
758 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
759 return -1;
760 }
761 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
762 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
763 Slog.e(TAG, String.format("Unexpected response code %d", code));
764 return -1;
765 }
766 return Integer.parseInt(tok[1]);
767 } catch (Exception e) {
768 Slog.e(TAG, String.format(
769 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
770 }
771 return -1;
772 }
773
774 public int getInterfaceRxThrottle(String iface) {
775 return getInterfaceThrottle(iface, true);
776 }
777
778 public int getInterfaceTxThrottle(String iface) {
779 return getInterfaceThrottle(iface, false);
780 }
San Mehat873f2142010-01-14 10:25:07 -0800781}