blob: 4c26dbb174be493ad7764f386b3d3018ac43a44a [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
Jeff Sharkeyb0aec072011-10-14 18:32:24 -070019import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20import static android.Manifest.permission.CHANGE_NETWORK_STATE;
Jeff Sharkey47eb1022011-08-25 17:48:52 -070021import static android.Manifest.permission.DUMP;
Jeff Sharkey350083e2011-06-29 10:45:16 -070022import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070023import static android.net.NetworkStats.SET_DEFAULT;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070024import static android.net.NetworkStats.TAG_NONE;
25import static android.net.NetworkStats.UID_ALL;
Jeff Sharkeyae2c1812011-10-04 13:11:40 -070026import static android.net.TrafficStats.UID_TETHERING;
Jeff Sharkey350083e2011-06-29 10:45:16 -070027import static android.provider.Settings.Secure.NETSTATS_ENABLED;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070028import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070029
San Mehat873f2142010-01-14 10:25:07 -080030import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080031import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080032import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070033import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080034import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070035import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080036import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070037import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080038import android.net.wifi.WifiConfiguration;
39import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070040import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080041import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070042import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080043import android.os.SystemProperties;
Jeff Sharkey350083e2011-06-29 10:45:16 -070044import android.provider.Settings;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080045import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080046import android.util.Slog;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070047import android.util.SparseBooleanArray;
San Mehat873f2142010-01-14 10:25:07 -080048
Jeff Sharkey1059c3c2011-10-04 16:54:49 -070049import com.android.internal.net.NetworkStatsFactory;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070050import com.google.android.collect.Sets;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070051
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070052import java.io.BufferedReader;
53import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080054import java.io.File;
Jeff Sharkey47eb1022011-08-25 17:48:52 -070055import java.io.FileDescriptor;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070056import java.io.FileInputStream;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070057import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070058import java.io.InputStreamReader;
Jeff Sharkey47eb1022011-08-25 17:48:52 -070059import java.io.PrintWriter;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070060import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070061import java.net.InetAddress;
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -070062import java.net.InterfaceAddress;
63import java.net.NetworkInterface;
64import java.net.SocketException;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070065import java.util.ArrayList;
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -070066import java.util.Collection;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070067import java.util.HashSet;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070068import java.util.NoSuchElementException;
69import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070070import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080071
72/**
73 * @hide
74 */
Jeff Sharkey8e9992a2011-08-23 18:37:23 -070075public class NetworkManagementService extends INetworkManagementService.Stub
76 implements Watchdog.Monitor {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070077 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070078 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070079 private static final String NETD_TAG = "NetdConnector";
80
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070081 private static final int ADD = 1;
82 private static final int REMOVE = 2;
83
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -070084 private static final String DEFAULT = "default";
85 private static final String SECONDARY = "secondary";
86
Jeff Sharkey8e9992a2011-08-23 18:37:23 -070087 /**
88 * Name representing {@link #setGlobalAlert(long)} limit when delivered to
89 * {@link INetworkManagementEventObserver#limitReached(String, String)}.
90 */
91 public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
92
San Mehat873f2142010-01-14 10:25:07 -080093 class NetdResponseCode {
JP Abgrall12b933d2011-07-14 18:09:22 -070094 /* Keep in sync with system/netd/ResponseCode.h */
San Mehat873f2142010-01-14 10:25:07 -080095 public static final int InterfaceListResult = 110;
96 public static final int TetherInterfaceListResult = 111;
97 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080098 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080099
100 public static final int TetherStatusResult = 210;
101 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -0800102 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -0800103 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -0700104 public static final int InterfaceRxCounterResult = 216;
105 public static final int InterfaceTxCounterResult = 217;
106 public static final int InterfaceRxThrottleResult = 218;
107 public static final int InterfaceTxThrottleResult = 219;
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700108 public static final int QuotaCounterResult = 220;
109 public static final int TetheringStatsResult = 221;
Robert Greenwalte3253922010-02-18 09:23:25 -0800110
111 public static final int InterfaceChange = 600;
JP Abgrall12b933d2011-07-14 18:09:22 -0700112 public static final int BandwidthControl = 601;
San Mehat873f2142010-01-14 10:25:07 -0800113 }
114
115 /**
116 * Binder context for this service
117 */
118 private Context mContext;
119
120 /**
121 * connector object for communicating with netd
122 */
123 private NativeDaemonConnector mConnector;
124
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700125 private Thread mThread;
126 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
127
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700128 // TODO: replace with RemoteCallbackList
San Mehat4d02d002010-01-22 16:07:46 -0800129 private ArrayList<INetworkManagementEventObserver> mObservers;
130
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700131 private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
132
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700133 private Object mQuotaLock = new Object();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700134 /** Set of interfaces with active quotas. */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700135 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
136 /** Set of interfaces with active alerts. */
137 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700138 /** Set of UIDs with active reject rules. */
139 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
140
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700141 private volatile boolean mBandwidthControlEnabled;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700142
San Mehat873f2142010-01-14 10:25:07 -0800143 /**
144 * Constructs a new NetworkManagementService instance
145 *
146 * @param context Binder context for this service
147 */
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700148 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800149 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800150 mObservers = new ArrayList<INetworkManagementEventObserver>();
151
Marco Nelissen62dbb222010-02-18 10:56:30 -0800152 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
153 return;
154 }
155
San Mehat873f2142010-01-14 10:25:07 -0800156 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700157 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700158 mThread = new Thread(mConnector, NETD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700159
160 // Add ourself to the Watchdog monitors.
161 Watchdog.getInstance().addMonitor(this);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700162 }
163
164 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700165 NetworkManagementService service = new NetworkManagementService(context);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700166 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
167 service.mThread.start();
168 if (DBG) Slog.d(TAG, "Awaiting socket connection");
169 service.mConnectedSignal.await();
170 if (DBG) Slog.d(TAG, "Connected");
171 return service;
San Mehat873f2142010-01-14 10:25:07 -0800172 }
173
Jeff Sharkey350083e2011-06-29 10:45:16 -0700174 public void systemReady() {
Jeff Sharkey350083e2011-06-29 10:45:16 -0700175 // only enable bandwidth control when support exists, and requested by
176 // system setting.
Jeff Sharkey350083e2011-06-29 10:45:16 -0700177 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
178 final boolean shouldEnable =
Jeff Sharkey05355c32011-08-09 14:44:19 -0700179 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700180
Jeff Sharkey350083e2011-06-29 10:45:16 -0700181 if (hasKernelSupport && shouldEnable) {
182 Slog.d(TAG, "enabling bandwidth control");
183 try {
184 mConnector.doCommand("bandwidth enable");
185 mBandwidthControlEnabled = true;
186 } catch (NativeDaemonConnectorException e) {
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700187 Log.wtf(TAG, "problem enabling bandwidth controls", e);
Jeff Sharkey350083e2011-06-29 10:45:16 -0700188 }
189 } else {
190 Slog.d(TAG, "not enabling bandwidth control");
191 }
Jeff Sharkey62a2c8f2011-07-13 15:24:02 -0700192
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700193 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
Jeff Sharkey350083e2011-06-29 10:45:16 -0700194 }
195
San Mehat4d02d002010-01-22 16:07:46 -0800196 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800197 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800198 mObservers.add(obs);
199 }
200
201 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800202 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800203 mObservers.remove(mObservers.indexOf(obs));
204 }
205
206 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700207 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800208 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700209 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800210 for (INetworkManagementEventObserver obs : mObservers) {
211 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700212 obs.interfaceStatusChanged(iface, up);
213 } catch (Exception ex) {
214 Slog.w(TAG, "Observer notifier failed", ex);
215 }
216 }
217 }
218
219 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700220 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700221 * (typically, an Ethernet cable has been plugged-in or unplugged).
222 */
223 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
224 for (INetworkManagementEventObserver obs : mObservers) {
225 try {
226 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800227 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800228 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800229 }
230 }
231 }
232
233 /**
234 * Notify our observers of an interface addition.
235 */
236 private void notifyInterfaceAdded(String iface) {
237 for (INetworkManagementEventObserver obs : mObservers) {
238 try {
239 obs.interfaceAdded(iface);
240 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800241 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800242 }
243 }
244 }
245
246 /**
247 * Notify our observers of an interface removal.
248 */
249 private void notifyInterfaceRemoved(String iface) {
250 for (INetworkManagementEventObserver obs : mObservers) {
251 try {
252 obs.interfaceRemoved(iface);
253 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800254 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800255 }
256 }
257 }
258
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700259 /**
JP Abgrall12b933d2011-07-14 18:09:22 -0700260 * Notify our observers of a limit reached.
261 */
262 private void notifyLimitReached(String limitName, String iface) {
263 for (INetworkManagementEventObserver obs : mObservers) {
264 try {
265 obs.limitReached(limitName, iface);
JP Abgrall12b933d2011-07-14 18:09:22 -0700266 } catch (Exception ex) {
267 Slog.w(TAG, "Observer notifier failed", ex);
268 }
269 }
270 }
271
272 /**
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700273 * Let us know the daemon is connected
274 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700275 protected void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700276 if (DBG) Slog.d(TAG, "onConnected");
277 mConnectedSignal.countDown();
278 }
279
San Mehat4d02d002010-01-22 16:07:46 -0800280
San Mehat873f2142010-01-14 10:25:07 -0800281 //
282 // Netd Callback handling
283 //
284
285 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700286 /** {@inheritDoc} */
San Mehat873f2142010-01-14 10:25:07 -0800287 public void onDaemonConnected() {
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700288 NetworkManagementService.this.onDaemonConnected();
San Mehat873f2142010-01-14 10:25:07 -0800289 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700290
291 /** {@inheritDoc} */
San Mehat873f2142010-01-14 10:25:07 -0800292 public boolean onEvent(int code, String raw, String[] cooked) {
JP Abgrall12b933d2011-07-14 18:09:22 -0700293 switch (code) {
294 case NetdResponseCode.InterfaceChange:
295 /*
296 * a network interface change occured
297 * Format: "NNN Iface added <name>"
298 * "NNN Iface removed <name>"
299 * "NNN Iface changed <name> <up/down>"
300 * "NNN Iface linkstatus <name> <up/down>"
301 */
302 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
303 throw new IllegalStateException(
304 String.format("Invalid event from daemon (%s)", raw));
305 }
306 if (cooked[2].equals("added")) {
307 notifyInterfaceAdded(cooked[3]);
308 return true;
309 } else if (cooked[2].equals("removed")) {
310 notifyInterfaceRemoved(cooked[3]);
311 return true;
312 } else if (cooked[2].equals("changed") && cooked.length == 5) {
313 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
314 return true;
315 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
316 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
317 return true;
318 }
Robert Greenwalte3253922010-02-18 09:23:25 -0800319 throw new IllegalStateException(
320 String.format("Invalid event from daemon (%s)", raw));
JP Abgrall12b933d2011-07-14 18:09:22 -0700321 // break;
322 case NetdResponseCode.BandwidthControl:
323 /*
324 * Bandwidth control needs some attention
325 * Format: "NNN limit alert <alertName> <ifaceName>"
326 */
327 if (cooked.length < 5 || !cooked[1].equals("limit")) {
328 throw new IllegalStateException(
329 String.format("Invalid event from daemon (%s)", raw));
330 }
331 if (cooked[2].equals("alert")) {
332 notifyLimitReached(cooked[3], cooked[4]);
333 return true;
334 }
335 throw new IllegalStateException(
336 String.format("Invalid event from daemon (%s)", raw));
337 // break;
338 default: break;
Robert Greenwalte3253922010-02-18 09:23:25 -0800339 }
340 return false;
San Mehat873f2142010-01-14 10:25:07 -0800341 }
342 }
343
San Mehated4fc8a2010-01-22 12:28:36 -0800344
San Mehat873f2142010-01-14 10:25:07 -0800345 //
346 // INetworkManagementService members
347 //
348
349 public String[] listInterfaces() throws IllegalStateException {
350 mContext.enforceCallingOrSelfPermission(
351 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
352
Kenny Roota80ce062010-06-01 13:23:53 -0700353 try {
354 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
355 } catch (NativeDaemonConnectorException e) {
356 throw new IllegalStateException(
357 "Cannot communicate with native daemon to list interfaces");
358 }
San Mehated4fc8a2010-01-22 12:28:36 -0800359 }
360
361 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700362 mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
Kenny Roota80ce062010-06-01 13:23:53 -0700363 String rsp;
364 try {
365 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
366 } catch (NativeDaemonConnectorException e) {
367 throw new IllegalStateException(
368 "Cannot communicate with native daemon to get interface config");
369 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800370 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800371
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800372 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800373 StringTokenizer st = new StringTokenizer(rsp);
374
Kenny Roota80ce062010-06-01 13:23:53 -0700375 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800376 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700377 try {
378 int code = Integer.parseInt(st.nextToken(" "));
379 if (code != NetdResponseCode.InterfaceGetCfgResult) {
380 throw new IllegalStateException(
381 String.format("Expected code %d, but got %d",
382 NetdResponseCode.InterfaceGetCfgResult, code));
383 }
384 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800385 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700386 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800387 }
Kenny Roota80ce062010-06-01 13:23:53 -0700388
389 cfg = new InterfaceConfiguration();
390 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800391 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800392 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700393 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800394 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
395 } catch (IllegalArgumentException iae) {
396 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700397 }
398
399 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800400 prefixLength = Integer.parseInt(st.nextToken(" "));
401 } catch (NumberFormatException nfe) {
402 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700403 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800404
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800405 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700406 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
407 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800408 throw new IllegalStateException(
409 String.format("Invalid response from daemon (%s)", rsp));
410 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800411 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800412 return cfg;
413 }
414
415 public void setInterfaceConfig(
416 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700417 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
Robert Greenwalted126402011-01-28 15:34:55 -0800418 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800419 if (linkAddr == null || linkAddr.getAddress() == null) {
420 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800421 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800422 String cmd = String.format("interface setcfg %s %s %d %s", iface,
423 linkAddr.getAddress().getHostAddress(),
424 linkAddr.getNetworkPrefixLength(),
425 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700426 try {
427 mConnector.doCommand(cmd);
428 } catch (NativeDaemonConnectorException e) {
429 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800430 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700431 }
San Mehat873f2142010-01-14 10:25:07 -0800432 }
433
Irfan Sheriff7244c972011-08-05 20:40:45 -0700434 public void setInterfaceDown(String iface) throws IllegalStateException {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700435 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
Irfan Sheriff7244c972011-08-05 20:40:45 -0700436 try {
437 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
438 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
439 setInterfaceConfig(iface, ifcg);
440 } catch (NativeDaemonConnectorException e) {
441 throw new IllegalStateException(
442 "Unable to communicate with native daemon for interface down - " + e);
443 }
444 }
445
446 public void setInterfaceUp(String iface) throws IllegalStateException {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700447 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
Irfan Sheriff7244c972011-08-05 20:40:45 -0700448 try {
449 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
450 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
451 setInterfaceConfig(iface, ifcg);
452 } catch (NativeDaemonConnectorException e) {
453 throw new IllegalStateException(
454 "Unable to communicate with native daemon for interface up - " + e);
455 }
456 }
457
Irfan Sheriff73293612011-09-14 12:31:56 -0700458 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable)
459 throws IllegalStateException {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700460 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
Irfan Sheriff73293612011-09-14 12:31:56 -0700461 String cmd = String.format("interface ipv6privacyextensions %s %s", iface,
462 enable ? "enable" : "disable");
463 try {
464 mConnector.doCommand(cmd);
465 } catch (NativeDaemonConnectorException e) {
466 throw new IllegalStateException(
467 "Unable to communicate with native daemon to set ipv6privacyextensions - " + e);
468 }
469 }
470
471
472
Irfan Sherifff5600612011-06-16 10:26:28 -0700473 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
474 IPv6 addresses on interface down, but we need to do full clean up here */
475 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700476 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
477 String cmd = String.format("interface clearaddrs %s", iface);
Irfan Sherifff5600612011-06-16 10:26:28 -0700478 try {
479 mConnector.doCommand(cmd);
480 } catch (NativeDaemonConnectorException e) {
481 throw new IllegalStateException(
482 "Unable to communicate with native daemon to interface clearallips - " + e);
483 }
484 }
485
repo sync7960d9f2011-09-29 12:40:02 -0700486 public void enableIpv6(String iface) throws IllegalStateException {
487 mContext.enforceCallingOrSelfPermission(
488 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
489 try {
490 mConnector.doCommand(String.format("interface ipv6 %s enable", iface));
491 } catch (NativeDaemonConnectorException e) {
492 throw new IllegalStateException(
493 "Unable to communicate to native daemon for enabling ipv6");
494 }
495 }
496
497 public void disableIpv6(String iface) throws IllegalStateException {
498 mContext.enforceCallingOrSelfPermission(
499 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
500 try {
501 mConnector.doCommand(String.format("interface ipv6 %s disable", iface));
502 } catch (NativeDaemonConnectorException e) {
503 throw new IllegalStateException(
504 "Unable to communicate to native daemon for disabling ipv6");
505 }
506 }
507
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700508 public void addRoute(String interfaceName, RouteInfo route) {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700509 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700510 modifyRoute(interfaceName, ADD, route, DEFAULT);
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700511 }
512
513 public void removeRoute(String interfaceName, RouteInfo route) {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700514 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700515 modifyRoute(interfaceName, REMOVE, route, DEFAULT);
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700516 }
517
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700518 public void addSecondaryRoute(String interfaceName, RouteInfo route) {
519 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
520 modifyRoute(interfaceName, ADD, route, SECONDARY);
521 }
522
523 public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
524 mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
525 modifyRoute(interfaceName, REMOVE, route, SECONDARY);
526 }
527
528 private void modifyRoute(String interfaceName, int action, RouteInfo route, String type) {
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700529 ArrayList<String> rsp;
530
531 StringBuilder cmd;
532
533 switch (action) {
534 case ADD:
535 {
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700536 cmd = new StringBuilder("interface route add " + interfaceName + " " + type);
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700537 break;
538 }
539 case REMOVE:
540 {
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700541 cmd = new StringBuilder("interface route remove " + interfaceName + " " + type);
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700542 break;
543 }
544 default:
545 throw new IllegalStateException("Unknown action type " + action);
546 }
547
548 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
549 LinkAddress la = route.getDestination();
550 cmd.append(' ');
551 cmd.append(la.getAddress().getHostAddress());
552 cmd.append(' ');
553 cmd.append(la.getNetworkPrefixLength());
554 cmd.append(' ');
555 if (route.getGateway() == null) {
556 if (la.getAddress() instanceof Inet4Address) {
557 cmd.append("0.0.0.0");
558 } else {
559 cmd.append ("::0");
560 }
561 } else {
562 cmd.append(route.getGateway().getHostAddress());
563 }
564 try {
565 rsp = mConnector.doCommand(cmd.toString());
566 } catch (NativeDaemonConnectorException e) {
567 throw new IllegalStateException(
568 "Unable to communicate with native dameon to add routes - "
569 + e);
570 }
571
Wink Savillec9acde92011-09-21 11:05:43 -0700572 if (DBG) {
573 for (String line : rsp) {
574 Log.v(TAG, "add route response is " + line);
575 }
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700576 }
577 }
578
579 private ArrayList<String> readRouteList(String filename) {
580 FileInputStream fstream = null;
581 ArrayList<String> list = new ArrayList<String>();
582
583 try {
584 fstream = new FileInputStream(filename);
585 DataInputStream in = new DataInputStream(fstream);
586 BufferedReader br = new BufferedReader(new InputStreamReader(in));
587 String s;
588
589 // throw away the title line
590
591 while (((s = br.readLine()) != null) && (s.length() != 0)) {
592 list.add(s);
593 }
594 } catch (IOException ex) {
595 // return current list, possibly empty
596 } finally {
597 if (fstream != null) {
598 try {
599 fstream.close();
600 } catch (IOException ex) {}
601 }
602 }
603
604 return list;
605 }
606
607 public RouteInfo[] getRoutes(String interfaceName) {
Jeff Sharkeyb0aec072011-10-14 18:32:24 -0700608 mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700609 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
610
611 // v4 routes listed as:
612 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
613 for (String s : readRouteList("/proc/net/route")) {
614 String[] fields = s.split("\t");
615
616 if (fields.length > 7) {
617 String iface = fields[0];
618
619 if (interfaceName.equals(iface)) {
620 String dest = fields[1];
621 String gate = fields[2];
622 String flags = fields[3]; // future use?
623 String mask = fields[7];
624 try {
625 // address stored as a hex string, ex: 0014A8C0
626 InetAddress destAddr =
627 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
628 int prefixLength =
629 NetworkUtils.netmaskIntToPrefixLength(
630 (int)Long.parseLong(mask, 16));
631 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
632
633 // address stored as a hex string, ex 0014A8C0
634 InetAddress gatewayAddr =
635 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
636
637 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
638 routes.add(route);
639 } catch (Exception e) {
640 Log.e(TAG, "Error parsing route " + s + " : " + e);
641 continue;
642 }
643 }
644 }
645 }
646
647 // v6 routes listed as:
648 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
649 for (String s : readRouteList("/proc/net/ipv6_route")) {
650 String[]fields = s.split("\\s+");
651 if (fields.length > 9) {
652 String iface = fields[9].trim();
653 if (interfaceName.equals(iface)) {
654 String dest = fields[0];
655 String prefix = fields[1];
656 String gate = fields[4];
657
658 try {
659 // prefix length stored as a hex string, ex 40
660 int prefixLength = Integer.parseInt(prefix, 16);
661
662 // address stored as a 32 char hex string
663 // ex fe800000000000000000000000000000
664 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
665 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
666
667 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
668
669 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
670 routes.add(route);
671 } catch (Exception e) {
672 Log.e(TAG, "Error parsing route " + s + " : " + e);
673 continue;
674 }
675 }
676 }
677 }
678 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
679 }
680
San Mehat873f2142010-01-14 10:25:07 -0800681 public void shutdown() {
682 if (mContext.checkCallingOrSelfPermission(
683 android.Manifest.permission.SHUTDOWN)
684 != PackageManager.PERMISSION_GRANTED) {
685 throw new SecurityException("Requires SHUTDOWN permission");
686 }
687
Joe Onorato8a9b2202010-02-26 18:56:32 -0800688 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800689 }
690
691 public boolean getIpForwardingEnabled() throws IllegalStateException{
692 mContext.enforceCallingOrSelfPermission(
693 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
694
Kenny Roota80ce062010-06-01 13:23:53 -0700695 ArrayList<String> rsp;
696 try {
697 rsp = mConnector.doCommand("ipfwd status");
698 } catch (NativeDaemonConnectorException e) {
699 throw new IllegalStateException(
700 "Unable to communicate with native daemon to ipfwd status");
701 }
San Mehat873f2142010-01-14 10:25:07 -0800702
703 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700704 String[] tok = line.split(" ");
705 if (tok.length < 3) {
706 Slog.e(TAG, "Malformed response from native daemon: " + line);
707 return false;
708 }
709
San Mehat873f2142010-01-14 10:25:07 -0800710 int code = Integer.parseInt(tok[0]);
711 if (code == NetdResponseCode.IpFwdStatusResult) {
712 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700713 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800714 } else {
715 throw new IllegalStateException(String.format("Unexpected response code %d", code));
716 }
717 }
718 throw new IllegalStateException("Got an empty response");
719 }
720
721 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
722 mContext.enforceCallingOrSelfPermission(
723 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
724 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
725 }
726
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700727 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800728 throws IllegalStateException {
729 mContext.enforceCallingOrSelfPermission(
730 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700731 // cmd is "tether start first_start first_stop second_start second_stop ..."
732 // an odd number of addrs will fail
733 String cmd = "tether start";
734 for (String d : dhcpRange) {
735 cmd += " " + d;
736 }
Kenny Roota80ce062010-06-01 13:23:53 -0700737
738 try {
739 mConnector.doCommand(cmd);
740 } catch (NativeDaemonConnectorException e) {
741 throw new IllegalStateException("Unable to communicate to native daemon");
742 }
San Mehat873f2142010-01-14 10:25:07 -0800743 }
744
745 public void stopTethering() throws IllegalStateException {
746 mContext.enforceCallingOrSelfPermission(
747 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700748 try {
749 mConnector.doCommand("tether stop");
750 } catch (NativeDaemonConnectorException e) {
751 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
752 }
San Mehat873f2142010-01-14 10:25:07 -0800753 }
754
755 public boolean isTetheringStarted() throws IllegalStateException {
756 mContext.enforceCallingOrSelfPermission(
757 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
758
Kenny Roota80ce062010-06-01 13:23:53 -0700759 ArrayList<String> rsp;
760 try {
761 rsp = mConnector.doCommand("tether status");
762 } catch (NativeDaemonConnectorException e) {
763 throw new IllegalStateException(
764 "Unable to communicate to native daemon to get tether status");
765 }
San Mehat873f2142010-01-14 10:25:07 -0800766
767 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700768 String[] tok = line.split(" ");
769 if (tok.length < 3) {
770 throw new IllegalStateException("Malformed response for tether status: " + line);
771 }
San Mehat873f2142010-01-14 10:25:07 -0800772 int code = Integer.parseInt(tok[0]);
773 if (code == NetdResponseCode.TetherStatusResult) {
774 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700775 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800776 } else {
777 throw new IllegalStateException(String.format("Unexpected response code %d", code));
778 }
779 }
780 throw new IllegalStateException("Got an empty response");
781 }
782
783 public void tetherInterface(String iface) throws IllegalStateException {
784 mContext.enforceCallingOrSelfPermission(
785 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700786 try {
787 mConnector.doCommand("tether interface add " + iface);
788 } catch (NativeDaemonConnectorException e) {
789 throw new IllegalStateException(
790 "Unable to communicate to native daemon for adding tether interface");
791 }
San Mehat873f2142010-01-14 10:25:07 -0800792 }
793
794 public void untetherInterface(String iface) {
795 mContext.enforceCallingOrSelfPermission(
796 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700797 try {
798 mConnector.doCommand("tether interface remove " + iface);
799 } catch (NativeDaemonConnectorException e) {
800 throw new IllegalStateException(
801 "Unable to communicate to native daemon for removing tether interface");
802 }
San Mehat873f2142010-01-14 10:25:07 -0800803 }
804
805 public String[] listTetheredInterfaces() throws IllegalStateException {
806 mContext.enforceCallingOrSelfPermission(
807 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700808 try {
809 return mConnector.doListCommand(
810 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
811 } catch (NativeDaemonConnectorException e) {
812 throw new IllegalStateException(
813 "Unable to communicate to native daemon for listing tether interfaces");
814 }
San Mehat873f2142010-01-14 10:25:07 -0800815 }
816
817 public void setDnsForwarders(String[] dns) throws IllegalStateException {
818 mContext.enforceCallingOrSelfPermission(
819 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
820 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800821 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800822 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800823 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800824 }
Kenny Roota80ce062010-06-01 13:23:53 -0700825 try {
826 mConnector.doCommand(cmd);
827 } catch (NativeDaemonConnectorException e) {
828 throw new IllegalStateException(
829 "Unable to communicate to native daemon for setting tether dns");
830 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800831 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800832 throw new IllegalStateException("Error resolving dns name", e);
833 }
834 }
835
836 public String[] getDnsForwarders() throws IllegalStateException {
837 mContext.enforceCallingOrSelfPermission(
838 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700839 try {
840 return mConnector.doListCommand(
841 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
842 } catch (NativeDaemonConnectorException e) {
843 throw new IllegalStateException(
844 "Unable to communicate to native daemon for listing tether dns");
845 }
San Mehat873f2142010-01-14 10:25:07 -0800846 }
847
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700848 private void modifyNat(String cmd, String internalInterface, String externalInterface)
849 throws SocketException {
850 cmd = String.format("nat %s %s %s", cmd, internalInterface, externalInterface);
851
852 NetworkInterface internalNetworkInterface =
853 NetworkInterface.getByName(internalInterface);
854 Collection<InterfaceAddress>interfaceAddresses =
855 internalNetworkInterface.getInterfaceAddresses();
856 cmd += " " + interfaceAddresses.size();
857 for (InterfaceAddress ia : interfaceAddresses) {
858 InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(),
859 ia.getNetworkPrefixLength());
860 cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength();
861 }
862
863 mConnector.doCommand(cmd);
864 }
865
San Mehat873f2142010-01-14 10:25:07 -0800866 public void enableNat(String internalInterface, String externalInterface)
867 throws IllegalStateException {
868 mContext.enforceCallingOrSelfPermission(
869 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700870 if (DBG) Log.d(TAG, "enableNat(" + internalInterface + ", " + externalInterface + ")");
Kenny Roota80ce062010-06-01 13:23:53 -0700871 try {
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700872 modifyNat("enable", internalInterface, externalInterface);
873 } catch (Exception e) {
874 Log.e(TAG, "enableNat got Exception " + e.toString());
Kenny Roota80ce062010-06-01 13:23:53 -0700875 throw new IllegalStateException(
876 "Unable to communicate to native daemon for enabling NAT interface");
877 }
San Mehat873f2142010-01-14 10:25:07 -0800878 }
879
880 public void disableNat(String internalInterface, String externalInterface)
881 throws IllegalStateException {
882 mContext.enforceCallingOrSelfPermission(
883 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700884 if (DBG) Log.d(TAG, "disableNat(" + internalInterface + ", " + externalInterface + ")");
Kenny Roota80ce062010-06-01 13:23:53 -0700885 try {
Robert Greenwalt3b28e9a2011-11-02 14:37:19 -0700886 modifyNat("disable", internalInterface, externalInterface);
887 } catch (Exception e) {
888 Log.e(TAG, "disableNat got Exception " + e.toString());
Kenny Roota80ce062010-06-01 13:23:53 -0700889 throw new IllegalStateException(
890 "Unable to communicate to native daemon for disabling NAT interface");
891 }
San Mehat873f2142010-01-14 10:25:07 -0800892 }
San Mehat72759df2010-01-19 13:50:37 -0800893
894 public String[] listTtys() throws IllegalStateException {
895 mContext.enforceCallingOrSelfPermission(
896 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700897 try {
898 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
899 } catch (NativeDaemonConnectorException e) {
900 throw new IllegalStateException(
901 "Unable to communicate to native daemon for listing TTYs");
902 }
San Mehat72759df2010-01-19 13:50:37 -0800903 }
904
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800905 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
906 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800907 try {
908 mContext.enforceCallingOrSelfPermission(
909 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800910 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800911 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
912 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
913 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
914 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
915 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800916 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700917 } catch (NativeDaemonConnectorException e) {
918 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800919 }
920 }
921
922 public void detachPppd(String tty) throws IllegalStateException {
923 mContext.enforceCallingOrSelfPermission(
924 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700925 try {
926 mConnector.doCommand(String.format("pppd detach %s", tty));
927 } catch (NativeDaemonConnectorException e) {
928 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
929 }
San Mehat72759df2010-01-19 13:50:37 -0800930 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800931
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700932 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800933 throws IllegalStateException {
934 mContext.enforceCallingOrSelfPermission(
935 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
936 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700937 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700938 try {
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700939 wifiFirmwareReload(wlanIface, "AP");
Kenny Roota80ce062010-06-01 13:23:53 -0700940 mConnector.doCommand(String.format("softap start " + wlanIface));
941 if (wifiConfig == null) {
942 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
943 } else {
944 /**
945 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
946 * argv1 - wlan interface
947 * argv2 - softap interface
948 * argv3 - SSID
949 * argv4 - Security
950 * argv5 - Key
951 * argv6 - Channel
952 * argv7 - Preamble
953 * argv8 - Max SCB
954 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800955 String str = String.format("softap set " + wlanIface + " " + softapIface +
956 " %s %s %s", convertQuotedString(wifiConfig.SSID),
957 getSecurityType(wifiConfig),
958 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700959 mConnector.doCommand(str);
960 }
961 mConnector.doCommand(String.format("softap startap"));
962 } catch (NativeDaemonConnectorException e) {
963 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800964 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800965 }
966
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700967 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700968 if (s == null) {
969 return s;
970 }
971 /* Replace \ with \\, then " with \" and add quotes at end */
972 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700973 }
974
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800975 private String getSecurityType(WifiConfiguration wifiConfig) {
976 switch (wifiConfig.getAuthType()) {
977 case KeyMgmt.WPA_PSK:
978 return "wpa-psk";
979 case KeyMgmt.WPA2_PSK:
980 return "wpa2-psk";
981 default:
982 return "open";
983 }
984 }
985
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700986 /* @param mode can be "AP", "STA" or "P2P" */
987 public void wifiFirmwareReload(String wlanIface, String mode) throws IllegalStateException {
988 mContext.enforceCallingOrSelfPermission(
989 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
990 mContext.enforceCallingOrSelfPermission(
991 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
992
993 try {
994 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " " + mode));
995 } catch (NativeDaemonConnectorException e) {
996 throw new IllegalStateException("Error communicating to native daemon ", e);
997 }
998 }
999
Irfan Sheriff23eb2972011-07-22 15:21:10 -07001000 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -08001001 mContext.enforceCallingOrSelfPermission(
1002 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1003 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -07001004 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001005 try {
1006 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -07001007 mConnector.doCommand("softap stop " + wlanIface);
Irfan Sheriffcb30b222011-07-29 20:54:52 -07001008 wifiFirmwareReload(wlanIface, "STA");
Kenny Roota80ce062010-06-01 13:23:53 -07001009 } catch (NativeDaemonConnectorException e) {
1010 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
1011 e);
1012 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -08001013 }
1014
Irfan Sheriffc2f54c22010-03-18 14:02:22 -07001015 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
1016 throws IllegalStateException {
1017 mContext.enforceCallingOrSelfPermission(
1018 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1019 mContext.enforceCallingOrSelfPermission(
1020 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001021 try {
1022 if (wifiConfig == null) {
1023 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
1024 } else {
1025 String str = String.format("softap set " + wlanIface + " " + softapIface
1026 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -08001027 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -07001028 convertQuotedString(wifiConfig.preSharedKey));
1029 mConnector.doCommand(str);
1030 }
1031 } catch (NativeDaemonConnectorException e) {
1032 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
1033 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -07001034 }
1035 }
San Mehat91cac642010-03-31 14:31:36 -07001036
1037 private long getInterfaceCounter(String iface, boolean rx) {
1038 mContext.enforceCallingOrSelfPermission(
1039 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1040 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001041 String rsp;
1042 try {
1043 rsp = mConnector.doCommand(
1044 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
1045 } catch (NativeDaemonConnectorException e1) {
1046 Slog.e(TAG, "Error communicating with native daemon", e1);
1047 return -1;
1048 }
1049
1050 String[] tok = rsp.split(" ");
1051 if (tok.length < 2) {
1052 Slog.e(TAG, String.format("Malformed response for reading %s interface",
1053 (rx ? "rx" : "tx")));
1054 return -1;
1055 }
1056
San Mehat91cac642010-03-31 14:31:36 -07001057 int code;
1058 try {
1059 code = Integer.parseInt(tok[0]);
1060 } catch (NumberFormatException nfe) {
1061 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1062 return -1;
1063 }
1064 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
1065 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
1066 Slog.e(TAG, String.format("Unexpected response code %d", code));
1067 return -1;
1068 }
1069 return Long.parseLong(tok[1]);
1070 } catch (Exception e) {
1071 Slog.e(TAG, String.format(
1072 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
1073 }
1074 return -1;
1075 }
1076
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001077 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001078 public NetworkStats getNetworkStatsSummary() {
1079 mContext.enforceCallingOrSelfPermission(
1080 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Jeff Sharkey1059c3c2011-10-04 16:54:49 -07001081 return mStatsFactory.readNetworkStatsSummary();
Jeff Sharkeyae2c1812011-10-04 13:11:40 -07001082 }
1083
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001084 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001085 public NetworkStats getNetworkStatsDetail() {
1086 mContext.enforceCallingOrSelfPermission(
1087 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Jeff Sharkey1059c3c2011-10-04 16:54:49 -07001088 return mStatsFactory.readNetworkStatsDetail(UID_ALL);
San Mehat91cac642010-03-31 14:31:36 -07001089 }
1090
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001091 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001092 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001093 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1094
Jeff Sharkey350083e2011-06-29 10:45:16 -07001095 // silently discard when control disabled
1096 // TODO: eventually migrate to be always enabled
1097 if (!mBandwidthControlEnabled) return;
1098
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001099 synchronized (mQuotaLock) {
1100 if (mActiveQuotaIfaces.contains(iface)) {
1101 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001102 }
1103
1104 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001105 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001106
1107 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001108 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001109 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001110 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001111 } catch (NativeDaemonConnectorException e) {
1112 throw new IllegalStateException("Error communicating to native daemon", e);
1113 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001114 }
1115 }
1116
1117 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001118 public void removeInterfaceQuota(String iface) {
1119 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1120
Jeff Sharkey350083e2011-06-29 10:45:16 -07001121 // silently discard when control disabled
1122 // TODO: eventually migrate to be always enabled
1123 if (!mBandwidthControlEnabled) return;
1124
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001125 synchronized (mQuotaLock) {
1126 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001127 // TODO: eventually consider throwing
1128 return;
1129 }
1130
1131 final StringBuilder command = new StringBuilder();
1132 command.append("bandwidth removeiquota ").append(iface);
1133
1134 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001135 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001136 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001137 mActiveQuotaIfaces.remove(iface);
1138 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001139 } catch (NativeDaemonConnectorException e) {
1140 throw new IllegalStateException("Error communicating to native daemon", e);
1141 }
1142 }
1143 }
1144
1145 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001146 public void setInterfaceAlert(String iface, long alertBytes) {
1147 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1148
1149 // silently discard when control disabled
1150 // TODO: eventually migrate to be always enabled
1151 if (!mBandwidthControlEnabled) return;
1152
1153 // quick sanity check
1154 if (!mActiveQuotaIfaces.contains(iface)) {
1155 throw new IllegalStateException("setting alert requires existing quota on iface");
1156 }
1157
1158 synchronized (mQuotaLock) {
1159 if (mActiveAlertIfaces.contains(iface)) {
1160 throw new IllegalStateException("iface " + iface + " already has alert");
1161 }
1162
1163 final StringBuilder command = new StringBuilder();
1164 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1165 alertBytes);
1166
1167 try {
1168 // TODO: support alert shared across interfaces
1169 mConnector.doCommand(command.toString());
1170 mActiveAlertIfaces.add(iface);
1171 } catch (NativeDaemonConnectorException e) {
1172 throw new IllegalStateException("Error communicating to native daemon", e);
1173 }
1174 }
1175 }
1176
1177 @Override
1178 public void removeInterfaceAlert(String iface) {
1179 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1180
1181 // silently discard when control disabled
1182 // TODO: eventually migrate to be always enabled
1183 if (!mBandwidthControlEnabled) return;
1184
1185 synchronized (mQuotaLock) {
1186 if (!mActiveAlertIfaces.contains(iface)) {
1187 // TODO: eventually consider throwing
1188 return;
1189 }
1190
1191 final StringBuilder command = new StringBuilder();
1192 command.append("bandwidth removeinterfacealert ").append(iface);
1193
1194 try {
1195 // TODO: support alert shared across interfaces
1196 mConnector.doCommand(command.toString());
1197 mActiveAlertIfaces.remove(iface);
1198 } catch (NativeDaemonConnectorException e) {
1199 throw new IllegalStateException("Error communicating to native daemon", e);
1200 }
1201 }
1202 }
1203
1204 @Override
1205 public void setGlobalAlert(long alertBytes) {
1206 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1207
1208 // silently discard when control disabled
1209 // TODO: eventually migrate to be always enabled
1210 if (!mBandwidthControlEnabled) return;
1211
1212 final StringBuilder command = new StringBuilder();
1213 command.append("bandwidth setglobalalert ").append(alertBytes);
1214
1215 try {
1216 mConnector.doCommand(command.toString());
1217 } catch (NativeDaemonConnectorException e) {
1218 throw new IllegalStateException("Error communicating to native daemon", e);
1219 }
1220 }
1221
1222 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001223 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1224 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1225
Jeff Sharkey350083e2011-06-29 10:45:16 -07001226 // silently discard when control disabled
1227 // TODO: eventually migrate to be always enabled
1228 if (!mBandwidthControlEnabled) return;
1229
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001230 synchronized (mUidRejectOnQuota) {
1231 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1232 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1233 // TODO: eventually consider throwing
1234 return;
1235 }
1236
1237 final StringBuilder command = new StringBuilder();
1238 command.append("bandwidth");
1239 if (rejectOnQuotaInterfaces) {
1240 command.append(" addnaughtyapps");
1241 } else {
1242 command.append(" removenaughtyapps");
1243 }
1244 command.append(" ").append(uid);
1245
1246 try {
1247 mConnector.doCommand(command.toString());
1248 if (rejectOnQuotaInterfaces) {
1249 mUidRejectOnQuota.put(uid, true);
1250 } else {
1251 mUidRejectOnQuota.delete(uid);
1252 }
1253 } catch (NativeDaemonConnectorException e) {
1254 throw new IllegalStateException("Error communicating to native daemon", e);
1255 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001256 }
1257 }
1258
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001259 @Override
1260 public boolean isBandwidthControlEnabled() {
1261 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1262 return mBandwidthControlEnabled;
1263 }
1264
1265 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001266 public NetworkStats getNetworkStatsUidDetail(int uid) {
1267 if (Binder.getCallingUid() != uid) {
1268 mContext.enforceCallingOrSelfPermission(
1269 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1270 }
Jeff Sharkey1059c3c2011-10-04 16:54:49 -07001271 return mStatsFactory.readNetworkStatsDetail(uid);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001272 }
1273
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -07001274 @Override
1275 public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
1276 mContext.enforceCallingOrSelfPermission(
1277 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1278
1279 if (ifacePairs.length % 2 != 0) {
1280 throw new IllegalArgumentException(
1281 "unexpected ifacePairs; length=" + ifacePairs.length);
1282 }
1283
1284 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1285 for (int i = 0; i < ifacePairs.length; i += 2) {
1286 final String ifaceIn = ifacePairs[i];
1287 final String ifaceOut = ifacePairs[i + 1];
1288 if (ifaceIn != null && ifaceOut != null) {
1289 stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
1290 }
1291 }
1292 return stats;
1293 }
1294
1295 private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
1296 final StringBuilder command = new StringBuilder();
1297 command.append("bandwidth gettetherstats ").append(ifaceIn).append(" ").append(ifaceOut);
1298
1299 final String rsp;
1300 try {
1301 rsp = mConnector.doCommand(command.toString()).get(0);
1302 } catch (NativeDaemonConnectorException e) {
1303 throw new IllegalStateException("Error communicating to native daemon", e);
1304 }
1305
1306 final String[] tok = rsp.split(" ");
1307 /* Expecting: "code ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets" */
1308 if (tok.length != 7) {
1309 throw new IllegalStateException("Native daemon returned unexpected result: " + rsp);
1310 }
1311
1312 final int code;
1313 try {
1314 code = Integer.parseInt(tok[0]);
1315 } catch (NumberFormatException e) {
1316 throw new IllegalStateException(
1317 "Failed to parse native daemon return code for " + ifaceIn + " " + ifaceOut);
1318 }
1319 if (code != NetdResponseCode.TetheringStatsResult) {
1320 throw new IllegalStateException(
1321 "Unexpected return code from native daemon for " + ifaceIn + " " + ifaceOut);
1322 }
1323
1324 try {
1325 final NetworkStats.Entry entry = new NetworkStats.Entry();
1326 entry.iface = ifaceIn;
Jeff Sharkey905b5892011-09-30 15:19:49 -07001327 entry.uid = UID_TETHERING;
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -07001328 entry.set = SET_DEFAULT;
1329 entry.tag = TAG_NONE;
1330 entry.rxBytes = Long.parseLong(tok[3]);
1331 entry.rxPackets = Long.parseLong(tok[4]);
1332 entry.txBytes = Long.parseLong(tok[5]);
1333 entry.txPackets = Long.parseLong(tok[6]);
1334 return entry;
1335 } catch (NumberFormatException e) {
1336 throw new IllegalStateException(
1337 "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
1338 }
1339 }
1340
San Mehatf0db6e12010-04-07 15:22:10 -07001341 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001342 mContext.enforceCallingOrSelfPermission(
1343 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001344 try {
1345 mConnector.doCommand(String.format(
1346 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1347 } catch (NativeDaemonConnectorException e) {
1348 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1349 }
San Mehat91cac642010-03-31 14:31:36 -07001350 }
1351
1352 private int getInterfaceThrottle(String iface, boolean rx) {
1353 mContext.enforceCallingOrSelfPermission(
1354 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1355 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001356 String rsp;
1357 try {
1358 rsp = mConnector.doCommand(
1359 String.format("interface getthrottle %s %s", iface,
1360 (rx ? "rx" : "tx"))).get(0);
1361 } catch (NativeDaemonConnectorException e) {
1362 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1363 return -1;
1364 }
1365
1366 String[] tok = rsp.split(" ");
1367 if (tok.length < 2) {
1368 Slog.e(TAG, "Malformed response to getthrottle command");
1369 return -1;
1370 }
1371
San Mehat91cac642010-03-31 14:31:36 -07001372 int code;
1373 try {
1374 code = Integer.parseInt(tok[0]);
1375 } catch (NumberFormatException nfe) {
1376 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1377 return -1;
1378 }
1379 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1380 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1381 Slog.e(TAG, String.format("Unexpected response code %d", code));
1382 return -1;
1383 }
1384 return Integer.parseInt(tok[1]);
1385 } catch (Exception e) {
1386 Slog.e(TAG, String.format(
1387 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1388 }
1389 return -1;
1390 }
1391
1392 public int getInterfaceRxThrottle(String iface) {
1393 return getInterfaceThrottle(iface, true);
1394 }
1395
1396 public int getInterfaceTxThrottle(String iface) {
1397 return getInterfaceThrottle(iface, false);
1398 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001399
Mattias Falk7475c0c2011-04-04 16:10:36 +02001400 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1401 mContext.enforceCallingOrSelfPermission(
1402 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1403 try {
1404 String cmd = "resolver setdefaultif " + iface;
1405
1406 mConnector.doCommand(cmd);
1407 } catch (NativeDaemonConnectorException e) {
1408 throw new IllegalStateException(
1409 "Error communicating with native daemon to set default interface", e);
1410 }
1411 }
1412
1413 public void setDnsServersForInterface(String iface, String[] servers)
1414 throws IllegalStateException {
1415 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1416 "NetworkManagementService");
1417 try {
1418 String cmd = "resolver setifdns " + iface;
1419 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001420 InetAddress a = NetworkUtils.numericToInetAddress(s);
1421 if (a.isAnyLocalAddress() == false) {
1422 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001423 }
1424 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001425 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001426 } catch (IllegalArgumentException e) {
1427 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001428 } catch (NativeDaemonConnectorException e) {
1429 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001430 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001431 }
1432 }
1433
1434 public void flushDefaultDnsCache() throws IllegalStateException {
1435 mContext.enforceCallingOrSelfPermission(
1436 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1437 try {
1438 String cmd = "resolver flushdefaultif";
1439
1440 mConnector.doCommand(cmd);
1441 } catch (NativeDaemonConnectorException e) {
1442 throw new IllegalStateException(
1443 "Error communicating with native deamon to flush default interface", e);
1444 }
1445 }
1446
1447 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1448 mContext.enforceCallingOrSelfPermission(
1449 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1450 try {
1451 String cmd = "resolver flushif " + iface;
1452
1453 mConnector.doCommand(cmd);
1454 } catch (NativeDaemonConnectorException e) {
1455 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001456 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001457 }
1458 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001459
1460 /** {@inheritDoc} */
1461 public void monitor() {
1462 if (mConnector != null) {
1463 mConnector.monitor();
1464 }
1465 }
Jeff Sharkey47eb1022011-08-25 17:48:52 -07001466
1467 @Override
1468 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1469 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1470
1471 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
1472
1473 synchronized (mQuotaLock) {
1474 pw.print("Active quota ifaces: "); pw.println(mActiveQuotaIfaces.toString());
1475 pw.print("Active alert ifaces: "); pw.println(mActiveAlertIfaces.toString());
1476 }
1477
1478 synchronized (mUidRejectOnQuota) {
1479 pw.print("UID reject on quota ifaces: [");
1480 final int size = mUidRejectOnQuota.size();
1481 for (int i = 0; i < size; i++) {
1482 pw.print(mUidRejectOnQuota.keyAt(i));
1483 if (i < size - 1) pw.print(",");
1484 }
1485 pw.println("]");
1486 }
1487 }
San Mehat873f2142010-01-14 10:25:07 -08001488}