NetworkManagementService.java revision 89b8a2161ab6ad0211df305da1eebd6227a217e6
1873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat/*
2873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * Copyright (C) 2007 The Android Open Source Project
3873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat *
4873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * you may not use this file except in compliance with the License.
6873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * You may obtain a copy of the License at
7873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat *
8873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat *
10873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * Unless required by applicable law or agreed to in writing, software
11873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * See the License for the specific language governing permissions and
14873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * limitations under the License.
15873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat */
16873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
17873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatpackage com.android.server;
18873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
1947eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkeyimport static android.Manifest.permission.DUMP;
20350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkeyimport static android.Manifest.permission.MANAGE_NETWORK_POLICY;
21b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkeyimport static android.net.NetworkStats.SET_DEFAULT;
221b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkStats.TAG_NONE;
231b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkStats.UID_ALL;
24ae2c1810839430c84e4a1172580d9c4b18f568caJeff Sharkeyimport static android.net.TrafficStats.UID_TETHERING;
25350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkeyimport static android.provider.Settings.Secure.NETSTATS_ENABLED;
26a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
271b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
28873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.Context;
29873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.pm.PackageManager;
304d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehatimport android.net.INetworkManagementEventObserver;
31eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport android.net.InterfaceConfiguration;
32ed1264093234b1f1354cd5f669eb82a50bb56869Robert Greenwaltimport android.net.LinkAddress;
33eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport android.net.NetworkStats;
34ed1264093234b1f1354cd5f669eb82a50bb56869Robert Greenwaltimport android.net.NetworkUtils;
3559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwaltimport android.net.RouteInfo;
369ab518ad793385f8405edf19363fe825fb64f5f8Irfan Sheriffimport android.net.wifi.WifiConfiguration;
379ab518ad793385f8405edf19363fe825fb64f5f8Irfan Sheriffimport android.net.wifi.WifiConfiguration.KeyMgmt;
38eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport android.os.Binder;
39873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.os.INetworkManagementService;
409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.SystemClock;
4162dbb22bd4878369975492c8a1c234840e418a4fMarco Nelissenimport android.os.SystemProperties;
42350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkeyimport android.provider.Settings;
439ab518ad793385f8405edf19363fe825fb64f5f8Irfan Sheriffimport android.util.Log;
448a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
45b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkeyimport android.util.SparseBooleanArray;
46873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
471059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkeyimport com.android.internal.net.NetworkStatsFactory;
48b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkeyimport com.google.android.collect.Sets;
494414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey
5059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwaltimport java.io.BufferedReader;
5159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwaltimport java.io.DataInputStream;
52873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.io.File;
5347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkeyimport java.io.FileDescriptor;
549a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.FileInputStream;
559a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.IOException;
569a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.InputStreamReader;
5747eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkeyimport java.io.PrintWriter;
5859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwaltimport java.net.Inet4Address;
59eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport java.net.InetAddress;
60eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport java.util.ArrayList;
61b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkeyimport java.util.HashSet;
62eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport java.util.NoSuchElementException;
63eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkeyimport java.util.StringTokenizer;
64e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwaltimport java.util.concurrent.CountDownLatch;
65873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
66873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat/**
67873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * @hide
68873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat */
698e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkeypublic class NetworkManagementService extends INetworkManagementService.Stub
708e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        implements Watchdog.Monitor {
71eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    private static final String TAG = "NetworkManagementService";
72cef65eeb0315c3118bf8860d6f723cb49ff6bc52Dianne Hackborn    private static final boolean DBG = false;
73305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String NETD_TAG = "NetdConnector";
74305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
7559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    private static final int ADD = 1;
7659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    private static final int REMOVE = 2;
7759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
788e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    /**
798e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * Name representing {@link #setGlobalAlert(long)} limit when delivered to
808e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * {@link INetworkManagementEventObserver#limitReached(String, String)}.
818e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     */
828e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
838e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
84873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    class NetdResponseCode {
8512b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall        /* Keep in sync with system/netd/ResponseCode.h */
86873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int InterfaceListResult       = 110;
87873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int TetherInterfaceListResult = 111;
88873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int TetherDnsFwdTgtListResult = 112;
8972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        public static final int TtyListResult             = 113;
90873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
91873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int TetherStatusResult        = 210;
92873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int IpFwdStatusResult         = 211;
93ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        public static final int InterfaceGetCfgResult     = 213;
94e325392c257a5460de6327420c81729f4e687881Robert Greenwalt        public static final int SoftapStatusResult        = 214;
9591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        public static final int InterfaceRxCounterResult  = 216;
9691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        public static final int InterfaceTxCounterResult  = 217;
9791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        public static final int InterfaceRxThrottleResult = 218;
9891cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        public static final int InterfaceTxThrottleResult = 219;
99cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        public static final int QuotaCounterResult        = 220;
100cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        public static final int TetheringStatsResult      = 221;
101e325392c257a5460de6327420c81729f4e687881Robert Greenwalt
102e325392c257a5460de6327420c81729f4e687881Robert Greenwalt        public static final int InterfaceChange           = 600;
10312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall        public static final int BandwidthControl          = 601;
104873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
105873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
106873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
107873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * Binder context for this service
108873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
109873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private Context mContext;
110873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
111873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
112873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * connector object for communicating with netd
113873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
114873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private NativeDaemonConnector mConnector;
115873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
116e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt    private Thread mThread;
117e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt    private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
118e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt
11941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    // TODO: replace with RemoteCallbackList
1204d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private ArrayList<INetworkManagementEventObserver> mObservers;
1214d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1221059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
1231059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
12441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private Object mQuotaLock = new Object();
125b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    /** Set of interfaces with active quotas. */
12641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
12741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /** Set of interfaces with active alerts. */
12841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
129b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    /** Set of UIDs with active reject rules. */
130b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
131b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
132fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    private volatile boolean mBandwidthControlEnabled;
133350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
134873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
135873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * Constructs a new NetworkManagementService instance
136873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     *
137873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * @param context  Binder context for this service
138873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
1391059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    private NetworkManagementService(Context context) {
140873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext = context;
1414d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers = new ArrayList<INetworkManagementEventObserver>();
1424d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
14362dbb22bd4878369975492c8a1c234840e418a4fMarco Nelissen        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
14462dbb22bd4878369975492c8a1c234840e418a4fMarco Nelissen            return;
14562dbb22bd4878369975492c8a1c234840e418a4fMarco Nelissen        }
14662dbb22bd4878369975492c8a1c234840e418a4fMarco Nelissen
147873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector = new NativeDaemonConnector(
148305bcbf0c961840c4505770d084a1caacc074dbbKenny Root                new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
149e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        mThread = new Thread(mConnector, NETD_TAG);
150fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey
151fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        // Add ourself to the Watchdog monitors.
152fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        Watchdog.getInstance().addMonitor(this);
153e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt    }
154e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt
155e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt    public static NetworkManagementService create(Context context) throws InterruptedException {
1561059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        NetworkManagementService service = new NetworkManagementService(context);
157e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
158e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        service.mThread.start();
159e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        if (DBG) Slog.d(TAG, "Awaiting socket connection");
160e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        service.mConnectedSignal.await();
161e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        if (DBG) Slog.d(TAG, "Connected");
162e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        return service;
163873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
164873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
165350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey    public void systemReady() {
166350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // only enable bandwidth control when support exists, and requested by
167350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // system setting.
168350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
169350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        final boolean shouldEnable =
17005355c3eb69ef2cd8d08260be059be006a2883b9Jeff Sharkey                Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
171350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
172350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (hasKernelSupport && shouldEnable) {
173350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            Slog.d(TAG, "enabling bandwidth control");
174350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            try {
175350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey                mConnector.doCommand("bandwidth enable");
176350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey                mBandwidthControlEnabled = true;
177350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            } catch (NativeDaemonConnectorException e) {
1781059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                Log.wtf(TAG, "problem enabling bandwidth controls", e);
179350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            }
180350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        } else {
181350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            Slog.d(TAG, "not enabling bandwidth control");
182350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        }
18362a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey
184a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
185350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey    }
186350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
1874d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    public void registerObserver(INetworkManagementEventObserver obs) {
1888a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, "Registering observer");
1894d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers.add(obs);
1904d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1914d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1924d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    public void unregisterObserver(INetworkManagementEventObserver obs) {
1938a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, "Unregistering observer");
1944d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers.remove(mObservers.indexOf(obs));
1954d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1964d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1974d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1986143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen     * Notify our observers of an interface status change
1994d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
2006143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen    private void notifyInterfaceStatusChanged(String iface, boolean up) {
2014d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
2024d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
2036143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen                obs.interfaceStatusChanged(iface, up);
2046143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen            } catch (Exception ex) {
2056143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen                Slog.w(TAG, "Observer notifier failed", ex);
2066143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen            }
2076143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen        }
2086143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen    }
2096143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen
2106143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen    /**
211f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen     * Notify our observers of an interface link state change
2126143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen     * (typically, an Ethernet cable has been plugged-in or unplugged).
2136143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen     */
2146143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen    private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
2156143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen        for (INetworkManagementEventObserver obs : mObservers) {
2166143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen            try {
2176143f5f7392fb0d3e5702a46a2415bd0ecb6efb4Mike J. Chen                obs.interfaceLinkStateChanged(iface, up);
2184d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
2198a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Observer notifier failed", ex);
2204d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
2214d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
2224d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
2234d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
2244d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
2254d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface addition.
2264d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
2274d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceAdded(String iface) {
2284d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
2294d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
2304d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceAdded(iface);
2314d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
2328a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Observer notifier failed", ex);
2334d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
2344d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
2354d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
2364d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
2374d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
2384d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface removal.
2394d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
2404d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceRemoved(String iface) {
24189b8a2161ab6ad0211df305da1eebd6227a217e6Jeff Sharkey        // netd already clears out quota and alerts for removed ifaces; update
24289b8a2161ab6ad0211df305da1eebd6227a217e6Jeff Sharkey        // our sanity-checking state.
24389b8a2161ab6ad0211df305da1eebd6227a217e6Jeff Sharkey        mActiveAlertIfaces.remove(iface);
24489b8a2161ab6ad0211df305da1eebd6227a217e6Jeff Sharkey        mActiveQuotaIfaces.remove(iface);
24589b8a2161ab6ad0211df305da1eebd6227a217e6Jeff Sharkey
2464d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
2474d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
2484d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceRemoved(iface);
2494d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
2508a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.w(TAG, "Observer notifier failed", ex);
2514d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
2524d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
2534d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
2544d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
255e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt    /**
25612b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall     * Notify our observers of a limit reached.
25712b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall     */
25812b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall    private void notifyLimitReached(String limitName, String iface) {
25912b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall        for (INetworkManagementEventObserver obs : mObservers) {
26012b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            try {
26112b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                obs.limitReached(limitName, iface);
26212b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            } catch (Exception ex) {
26312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                Slog.w(TAG, "Observer notifier failed", ex);
26412b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            }
26512b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall        }
26612b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall    }
26712b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall
26812b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall    /**
269e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt     * Let us know the daemon is connected
270e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt     */
271fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    protected void onDaemonConnected() {
272e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        if (DBG) Slog.d(TAG, "onConnected");
273e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt        mConnectedSignal.countDown();
274e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt    }
275e5c3afb29241fd3faae309f973645d7f6a7ed111Robert Greenwalt
2764d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
277873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
278873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    // Netd Callback handling
279873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
280873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
281873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
282fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        /** {@inheritDoc} */
283873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public void onDaemonConnected() {
284fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey            NetworkManagementService.this.onDaemonConnected();
285873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
286fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey
287fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        /** {@inheritDoc} */
288873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public boolean onEvent(int code, String raw, String[] cooked) {
28912b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            switch (code) {
29012b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            case NetdResponseCode.InterfaceChange:
29112b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    /*
29212b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     * a network interface change occured
29312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     * Format: "NNN Iface added <name>"
29412b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     *         "NNN Iface removed <name>"
29512b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     *         "NNN Iface changed <name> <up/down>"
29612b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     *         "NNN Iface linkstatus <name> <up/down>"
29712b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     */
29812b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    if (cooked.length < 4 || !cooked[1].equals("Iface")) {
29912b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        throw new IllegalStateException(
30012b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                                String.format("Invalid event from daemon (%s)", raw));
30112b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    }
30212b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    if (cooked[2].equals("added")) {
30312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        notifyInterfaceAdded(cooked[3]);
30412b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        return true;
30512b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    } else if (cooked[2].equals("removed")) {
30612b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        notifyInterfaceRemoved(cooked[3]);
30712b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        return true;
30812b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    } else if (cooked[2].equals("changed") && cooked.length == 5) {
30912b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
31012b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        return true;
31112b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
31212b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
31312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        return true;
31412b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    }
315e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    throw new IllegalStateException(
316e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                            String.format("Invalid event from daemon (%s)", raw));
31712b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    // break;
31812b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            case NetdResponseCode.BandwidthControl:
31912b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    /*
32012b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     * Bandwidth control needs some attention
32112b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     * Format: "NNN limit alert <alertName> <ifaceName>"
32212b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                     */
32312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    if (cooked.length < 5 || !cooked[1].equals("limit")) {
32412b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        throw new IllegalStateException(
32512b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                                String.format("Invalid event from daemon (%s)", raw));
32612b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    }
32712b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    if (cooked[2].equals("alert")) {
32812b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        notifyLimitReached(cooked[3], cooked[4]);
32912b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                        return true;
33012b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    }
33112b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    throw new IllegalStateException(
33212b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                            String.format("Invalid event from daemon (%s)", raw));
33312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall                    // break;
33412b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall            default: break;
335e325392c257a5460de6327420c81729f4e687881Robert Greenwalt            }
336e325392c257a5460de6327420c81729f4e687881Robert Greenwalt            return false;
337873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
338873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
339873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
340ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
341873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
342873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    // INetworkManagementService members
343873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
344873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
345873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] listInterfaces() throws IllegalStateException {
346873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
347873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
348873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
349a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
350a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
351a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
352a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
353a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Cannot communicate with native daemon to list interfaces");
354a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
355ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
356ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
357ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
358a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        String rsp;
359a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
360a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
361a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
362a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
363a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Cannot communicate with native daemon to get interface config");
364a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
3658a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, String.format("rsp <%s>", rsp));
366ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
3672d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
368ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        StringTokenizer st = new StringTokenizer(rsp);
369ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
370a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        InterfaceConfiguration cfg;
371ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
372a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            try {
373a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                int code = Integer.parseInt(st.nextToken(" "));
374a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                if (code != NetdResponseCode.InterfaceGetCfgResult) {
375a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    throw new IllegalStateException(
376a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        String.format("Expected code %d, but got %d",
377a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                                NetdResponseCode.InterfaceGetCfgResult, code));
378a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                }
379a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            } catch (NumberFormatException nfe) {
380ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                throw new IllegalStateException(
381a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        String.format("Invalid response from daemon (%s)", rsp));
382ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            }
383ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
384a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            cfg = new InterfaceConfiguration();
385a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            cfg.hwAddr = st.nextToken(" ");
386ed1264093234b1f1354cd5f669eb82a50bb56869Robert Greenwalt            InetAddress addr = null;
3872d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt            int prefixLength = 0;
388a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            try {
389e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
390e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt            } catch (IllegalArgumentException iae) {
391e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                Slog.e(TAG, "Failed to parse ipaddr", iae);
392a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
393ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
394a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            try {
3952d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt                prefixLength = Integer.parseInt(st.nextToken(" "));
3962d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt            } catch (NumberFormatException nfe) {
3972d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt                Slog.e(TAG, "Failed to parse prefixLength", nfe);
398a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
39904808c294027f8bc318643a94c85a999257d7f52Robert Greenwalt
4002d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt            cfg.addr = new LinkAddress(addr, prefixLength);
401a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            cfg.interfaceFlags = st.nextToken("]").trim() +"]";
402a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NoSuchElementException nsee) {
403a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
404a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    String.format("Invalid response from daemon (%s)", rsp));
405ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
4068a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
407ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return cfg;
408ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
409ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
410ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public void setInterfaceConfig(
411ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            String iface, InterfaceConfiguration cfg) throws IllegalStateException {
412ed1264093234b1f1354cd5f669eb82a50bb56869Robert Greenwalt        LinkAddress linkAddr = cfg.addr;
4132d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt        if (linkAddr == null || linkAddr.getAddress() == null) {
4142d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt            throw new IllegalStateException("Null LinkAddress given");
415ed1264093234b1f1354cd5f669eb82a50bb56869Robert Greenwalt        }
4162d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt        String cmd = String.format("interface setcfg %s %s %d %s", iface,
4172d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt                linkAddr.getAddress().getHostAddress(),
4182d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt                linkAddr.getNetworkPrefixLength(),
4192d2afd13af94c2669eb464101dee3b17c8448110Robert Greenwalt                cfg.interfaceFlags);
420a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
421a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(cmd);
422a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
423a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
42481d5ad515a9379432b2907aa9bcc830303202c84Robert Greenwalt                    "Unable to communicate with native daemon to interface setcfg - " + e);
425a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
426873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
427873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
4287244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff    public void setInterfaceDown(String iface) throws IllegalStateException {
4297244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff        try {
4307244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            InterfaceConfiguration ifcg = getInterfaceConfig(iface);
4317244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
4327244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            setInterfaceConfig(iface, ifcg);
4337244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff        } catch (NativeDaemonConnectorException e) {
4347244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            throw new IllegalStateException(
4357244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff                    "Unable to communicate with native daemon for interface down - " + e);
4367244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff        }
4377244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff    }
4387244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff
4397244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff    public void setInterfaceUp(String iface) throws IllegalStateException {
4407244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff        try {
4417244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            InterfaceConfiguration ifcg = getInterfaceConfig(iface);
4427244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
4437244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            setInterfaceConfig(iface, ifcg);
4447244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff        } catch (NativeDaemonConnectorException e) {
4457244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff            throw new IllegalStateException(
4467244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff                    "Unable to communicate with native daemon for interface up - " + e);
4477244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff        }
4487244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff    }
4497244c977ecbc1f73e4cfd9d824fc2b68aa886139Irfan Sheriff
4507329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff    public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable)
4517329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff            throws IllegalStateException {
4527329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff        String cmd = String.format("interface ipv6privacyextensions %s %s", iface,
4537329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff                enable ? "enable" : "disable");
4547329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff        try {
4557329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff            mConnector.doCommand(cmd);
4567329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff        } catch (NativeDaemonConnectorException e) {
4577329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff            throw new IllegalStateException(
4587329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff                    "Unable to communicate with native daemon to set ipv6privacyextensions - " + e);
4597329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff        }
4607329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff    }
4617329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff
4627329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff
4637329361cdce711775542b112663bf71a6e0d5cefIrfan Sheriff
464f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff    /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
465f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff       IPv6 addresses on interface down, but we need to do full clean up here */
466f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff    public void clearInterfaceAddresses(String iface) throws IllegalStateException {
467f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff         String cmd = String.format("interface clearaddrs %s", iface);
468f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff        try {
469f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff            mConnector.doCommand(cmd);
470f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff        } catch (NativeDaemonConnectorException e) {
471f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff            throw new IllegalStateException(
472f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff                    "Unable to communicate with native daemon to interface clearallips - " + e);
473f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff        }
474f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff    }
475f5600618df153d9c51388562ebf3524e3bdc8b7dIrfan Sheriff
4767960d9f888e31602e17b8856c77a3826bf8c841erepo sync    public void enableIpv6(String iface) throws IllegalStateException {
4777960d9f888e31602e17b8856c77a3826bf8c841erepo sync        mContext.enforceCallingOrSelfPermission(
4787960d9f888e31602e17b8856c77a3826bf8c841erepo sync                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
4797960d9f888e31602e17b8856c77a3826bf8c841erepo sync        try {
4807960d9f888e31602e17b8856c77a3826bf8c841erepo sync            mConnector.doCommand(String.format("interface ipv6 %s enable", iface));
4817960d9f888e31602e17b8856c77a3826bf8c841erepo sync        } catch (NativeDaemonConnectorException e) {
4827960d9f888e31602e17b8856c77a3826bf8c841erepo sync            throw new IllegalStateException(
4837960d9f888e31602e17b8856c77a3826bf8c841erepo sync                    "Unable to communicate to native daemon for enabling ipv6");
4847960d9f888e31602e17b8856c77a3826bf8c841erepo sync        }
4857960d9f888e31602e17b8856c77a3826bf8c841erepo sync    }
4867960d9f888e31602e17b8856c77a3826bf8c841erepo sync
4877960d9f888e31602e17b8856c77a3826bf8c841erepo sync    public void disableIpv6(String iface) throws IllegalStateException {
4887960d9f888e31602e17b8856c77a3826bf8c841erepo sync        mContext.enforceCallingOrSelfPermission(
4897960d9f888e31602e17b8856c77a3826bf8c841erepo sync                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
4907960d9f888e31602e17b8856c77a3826bf8c841erepo sync        try {
4917960d9f888e31602e17b8856c77a3826bf8c841erepo sync            mConnector.doCommand(String.format("interface ipv6 %s disable", iface));
4927960d9f888e31602e17b8856c77a3826bf8c841erepo sync        } catch (NativeDaemonConnectorException e) {
4937960d9f888e31602e17b8856c77a3826bf8c841erepo sync            throw new IllegalStateException(
4947960d9f888e31602e17b8856c77a3826bf8c841erepo sync                    "Unable to communicate to native daemon for disabling ipv6");
4957960d9f888e31602e17b8856c77a3826bf8c841erepo sync        }
4967960d9f888e31602e17b8856c77a3826bf8c841erepo sync    }
4977960d9f888e31602e17b8856c77a3826bf8c841erepo sync
49859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    public void addRoute(String interfaceName, RouteInfo route) {
49959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        modifyRoute(interfaceName, ADD, route);
50059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    }
50159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
50259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    public void removeRoute(String interfaceName, RouteInfo route) {
50359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        modifyRoute(interfaceName, REMOVE, route);
50459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    }
50559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
50659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    private void modifyRoute(String interfaceName, int action, RouteInfo route) {
50759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        ArrayList<String> rsp;
50859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
50959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        StringBuilder cmd;
51059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
51159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        switch (action) {
51259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            case ADD:
51359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            {
51459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                cmd = new StringBuilder("interface route add " + interfaceName);
51559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                break;
51659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
51759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            case REMOVE:
51859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            {
51959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                cmd = new StringBuilder("interface route remove " + interfaceName);
52059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                break;
52159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
52259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            default:
52359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                throw new IllegalStateException("Unknown action type " + action);
52459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
52559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
52659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        // create triplet: dest-ip-addr prefixlength gateway-ip-addr
52759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        LinkAddress la = route.getDestination();
52859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        cmd.append(' ');
52959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        cmd.append(la.getAddress().getHostAddress());
53059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        cmd.append(' ');
53159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        cmd.append(la.getNetworkPrefixLength());
53259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        cmd.append(' ');
53359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        if (route.getGateway() == null) {
53459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            if (la.getAddress() instanceof Inet4Address) {
53559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                cmd.append("0.0.0.0");
53659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            } else {
53759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                cmd.append ("::0");
53859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
53959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        } else {
54059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            cmd.append(route.getGateway().getHostAddress());
54159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
54259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        try {
54359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            rsp = mConnector.doCommand(cmd.toString());
54459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        } catch (NativeDaemonConnectorException e) {
54559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            throw new IllegalStateException(
54659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    "Unable to communicate with native dameon to add routes - "
54759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    + e);
54859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
54959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
550c9acde9aa6cf21598640aeebb7d908f1926a48ddWink Saville        if (DBG) {
551c9acde9aa6cf21598640aeebb7d908f1926a48ddWink Saville            for (String line : rsp) {
552c9acde9aa6cf21598640aeebb7d908f1926a48ddWink Saville                Log.v(TAG, "add route response is " + line);
553c9acde9aa6cf21598640aeebb7d908f1926a48ddWink Saville            }
55459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
55559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    }
55659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
55759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    private ArrayList<String> readRouteList(String filename) {
55859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        FileInputStream fstream = null;
55959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        ArrayList<String> list = new ArrayList<String>();
56059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
56159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        try {
56259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            fstream = new FileInputStream(filename);
56359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            DataInputStream in = new DataInputStream(fstream);
56459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            BufferedReader br = new BufferedReader(new InputStreamReader(in));
56559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            String s;
56659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
56759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            // throw away the title line
56859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
56959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            while (((s = br.readLine()) != null) && (s.length() != 0)) {
57059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                list.add(s);
57159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
57259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        } catch (IOException ex) {
57359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            // return current list, possibly empty
57459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        } finally {
57559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            if (fstream != null) {
57659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                try {
57759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    fstream.close();
57859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                } catch (IOException ex) {}
57959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
58059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
58159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
58259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        return list;
58359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    }
58459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
58559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    public RouteInfo[] getRoutes(String interfaceName) {
58659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
58759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
58859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        // v4 routes listed as:
58959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
59059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        for (String s : readRouteList("/proc/net/route")) {
59159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            String[] fields = s.split("\t");
59259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
59359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            if (fields.length > 7) {
59459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                String iface = fields[0];
59559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
59659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                if (interfaceName.equals(iface)) {
59759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String dest = fields[1];
59859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String gate = fields[2];
59959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String flags = fields[3]; // future use?
60059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String mask = fields[7];
60159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    try {
60259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        // address stored as a hex string, ex: 0014A8C0
60359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        InetAddress destAddr =
60459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                                NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
60559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        int prefixLength =
60659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                                NetworkUtils.netmaskIntToPrefixLength(
60759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                                (int)Long.parseLong(mask, 16));
60859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
60959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
61059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        // address stored as a hex string, ex 0014A8C0
61159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        InetAddress gatewayAddr =
61259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                                NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
61359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
61459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
61559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        routes.add(route);
61659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    } catch (Exception e) {
61759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        Log.e(TAG, "Error parsing route " + s + " : " + e);
61859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        continue;
61959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    }
62059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                }
62159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
62259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
62359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
62459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        // v6 routes listed as:
62559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
62659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        for (String s : readRouteList("/proc/net/ipv6_route")) {
62759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            String[]fields = s.split("\\s+");
62859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            if (fields.length > 9) {
62959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                String iface = fields[9].trim();
63059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                if (interfaceName.equals(iface)) {
63159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String dest = fields[0];
63259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String prefix = fields[1];
63359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    String gate = fields[4];
63459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
63559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    try {
63659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        // prefix length stored as a hex string, ex 40
63759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        int prefixLength = Integer.parseInt(prefix, 16);
63859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
63959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        // address stored as a 32 char hex string
64059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        // ex fe800000000000000000000000000000
64159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
64259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
64359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
64459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
64559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
64659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        RouteInfo route = new RouteInfo(linkAddress, gateAddr);
64759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        routes.add(route);
64859b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    } catch (Exception e) {
64959b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        Log.e(TAG, "Error parsing route " + s + " : " + e);
65059b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                        continue;
65159b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                    }
65259b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt                }
65359b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt            }
65459b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        }
65559b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt        return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
65659b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt    }
65759b1a4ede7032c1b4d897e13dd4ede09b5e14743Robert Greenwalt
658873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void shutdown() {
659873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        if (mContext.checkCallingOrSelfPermission(
660873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.SHUTDOWN)
661873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                != PackageManager.PERMISSION_GRANTED) {
662873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throw new SecurityException("Requires SHUTDOWN permission");
663873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
664873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
6658a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, "Shutting down");
666873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
667873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
668873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public boolean getIpForwardingEnabled() throws IllegalStateException{
669873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
670873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
671873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
672a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        ArrayList<String> rsp;
673a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
674a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            rsp = mConnector.doCommand("ipfwd status");
675a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
676a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
677a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate with native daemon to ipfwd status");
678a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
679873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
680873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        for (String line : rsp) {
681a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
682a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
683a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response from native daemon: " + line);
684a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
685a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
686a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
687873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            int code = Integer.parseInt(tok[0]);
688873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            if (code == NetdResponseCode.IpFwdStatusResult) {
689873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                // 211 Forwarding <enabled/disabled>
690a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return "enabled".equals(tok[2]);
691873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            } else {
692873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
693873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
694873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
695873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        throw new IllegalStateException("Got an empty response");
696873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
697873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
698873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
699873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
700873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
701873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
702873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
703873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
704bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt    public void startTethering(String[] dhcpRange)
705873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat             throws IllegalStateException {
706873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
707873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
708bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt        // cmd is "tether start first_start first_stop second_start second_stop ..."
709bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt        // an odd number of addrs will fail
710bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt        String cmd = "tether start";
711bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt        for (String d : dhcpRange) {
712bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt            cmd += " " + d;
713bfb7bfa53847832db2a3eb05e5eff7cb974c3c7aRobert Greenwalt        }
714a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
715a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
716a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(cmd);
717a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
718a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Unable to communicate to native daemon");
719a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
720873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
721873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
722873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void stopTethering() throws IllegalStateException {
723873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
724873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
725a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
726a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand("tether stop");
727a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
728a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
729a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
730873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
731873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
732873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public boolean isTetheringStarted() throws IllegalStateException {
733873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
734873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
735873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
736a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        ArrayList<String> rsp;
737a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
738a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            rsp = mConnector.doCommand("tether status");
739a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
740a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
741a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon to get tether status");
742a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
743873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
744873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        for (String line : rsp) {
745a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
746a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
747a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                throw new IllegalStateException("Malformed response for tether status: " + line);
748a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
749873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            int code = Integer.parseInt(tok[0]);
750873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            if (code == NetdResponseCode.TetherStatusResult) {
751873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                // XXX: Tethering services <started/stopped> <TBD>...
752a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return "started".equals(tok[2]);
753873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            } else {
754873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
755873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
756873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
757873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        throw new IllegalStateException("Got an empty response");
758873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
759873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
760873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void tetherInterface(String iface) throws IllegalStateException {
761873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
762873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
763a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
764a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand("tether interface add " + iface);
765a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
766a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
767a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for adding tether interface");
768a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
769873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
770873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
771873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void untetherInterface(String iface) {
772873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
773873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
774a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
775a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand("tether interface remove " + iface);
776a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
777a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
778a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for removing tether interface");
779a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
780873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
781873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
782873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] listTetheredInterfaces() throws IllegalStateException {
783873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
784873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
785a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
786a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return mConnector.doListCommand(
787a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "tether interface list", NetdResponseCode.TetherInterfaceListResult);
788a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
789a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
790a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for listing tether interfaces");
791a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
792873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
793873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
794873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void setDnsForwarders(String[] dns) throws IllegalStateException {
795873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
796873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
797873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        try {
798d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            String cmd = "tether dns set";
799873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            for (String s : dns) {
800e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
801873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
802a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            try {
803a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                mConnector.doCommand(cmd);
804a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            } catch (NativeDaemonConnectorException e) {
805a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                throw new IllegalStateException(
806a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        "Unable to communicate to native daemon for setting tether dns");
807a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
808e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt        } catch (IllegalArgumentException e) {
809873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throw new IllegalStateException("Error resolving dns name", e);
810873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
811873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
812873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
813873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] getDnsForwarders() throws IllegalStateException {
814873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
815873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
816a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
817a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return mConnector.doListCommand(
818a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
819a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
820a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
821a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for listing tether dns");
822a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
823873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
824873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
825873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void enableNat(String internalInterface, String externalInterface)
826873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throws IllegalStateException {
827873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
828873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
829a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
830a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(
831a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    String.format("nat enable %s %s", internalInterface, externalInterface));
832a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
833a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
834a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for enabling NAT interface");
835a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
836873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
837873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
838873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void disableNat(String internalInterface, String externalInterface)
839873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throws IllegalStateException {
840873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
841873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
842a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
843a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(
844a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    String.format("nat disable %s %s", internalInterface, externalInterface));
845a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
846a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
847a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for disabling NAT interface");
848a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
849873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
85072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
85172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    public String[] listTtys() throws IllegalStateException {
85272759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mContext.enforceCallingOrSelfPermission(
85372759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
854a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
855a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
856a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
857a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException(
858a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "Unable to communicate to native daemon for listing TTYs");
859a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
86072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
86172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
862d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
863d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            String dns2Addr) throws IllegalStateException {
86472759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        try {
86572759df749bb8557269db86c2e3b2a8a0343cc26San Mehat            mContext.enforceCallingOrSelfPermission(
86672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                    android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
867d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
868e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
869e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
870e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
871e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
872e590373ea71251cfffc8f22f011e2e6335dce716Robert Greenwalt        } catch (IllegalArgumentException e) {
87372759df749bb8557269db86c2e3b2a8a0343cc26San Mehat            throw new IllegalStateException("Error resolving addr", e);
874a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
875a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
87672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        }
87772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
87872759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
87972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    public void detachPppd(String tty) throws IllegalStateException {
88072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mContext.enforceCallingOrSelfPermission(
88172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
882a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
883a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(String.format("pppd detach %s", tty));
884a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
885a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
886a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
88772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
888ce1200d42c46ae5d3ec637587b07dfdc02ad21c0Robert Greenwalt
889c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff    public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
8905321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff             throws IllegalStateException {
8915321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
8925321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
8935321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
894c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff                android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
895a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
896cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff            wifiFirmwareReload(wlanIface, "AP");
897a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(String.format("softap start " + wlanIface));
898a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (wifiConfig == null) {
899a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
900a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            } else {
901a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                /**
902a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
903a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv1 - wlan interface
904a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv2 - softap interface
905a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv3 - SSID
906a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv4 - Security
907a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv5 - Key
908a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv6 - Channel
909a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv7 - Preamble
910a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 * argv8 - Max SCB
911a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                 */
912ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                 String str = String.format("softap set " + wlanIface + " " + softapIface +
913ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                                       " %s %s %s", convertQuotedString(wifiConfig.SSID),
914ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                                       getSecurityType(wifiConfig),
915ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                                       convertQuotedString(wifiConfig.preSharedKey));
916a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                mConnector.doCommand(str);
917a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
918a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(String.format("softap startap"));
919a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
920a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Error communicating to native daemon to start softap", e);
921a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
9225321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff    }
9235321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff
924a6e559edb73886c626e0e5a95085d0ead767ceb7Irfan Sheriff    private String convertQuotedString(String s) {
9257baec0fe4ef66ac308ebc132d6c08865db653b30Irfan Sheriff        if (s == null) {
9267baec0fe4ef66ac308ebc132d6c08865db653b30Irfan Sheriff            return s;
9277baec0fe4ef66ac308ebc132d6c08865db653b30Irfan Sheriff        }
9287baec0fe4ef66ac308ebc132d6c08865db653b30Irfan Sheriff        /* Replace \ with \\, then " with \" and add quotes at end */
9297baec0fe4ef66ac308ebc132d6c08865db653b30Irfan Sheriff        return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
930a6e559edb73886c626e0e5a95085d0ead767ceb7Irfan Sheriff    }
931a6e559edb73886c626e0e5a95085d0ead767ceb7Irfan Sheriff
932ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff    private String getSecurityType(WifiConfiguration wifiConfig) {
933ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff        switch (wifiConfig.getAuthType()) {
934ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff            case KeyMgmt.WPA_PSK:
935ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                return "wpa-psk";
936ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff            case KeyMgmt.WPA2_PSK:
937ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                return "wpa2-psk";
938ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff            default:
939ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                return "open";
940ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff        }
941ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff    }
942ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff
943cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff    /* @param mode can be "AP", "STA" or "P2P" */
944cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff    public void wifiFirmwareReload(String wlanIface, String mode) throws IllegalStateException {
945cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
946cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
947cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
948cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff                android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
949cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff
950cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff        try {
951cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff            mConnector.doCommand(String.format("softap fwreload " + wlanIface + " " + mode));
952cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff        } catch (NativeDaemonConnectorException e) {
953cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff            throw new IllegalStateException("Error communicating to native daemon ", e);
954cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff        }
955cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff    }
956cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff
95723eb297c771bd996fe8559178feb1a07be43ad72Irfan Sheriff    public void stopAccessPoint(String wlanIface) throws IllegalStateException {
9585321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
9595321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
9605321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
961c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff                android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
962a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
963a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand("softap stopap");
96423eb297c771bd996fe8559178feb1a07be43ad72Irfan Sheriff            mConnector.doCommand("softap stop " + wlanIface);
965cb30b22ff507a5a9a5d9c584f8b082f5e96c4d02Irfan Sheriff            wifiFirmwareReload(wlanIface, "STA");
966a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
967a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
968a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    e);
969a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
9705321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff    }
9715321aef4a22daef6ed01ed48d936cdd82f2e38b7Irfan Sheriff
972c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff    public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
973c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff            throws IllegalStateException {
974c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
975c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
976c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff        mContext.enforceCallingOrSelfPermission(
977c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff            android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
978a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
979a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (wifiConfig == null) {
980a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
981a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            } else {
982a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                String str = String.format("softap set " + wlanIface + " " + softapIface
983a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        + " %s %s %s", convertQuotedString(wifiConfig.SSID),
984ec8d23af7372204f068aebaa1bfae87dc9260e23Irfan Sheriff                        getSecurityType(wifiConfig),
985a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        convertQuotedString(wifiConfig.preSharedKey));
986a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                mConnector.doCommand(str);
987a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
988a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
989a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            throw new IllegalStateException("Error communicating to native daemon to set soft AP",
990a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    e);
991c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff        }
992c2f54c267b896cd1799d82be81e904a2b56c2f26Irfan Sheriff    }
99391cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
99491cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    private long getInterfaceCounter(String iface, boolean rx) {
99591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        mContext.enforceCallingOrSelfPermission(
99691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
99791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        try {
998a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String rsp;
999a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            try {
1000a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                rsp = mConnector.doCommand(
1001a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
1002a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            } catch (NativeDaemonConnectorException e1) {
1003a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Error communicating with native daemon", e1);
1004a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return -1;
1005a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
1006a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
1007a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = rsp.split(" ");
1008a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 2) {
1009a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, String.format("Malformed response for reading %s interface",
1010a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        (rx ? "rx" : "tx")));
1011a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return -1;
1012a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
1013a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
101491cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            int code;
101591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            try {
101691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                code = Integer.parseInt(tok[0]);
101791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            } catch (NumberFormatException nfe) {
101891cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
101991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                return -1;
102091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            }
102191cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
102291cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                    !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
102391cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
102491cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                return -1;
102591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            }
102691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            return Long.parseLong(tok[1]);
102791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        } catch (Exception e) {
102891cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            Slog.e(TAG, String.format(
102991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                    "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
103091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        }
103191cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        return -1;
103291cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
103391cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
1034eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    @Override
10359a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public NetworkStats getNetworkStatsSummary() {
10369a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        mContext.enforceCallingOrSelfPermission(
10379a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
10381059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return mStatsFactory.readNetworkStatsSummary();
103991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
104091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
1041eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    @Override
10429a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public NetworkStats getNetworkStatsDetail() {
10439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        mContext.enforceCallingOrSelfPermission(
10449a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
10451059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return mStatsFactory.readNetworkStatsDetail(UID_ALL);
104691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
104791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
1048eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    @Override
104941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public void setInterfaceQuota(String iface, long quotaBytes) {
1050b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1051b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1052350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // silently discard when control disabled
1053350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // TODO: eventually migrate to be always enabled
1054350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (!mBandwidthControlEnabled) return;
1055350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
105641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        synchronized (mQuotaLock) {
105741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            if (mActiveQuotaIfaces.contains(iface)) {
105841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                throw new IllegalStateException("iface " + iface + " already has quota");
1059b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
1060b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1061b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            final StringBuilder command = new StringBuilder();
106241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
1063b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1064b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            try {
106541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                // TODO: support quota shared across interfaces
1066b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                mConnector.doCommand(command.toString());
106741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mActiveQuotaIfaces.add(iface);
1068b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            } catch (NativeDaemonConnectorException e) {
1069b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                throw new IllegalStateException("Error communicating to native daemon", e);
1070b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
107150fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma        }
107250fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma    }
107350fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma
107450fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma    @Override
1075b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    public void removeInterfaceQuota(String iface) {
1076b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1077b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1078350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // silently discard when control disabled
1079350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // TODO: eventually migrate to be always enabled
1080350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (!mBandwidthControlEnabled) return;
1081350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
108241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        synchronized (mQuotaLock) {
108341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            if (!mActiveQuotaIfaces.contains(iface)) {
1084b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                // TODO: eventually consider throwing
1085b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                return;
1086b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
1087b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1088b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            final StringBuilder command = new StringBuilder();
1089b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            command.append("bandwidth removeiquota ").append(iface);
1090b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1091b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            try {
109241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                // TODO: support quota shared across interfaces
1093b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                mConnector.doCommand(command.toString());
109441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mActiveQuotaIfaces.remove(iface);
109541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mActiveAlertIfaces.remove(iface);
1096b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            } catch (NativeDaemonConnectorException e) {
1097b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                throw new IllegalStateException("Error communicating to native daemon", e);
1098b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
1099b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1100b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    }
1101b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1102b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    @Override
110341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public void setInterfaceAlert(String iface, long alertBytes) {
110441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
110541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
110641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // silently discard when control disabled
110741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // TODO: eventually migrate to be always enabled
110841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        if (!mBandwidthControlEnabled) return;
110941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
111041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // quick sanity check
111141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        if (!mActiveQuotaIfaces.contains(iface)) {
111241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            throw new IllegalStateException("setting alert requires existing quota on iface");
111341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
111441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
111541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        synchronized (mQuotaLock) {
111641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            if (mActiveAlertIfaces.contains(iface)) {
111741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                throw new IllegalStateException("iface " + iface + " already has alert");
111841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
111941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
112041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            final StringBuilder command = new StringBuilder();
112141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
112241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    alertBytes);
112341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
112441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            try {
112541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                // TODO: support alert shared across interfaces
112641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mConnector.doCommand(command.toString());
112741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mActiveAlertIfaces.add(iface);
112841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            } catch (NativeDaemonConnectorException e) {
112941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                throw new IllegalStateException("Error communicating to native daemon", e);
113041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
113141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
113241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
113341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
113441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    @Override
113541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public void removeInterfaceAlert(String iface) {
113641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
113741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
113841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // silently discard when control disabled
113941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // TODO: eventually migrate to be always enabled
114041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        if (!mBandwidthControlEnabled) return;
114141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
114241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        synchronized (mQuotaLock) {
114341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            if (!mActiveAlertIfaces.contains(iface)) {
114441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                // TODO: eventually consider throwing
114541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                return;
114641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
114741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
114841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            final StringBuilder command = new StringBuilder();
114941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            command.append("bandwidth removeinterfacealert ").append(iface);
115041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
115141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            try {
115241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                // TODO: support alert shared across interfaces
115341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mConnector.doCommand(command.toString());
115441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mActiveAlertIfaces.remove(iface);
115541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            } catch (NativeDaemonConnectorException e) {
115641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                throw new IllegalStateException("Error communicating to native daemon", e);
115741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
115841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
115941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
116041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
116141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    @Override
116241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public void setGlobalAlert(long alertBytes) {
116341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
116441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
116541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // silently discard when control disabled
116641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        // TODO: eventually migrate to be always enabled
116741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        if (!mBandwidthControlEnabled) return;
116841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
116941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        final StringBuilder command = new StringBuilder();
117041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        command.append("bandwidth setglobalalert ").append(alertBytes);
117141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
117241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        try {
117341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mConnector.doCommand(command.toString());
117441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        } catch (NativeDaemonConnectorException e) {
117541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            throw new IllegalStateException("Error communicating to native daemon", e);
117641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
117741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
117841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
117941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    @Override
1180b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1181b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1182b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1183350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // silently discard when control disabled
1184350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        // TODO: eventually migrate to be always enabled
1185350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (!mBandwidthControlEnabled) return;
1186350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
1187b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        synchronized (mUidRejectOnQuota) {
1188b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1189b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1190b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                // TODO: eventually consider throwing
1191b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                return;
1192b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
1193b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1194b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            final StringBuilder command = new StringBuilder();
1195b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            command.append("bandwidth");
1196b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            if (rejectOnQuotaInterfaces) {
1197b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                command.append(" addnaughtyapps");
1198b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            } else {
1199b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                command.append(" removenaughtyapps");
1200b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
1201b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            command.append(" ").append(uid);
1202b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1203b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            try {
1204b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                mConnector.doCommand(command.toString());
1205b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                if (rejectOnQuotaInterfaces) {
1206b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                    mUidRejectOnQuota.put(uid, true);
1207b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                } else {
1208b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                    mUidRejectOnQuota.delete(uid);
1209b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                }
1210b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            } catch (NativeDaemonConnectorException e) {
1211b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                throw new IllegalStateException("Error communicating to native daemon", e);
1212b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            }
121350fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma        }
121450fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma    }
121550fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma
121663d27a9233fed934340231f438493746084a681dJeff Sharkey    @Override
121763d27a9233fed934340231f438493746084a681dJeff Sharkey    public boolean isBandwidthControlEnabled() {
121863d27a9233fed934340231f438493746084a681dJeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
121963d27a9233fed934340231f438493746084a681dJeff Sharkey        return mBandwidthControlEnabled;
122063d27a9233fed934340231f438493746084a681dJeff Sharkey    }
122163d27a9233fed934340231f438493746084a681dJeff Sharkey
122263d27a9233fed934340231f438493746084a681dJeff Sharkey    @Override
1223eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    public NetworkStats getNetworkStatsUidDetail(int uid) {
1224eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        if (Binder.getCallingUid() != uid) {
1225eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            mContext.enforceCallingOrSelfPermission(
1226eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                    android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1227eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        }
12281059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return mStatsFactory.readNetworkStatsDetail(uid);
1229eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
1230eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
1231cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey    @Override
1232cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey    public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
1233cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        mContext.enforceCallingOrSelfPermission(
1234cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1235cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1236cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        if (ifacePairs.length % 2 != 0) {
1237cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            throw new IllegalArgumentException(
1238cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey                    "unexpected ifacePairs; length=" + ifacePairs.length);
1239cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1240cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1241cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1242cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        for (int i = 0; i < ifacePairs.length; i += 2) {
1243cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            final String ifaceIn = ifacePairs[i];
1244cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            final String ifaceOut = ifacePairs[i + 1];
1245cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            if (ifaceIn != null && ifaceOut != null) {
1246cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey                stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
1247cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            }
1248cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1249cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        return stats;
1250cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey    }
1251cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1252cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey    private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
1253cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        final StringBuilder command = new StringBuilder();
1254cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        command.append("bandwidth gettetherstats ").append(ifaceIn).append(" ").append(ifaceOut);
1255cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1256cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        final String rsp;
1257cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        try {
1258cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            rsp = mConnector.doCommand(command.toString()).get(0);
1259cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        } catch (NativeDaemonConnectorException e) {
1260cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            throw new IllegalStateException("Error communicating to native daemon", e);
1261cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1262cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1263cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        final String[] tok = rsp.split(" ");
1264cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        /* Expecting: "code ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets" */
1265cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        if (tok.length != 7) {
1266cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            throw new IllegalStateException("Native daemon returned unexpected result: " + rsp);
1267cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1268cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1269cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        final int code;
1270cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        try {
1271cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            code = Integer.parseInt(tok[0]);
1272cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        } catch (NumberFormatException e) {
1273cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            throw new IllegalStateException(
1274cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey                    "Failed to parse native daemon return code for " + ifaceIn + " " + ifaceOut);
1275cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1276cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        if (code != NetdResponseCode.TetheringStatsResult) {
1277cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            throw new IllegalStateException(
1278cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey                    "Unexpected return code from native daemon for " + ifaceIn + " " + ifaceOut);
1279cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1280cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1281cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        try {
1282cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            final NetworkStats.Entry entry = new NetworkStats.Entry();
1283cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.iface = ifaceIn;
1284905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.uid = UID_TETHERING;
1285cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.set = SET_DEFAULT;
1286cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.tag = TAG_NONE;
1287cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.rxBytes = Long.parseLong(tok[3]);
1288cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.rxPackets = Long.parseLong(tok[4]);
1289cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.txBytes = Long.parseLong(tok[5]);
1290cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            entry.txPackets = Long.parseLong(tok[6]);
1291cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            return entry;
1292cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        } catch (NumberFormatException e) {
1293cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey            throw new IllegalStateException(
1294cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey                    "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
1295cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey        }
1296cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey    }
1297cdd02c5d76d3dd4e21b5bb922d7fcfb86efec85fJeff Sharkey
1298f0db6e1853e929ae3b65501c31ee57c4dfbc767cSan Mehat    public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
129991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        mContext.enforceCallingOrSelfPermission(
130091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1301a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
1302a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            mConnector.doCommand(String.format(
1303a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                    "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1304a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException e) {
1305a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1306a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
130791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
130891cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
130991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    private int getInterfaceThrottle(String iface, boolean rx) {
131091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        mContext.enforceCallingOrSelfPermission(
131191cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
131291cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        try {
1313a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String rsp;
1314a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            try {
1315a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                rsp = mConnector.doCommand(
1316a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                        String.format("interface getthrottle %s %s", iface,
1317a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                                (rx ? "rx" : "tx"))).get(0);
1318a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            } catch (NativeDaemonConnectorException e) {
1319a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1320a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return -1;
1321a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
1322a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
1323a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = rsp.split(" ");
1324a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 2) {
1325a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to getthrottle command");
1326a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return -1;
1327a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
1328a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
132991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            int code;
133091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            try {
133191cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                code = Integer.parseInt(tok[0]);
133291cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            } catch (NumberFormatException nfe) {
133391cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
133491cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                return -1;
133591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            }
133691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
133791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                    !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
133891cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
133991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                return -1;
134091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            }
134191cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            return Integer.parseInt(tok[1]);
134291cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        } catch (Exception e) {
134391cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat            Slog.e(TAG, String.format(
134491cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat                    "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
134591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        }
134691cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        return -1;
134791cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
134891cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
134991cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    public int getInterfaceRxThrottle(String iface) {
135091cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        return getInterfaceThrottle(iface, true);
135191cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
135291cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat
135391cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    public int getInterfaceTxThrottle(String iface) {
135491cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat        return getInterfaceThrottle(iface, false);
135591cac64cd010e6b4006fdd14b39dbc75778f20cbSan Mehat    }
13569a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
13577475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
13587475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        mContext.enforceCallingOrSelfPermission(
13597475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
13607475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        try {
13617475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            String cmd = "resolver setdefaultif " + iface;
13627475c0cea622f126af966c3b5b9741f547e83450Mattias Falk
13637475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            mConnector.doCommand(cmd);
13647475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        } catch (NativeDaemonConnectorException e) {
13657475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            throw new IllegalStateException(
13667475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                    "Error communicating with native daemon to set default interface", e);
13677475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        }
13687475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    }
13697475c0cea622f126af966c3b5b9741f547e83450Mattias Falk
13707475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    public void setDnsServersForInterface(String iface, String[] servers)
13717475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            throws IllegalStateException {
13727475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
13737475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                "NetworkManagementService");
13747475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        try {
13757475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            String cmd = "resolver setifdns " + iface;
13767475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            for (String s : servers) {
1377572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt                InetAddress a = NetworkUtils.numericToInetAddress(s);
1378572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt                if (a.isAnyLocalAddress() == false) {
1379572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt                    cmd += " " + a.getHostAddress();
13807475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                }
13817475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            }
13827475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            mConnector.doCommand(cmd);
1383572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt        } catch (IllegalArgumentException e) {
1384572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt            throw new IllegalStateException("Error setting dnsn for interface", e);
13857475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        } catch (NativeDaemonConnectorException e) {
13867475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            throw new IllegalStateException(
1387572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt                    "Error communicating with native daemon to set dns for interface", e);
13887475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        }
13897475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    }
13907475c0cea622f126af966c3b5b9741f547e83450Mattias Falk
13917475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    public void flushDefaultDnsCache() throws IllegalStateException {
13927475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        mContext.enforceCallingOrSelfPermission(
13937475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
13947475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        try {
13957475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            String cmd = "resolver flushdefaultif";
13967475c0cea622f126af966c3b5b9741f547e83450Mattias Falk
13977475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            mConnector.doCommand(cmd);
13987475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        } catch (NativeDaemonConnectorException e) {
13997475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            throw new IllegalStateException(
14007475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                    "Error communicating with native deamon to flush default interface", e);
14017475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        }
14027475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    }
14037475c0cea622f126af966c3b5b9741f547e83450Mattias Falk
14047475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
14057475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        mContext.enforceCallingOrSelfPermission(
14067475c0cea622f126af966c3b5b9741f547e83450Mattias Falk                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
14077475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        try {
14087475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            String cmd = "resolver flushif " + iface;
14097475c0cea622f126af966c3b5b9741f547e83450Mattias Falk
14107475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            mConnector.doCommand(cmd);
14117475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        } catch (NativeDaemonConnectorException e) {
14127475c0cea622f126af966c3b5b9741f547e83450Mattias Falk            throw new IllegalStateException(
1413572b7048a6ed6cf6c5f6bc6c9d542dc377d601ffRobert Greenwalt                    "Error communicating with native daemon to flush interface " + iface, e);
14147475c0cea622f126af966c3b5b9741f547e83450Mattias Falk        }
14157475c0cea622f126af966c3b5b9741f547e83450Mattias Falk    }
1416fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey
1417fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    /** {@inheritDoc} */
1418fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    public void monitor() {
1419fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        if (mConnector != null) {
1420fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey            mConnector.monitor();
1421fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        }
1422fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    }
142347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey
142447eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey    @Override
142547eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
142647eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
142747eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey
142847eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey        pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
142947eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey
143047eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey        synchronized (mQuotaLock) {
143147eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            pw.print("Active quota ifaces: "); pw.println(mActiveQuotaIfaces.toString());
143247eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            pw.print("Active alert ifaces: "); pw.println(mActiveAlertIfaces.toString());
143347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey        }
143447eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey
143547eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey        synchronized (mUidRejectOnQuota) {
143647eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            pw.print("UID reject on quota ifaces: [");
143747eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            final int size = mUidRejectOnQuota.size();
143847eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            for (int i = 0; i < size; i++) {
143947eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                pw.print(mUidRejectOnQuota.keyAt(i));
144047eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                if (i < size - 1) pw.print(",");
144147eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            }
144247eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            pw.println("]");
144347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey        }
144447eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey    }
1445873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat}
1446