NetworkManagementService.java revision a6e559edb73886c626e0e5a95085d0ead767ceb7
146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)/*
246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * Copyright (C) 2007 The Android Open Source Project
346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) *
446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License");
546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * you may not use this file except in compliance with the License.
646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * You may obtain a copy of the License at
746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) *
846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) *      http://www.apache.org/licenses/LICENSE-2.0
946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) *
1046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software
1146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS,
1246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * See the License for the specific language governing permissions and
1446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * limitations under the License.
1546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) */
1646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
1746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)package com.android.server;
1846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
1946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.app.PendingIntent;
2046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.BroadcastReceiver;
2146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.Context;
2246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.Intent;
2346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.IntentFilter;
2446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.res.Resources;
2546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.pm.PackageManager;
2646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.net.Uri;
2746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.net.InterfaceConfiguration;
2846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.net.INetworkManagementEventObserver;
2946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.net.wifi.WifiConfiguration;
30e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixonimport android.net.wifi.WifiConfiguration.KeyMgmt;
31a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixonimport android.os.INetworkManagementService;
3246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.os.Handler;
3346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.os.SystemProperties;
3446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.text.TextUtils;
353411fdf2737f3f0dd0c1fa20045356cf89f34eddBo Liuimport android.util.Log;
3646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.util.Slog;
3746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import java.util.ArrayList;
3846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import java.util.StringTokenizer;
3946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.provider.Settings;
4046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.content.ContentResolver;
4146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import android.database.ContentObserver;
426d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch
437db34d3dcaac936566f912e1b0b21f3f103029ffJonathan Dixonimport java.io.File;
4446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import java.io.FileReader;
4546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import java.lang.IllegalStateException;
4646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
4746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import java.net.InetAddress;
4846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)import java.net.UnknownHostException;
4946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
5046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)/**
5146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles) * @hide
52aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen */
5346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)class NetworkManagementService extends INetworkManagementService.Stub {
5446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
5546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private static final String TAG = "NetworkManagmentService";
5646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
5746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    class NetdResponseCode {
5846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int InterfaceListResult       = 110;
59ea844f60b1b559788566fe6e004b1eeca53a8039Jonathan Dixon        public static final int TetherInterfaceListResult = 111;
6046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int TetherDnsFwdTgtListResult = 112;
6146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int TtyListResult             = 113;
6246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
6346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int TetherStatusResult        = 210;
6446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int IpFwdStatusResult         = 211;
651cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon        public static final int InterfaceGetCfgResult     = 213;
661cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon        public static final int SoftapStatusResult        = 214;
671cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon        public static final int UsbRNDISStatusResult      = 215;
681cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon        public static final int InterfaceRxCounterResult  = 216;
6946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int InterfaceTxCounterResult  = 217;
7046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int InterfaceRxThrottleResult = 218;
7146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public static final int InterfaceTxThrottleResult = 219;
72e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixon
73e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixon        public static final int InterfaceChange           = 600;
74e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixon    }
7546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
7646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    /**
7746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     * Binder context for this service
7846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     */
7946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private Context mContext;
8046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
8146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    /**
8246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     * connector object for communicating with netd
8346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     */
8446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private NativeDaemonConnector mConnector;
853949435b480cb71106f65b237025da359cf8a8caBen Murdoch
8646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private ArrayList<INetworkManagementEventObserver> mObservers;
87a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixon
88a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixon    /**
8946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     * Constructs a new NetworkManagementService instance
90aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen     *
91aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen     * @param context  Binder context for this service
92c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu     */
93c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu    public NetworkManagementService(Context context) {
94aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen        mContext = context;
95aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen
9646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mObservers = new ArrayList<INetworkManagementEventObserver>();
9746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
98c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
99aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen            return;
10046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
10146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
1021ee9dd0420198429115c3fe8cf0b0502fab9cf62Ben Murdoch        mConnector = new NativeDaemonConnector(
1031ee9dd0420198429115c3fe8cf0b0502fab9cf62Ben Murdoch                new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
1041ee9dd0420198429115c3fe8cf0b0502fab9cf62Ben Murdoch        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
1051ee9dd0420198429115c3fe8cf0b0502fab9cf62Ben Murdoch        thread.start();
10646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
10746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
10846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void registerObserver(INetworkManagementEventObserver obs) {
10946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        Slog.d(TAG, "Registering observer");
11046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mObservers.add(obs);
11146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
11246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
11346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void unregisterObserver(INetworkManagementEventObserver obs) {
1145a25477f4323996be9d5cc32935066c73b47061bBen Murdoch        Slog.d(TAG, "Unregistering observer");
1155a25477f4323996be9d5cc32935066c73b47061bBen Murdoch        mObservers.remove(mObservers.indexOf(obs));
1165a25477f4323996be9d5cc32935066c73b47061bBen Murdoch    }
1175a25477f4323996be9d5cc32935066c73b47061bBen Murdoch
11846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    /**
11946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     * Notify our observers of an interface link status change
12046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     */
12146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
12246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        for (INetworkManagementEventObserver obs : mObservers) {
123aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen            try {
124aa8b39f3e3f208586f3750d7278f1239a09ebd32Kristian Monsen                obs.interfaceLinkStatusChanged(iface, link);
12546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } catch (Exception ex) {
12646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                Slog.w(TAG, "Observer notifier failed", ex);
12746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
12846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
12946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
13046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
13146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    /**
13246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     * Notify our observers of an interface addition.
13346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     */
13446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private void notifyInterfaceAdded(String iface) {
13546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        for (INetworkManagementEventObserver obs : mObservers) {
13646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            try {
13746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                obs.interfaceAdded(iface);
13846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } catch (Exception ex) {
13946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                Slog.w(TAG, "Observer notifier failed", ex);
14046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
14146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
14246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
14346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
14446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    /**
14546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     * Notify our observers of an interface removal.
14646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)     */
14746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private void notifyInterfaceRemoved(String iface) {
14846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        for (INetworkManagementEventObserver obs : mObservers) {
14946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            try {
15046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                obs.interfaceRemoved(iface);
15146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } catch (Exception ex) {
15246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                Slog.w(TAG, "Observer notifier failed", ex);
15346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
15446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
15546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
15646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
15746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
15846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    //
15946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    // Netd Callback handling
16046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    //
16146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
16246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
16346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public void onDaemonConnected() {
16446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            new Thread() {
16546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                public void run() {
16646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                }
167adc6c4d74c77a617100bdfeb174ab0c314b24ea8Selim Gurun            }.start();
16846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
16946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        public boolean onEvent(int code, String raw, String[] cooked) {
17046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            if (code == NetdResponseCode.InterfaceChange) {
17146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                /*
17246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                 * a network interface change occured
17346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                 * Format: "NNN Iface added <name>"
17446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                 *         "NNN Iface removed <name>"
17546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                 *         "NNN Iface changed <name> <up/down>"
17646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                 */
17746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                if (cooked.length < 4 || !cooked[1].equals("Iface")) {
17846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    throw new IllegalStateException(
17946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                            String.format("Invalid event from daemon (%s)", raw));
18046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                }
18146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                if (cooked[2].equals("added")) {
18246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    notifyInterfaceAdded(cooked[3]);
1833949435b480cb71106f65b237025da359cf8a8caBen Murdoch                    return true;
184a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixon                } else if (cooked[2].equals("removed")) {
185a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixon                    notifyInterfaceRemoved(cooked[3]);
186a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixon                    return true;
187a2b0d0b4d6d1ff22fbb1329e358e1cc0a112aab3Jonathan Dixon                } else if (cooked[2].equals("changed") && cooked.length == 5) {
18846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
18946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    return true;
19046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                }
19146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                throw new IllegalStateException(
19246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                        String.format("Invalid event from daemon (%s)", raw));
19346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
19446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            return false;
19546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
19646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
197a08e8aada16dc4dbfb8745532169fb4a8347541dBo Liu
198a08e8aada16dc4dbfb8745532169fb4a8347541dBo Liu    private static int stringToIpAddr(String addrString) throws UnknownHostException {
199a08e8aada16dc4dbfb8745532169fb4a8347541dBo Liu        try {
20046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String[] parts = addrString.split("\\.");
20146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            if (parts.length != 4) {
20246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                throw new UnknownHostException(addrString);
20346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
2049405536501747e2d7b4fc46a33e5f0a1e7fd47acJonathan Dixon
20546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int a = Integer.parseInt(parts[0])      ;
20646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int b = Integer.parseInt(parts[1]) <<  8;
20746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int c = Integer.parseInt(parts[2]) << 16;
20846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int d = Integer.parseInt(parts[3]) << 24;
20946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
2109405536501747e2d7b4fc46a33e5f0a1e7fd47acJonathan Dixon            return a | b | c | d;
21146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } catch (NumberFormatException ex) {
21246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            throw new UnknownHostException(addrString);
21346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
21446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
21546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
216a08e8aada16dc4dbfb8745532169fb4a8347541dBo Liu    public static String intToIpString(int i) {
217a08e8aada16dc4dbfb8745532169fb4a8347541dBo Liu        return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >>  8 ) & 0xFF) + "." +
218a08e8aada16dc4dbfb8745532169fb4a8347541dBo Liu               (i & 0xFF);
21946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
22046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
22146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    //
22246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    // INetworkManagementService members
22346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    //
22446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
22546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public String[] listInterfaces() throws IllegalStateException {
22646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
22746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
22846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
22946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
23046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
23146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
23246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
23346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        String rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
23446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        Slog.d(TAG, String.format("rsp <%s>", rsp));
23546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
23646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
23746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        StringTokenizer st = new StringTokenizer(rsp);
23846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
23946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
24046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int code = Integer.parseInt(st.nextToken(" "));
24146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            if (code != NetdResponseCode.InterfaceGetCfgResult) {
24246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                throw new IllegalStateException(
24346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    String.format("Expected code %d, but got %d",
24446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                            NetdResponseCode.InterfaceGetCfgResult, code));
24546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
24646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } catch (NumberFormatException nfe) {
24746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            throw new IllegalStateException(
24846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    String.format("Invalid response from daemon (%s)", rsp));
24946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
25046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
25146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        InterfaceConfiguration cfg = new InterfaceConfiguration();
25246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        cfg.hwAddr = st.nextToken(" ");
25346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
2541127e126a25f26d7d255c73e19d2e07f1c854781Ben Murdoch            cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
2551127e126a25f26d7d255c73e19d2e07f1c854781Ben Murdoch        } catch (UnknownHostException uhe) {
2561127e126a25f26d7d255c73e19d2e07f1c854781Ben Murdoch            Slog.e(TAG, "Failed to parse ipaddr", uhe);
25746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            cfg.ipAddr = 0;
2581127e126a25f26d7d255c73e19d2e07f1c854781Ben Murdoch        }
25946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
26046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
26146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            cfg.netmask = stringToIpAddr(st.nextToken(" "));
26246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } catch (UnknownHostException uhe) {
26346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            Slog.e(TAG, "Failed to parse netmask", uhe);
26446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            cfg.netmask = 0;
26546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
26646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        cfg.interfaceFlags = st.nextToken("]").trim() +"]";
26746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
26846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return cfg;
26946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
27046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
27146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void setInterfaceConfig(
27246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String iface, InterfaceConfiguration cfg) throws IllegalStateException {
2737cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba        String cmd = String.format("interface setcfg %s %s %s %s", iface,
27446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
27546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(cmd);
27646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
27746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
2787cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba    public void shutdown() {
27946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        if (mContext.checkCallingOrSelfPermission(
28046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.SHUTDOWN)
28146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                != PackageManager.PERMISSION_GRANTED) {
28246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            throw new SecurityException("Requires SHUTDOWN permission");
2837cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba        }
28446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
28546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        Slog.d(TAG, "Shutting down");
28646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
28746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
2887cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba    public boolean getIpForwardingEnabled() throws IllegalStateException{
28946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
29046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
29146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
29246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
2937cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba
29446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        for (String line : rsp) {
29546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String []tok = line.split(" ");
29646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int code = Integer.parseInt(tok[0]);
29746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            if (code == NetdResponseCode.IpFwdStatusResult) {
2987cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba                // 211 Forwarding <enabled/disabled>
29946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                if (tok.length !=2) {
30046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    throw new IllegalStateException(
30146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                            String.format("Malformatted list entry '%s'", line));
30246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                }
3037cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba                if (tok[2].equals("enabled"))
30446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    return true;
30546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                return false;
30646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } else {
30746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                throw new IllegalStateException(String.format("Unexpected response code %d", code));
3087cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba            }
30946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
31046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        throw new IllegalStateException("Got an empty response");
31146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
31246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
3136d58f78e7fc0412a58b163559cb8e9c4af5c6fe1Jonathan Dixon    public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
31446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
31546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
31646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
31746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
31846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
3197cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba    public void startTethering(String[] dhcpRange)
32046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             throws IllegalStateException {
32146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
32246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
32346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        // cmd is "tether start first_start first_stop second_start second_stop ..."
3247cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba        // an odd number of addrs will fail
32546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        String cmd = "tether start";
32646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        for (String d : dhcpRange) {
32746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            cmd += " " + d;
32846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
32946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(cmd);
33046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
33146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
33246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void stopTethering() throws IllegalStateException {
33346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
3349c5a40623b62737244deb2d04a98830d7ffa8404Leandro Gracia Gil                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
33546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand("tether stop");
33646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
33746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
33846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public boolean isTetheringStarted() throws IllegalStateException {
3393520eb778d668dc76ca4541c69abd568b9d02691Mikhail Naganov        mContext.enforceCallingOrSelfPermission(
34046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
34146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
34246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        ArrayList<String> rsp = mConnector.doCommand("tether status");
34346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
3443520eb778d668dc76ca4541c69abd568b9d02691Mikhail Naganov        for (String line : rsp) {
34546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String []tok = line.split(" ");
34646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int code = Integer.parseInt(tok[0]);
34746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            if (code == NetdResponseCode.TetherStatusResult) {
34846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                // XXX: Tethering services <started/stopped> <TBD>...
3497cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba                if (tok[2].equals("started"))
35046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    return true;
35146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                return false;
35246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } else {
35346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                throw new IllegalStateException(String.format("Unexpected response code %d", code));
354c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu            }
355c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu        }
356c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu        throw new IllegalStateException("Got an empty response");
357c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu    }
35846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
35946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void tetherInterface(String iface) throws IllegalStateException {
36046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
36146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
362c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu        mConnector.doCommand("tether interface add " + iface);
36346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
36446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
36546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void untetherInterface(String iface) {
36646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
367c3fbc0fea57ba0dd4cf9eb8cc4d12f1b0edbcc5cBo Liu                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
36846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand("tether interface remove " + iface);
36946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
37046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
37146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public String[] listTetheredInterfaces() throws IllegalStateException {
3727cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba        mContext.enforceCallingOrSelfPermission(
37346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
37446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return mConnector.doListCommand(
37546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                "tether interface list", NetdResponseCode.TetherInterfaceListResult);
37646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
37746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
37846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void setDnsForwarders(String[] dns) throws IllegalStateException {
37946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
38046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
38146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
38246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String cmd = "tether dns set";
38346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            for (String s : dns) {
38446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                cmd += " " + InetAddress.getByName(s).getHostAddress();
38546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
3867cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba            mConnector.doCommand(cmd);
38746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } catch (UnknownHostException e) {
38846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            throw new IllegalStateException("Error resolving dns name", e);
38946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
39046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
3919405536501747e2d7b4fc46a33e5f0a1e7fd47acJonathan Dixon
39246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public String[] getDnsForwarders() throws IllegalStateException {
39346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
39446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
39546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return mConnector.doListCommand(
3969405536501747e2d7b4fc46a33e5f0a1e7fd47acJonathan Dixon                "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
39746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
39846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
39946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void enableNat(String internalInterface, String externalInterface)
40046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            throws IllegalStateException {
40146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
40246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
40346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(
40446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                String.format("nat enable %s %s", internalInterface, externalInterface));
40546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
40646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
4076b5f3d1546ae2a9c712cde60c54ec027582bc4e6Martin Kosiba    public void disableNat(String internalInterface, String externalInterface)
40846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            throws IllegalStateException {
40946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
41046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
41146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(
4126b5f3d1546ae2a9c712cde60c54ec027582bc4e6Martin Kosiba                String.format("nat disable %s %s", internalInterface, externalInterface));
41346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
41446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
41546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public String[] listTtys() throws IllegalStateException {
41646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
417531e68a2b50a5e542eeede13907f29e463a99ebfBen Murdoch                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
41846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
41946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
42046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
42146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
422531e68a2b50a5e542eeede13907f29e463a99ebfBen Murdoch            String dns2Addr) throws IllegalStateException {
42346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
42446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            mContext.enforceCallingOrSelfPermission(
42546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
42646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
4271cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon                    InetAddress.getByName(localAddr).getHostAddress(),
42846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    InetAddress.getByName(remoteAddr).getHostAddress(),
42946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    InetAddress.getByName(dns1Addr).getHostAddress(),
43046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    InetAddress.getByName(dns2Addr).getHostAddress()));
43146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } catch (UnknownHostException e) {
4321cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon            throw new IllegalStateException("Error resolving addr", e);
43346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
43446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
43546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
43646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void detachPppd(String tty) throws IllegalStateException {
4371cc4c3210fd2ea027bd6d883a15c3951476642bbJonathan Dixon        mContext.enforceCallingOrSelfPermission(
43846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
43946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(String.format("pppd detach %s", tty));
44046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
44146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
44246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void startUsbRNDIS() throws IllegalStateException {
44346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
44446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
44546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand("usb startrndis");
44646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
44746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
44846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void stopUsbRNDIS() throws IllegalStateException {
44946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
45046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
45146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand("usb stoprndis");
45246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
45346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
45446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public boolean isUsbRNDISStarted() throws IllegalStateException {
45546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
45646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
4577cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba        ArrayList<String> rsp = mConnector.doCommand("usb rndisstatus");
45846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
45946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        for (String line : rsp) {
46046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String []tok = line.split(" ");
46146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int code = Integer.parseInt(tok[0]);
4627cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba            if (code == NetdResponseCode.UsbRNDISStatusResult) {
46346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                if (tok[3].equals("started"))
46446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    return true;
46546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                return false;
46646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } else {
46708a5e00cdfb74f4ffd843d2d0a9b0b40b86b107aBo Liu                throw new IllegalStateException(String.format("Unexpected response code %d", code));
4687cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba            }
46946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
47046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        throw new IllegalStateException("Got an empty response");
47146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
47246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
47346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
47446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             throws IllegalStateException {
47546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
47646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
47746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
47846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
47946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(String.format("softap stop " + wlanIface));
48046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
48146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(String.format("softap start " + wlanIface));
48246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        if (wifiConfig == null) {
483f37548d6d8e2a73c65d675a26706a38f52960800Jonathan Dixon            mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
484f37548d6d8e2a73c65d675a26706a38f52960800Jonathan Dixon        } else {
48546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            /**
48646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
48746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv1 - wlan interface
48846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv2 - softap interface
48946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv3 - SSID
49046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv4 - Security
49146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv5 - Key
49246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv6 - Channel
49346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)             * argv7 - Preamble
4946d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch             * argv8 - Max SCB
4956d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch             */
4966d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch            String str = String.format("softap set " + wlanIface + " " + softapIface +
4976d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch                                       " %s %s %s", convertQuotedString(wifiConfig.SSID),
4986d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch                                       wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
4996d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch                                       "wpa2-psk" : "open",
5006d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch                                       convertQuotedString(wifiConfig.preSharedKey));
5016d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch            mConnector.doCommand(str);
5026d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch        }
5036d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch        mConnector.doCommand(String.format("softap startap"));
5046d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch    }
5056d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch
5066d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch    private String convertQuotedString(String s) {
5076d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch      /* Replace \ with \\, then " with \" and add quotes at end */
5086d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch      return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
5096d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch    }
5106d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch
5116d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch    public void stopAccessPoint() throws IllegalStateException {
5126d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch        mContext.enforceCallingOrSelfPermission(
5136d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
5146d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch        mContext.enforceCallingOrSelfPermission(
51546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
51646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand("softap stopap");
5176d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch    }
518fde8dae44f74be3de69ce6dd07b0023279b485a0Ben Murdoch
5196d4097cfa188a95c95fd5d0c86238c91f817c3edBen Murdoch    public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
520fde8dae44f74be3de69ce6dd07b0023279b485a0Ben Murdoch            throws IllegalStateException {
521fde8dae44f74be3de69ce6dd07b0023279b485a0Ben Murdoch        mContext.enforceCallingOrSelfPermission(
52246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
52346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
52446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
52546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        if (wifiConfig == null) {
52646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
52746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } else {
52846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String str = String.format("softap set " + wlanIface + " " + softapIface +
52946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                                       " %s %s %s", convertQuotedString(wifiConfig.SSID),
53046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                                       wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
53146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                                       "wpa2-psk" : "open",
53246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                                       convertQuotedString(wifiConfig.preSharedKey));
53346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            mConnector.doCommand(str);
53446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
53546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
53646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
53746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private long getInterfaceCounter(String iface, boolean rx) {
53846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
5394320e428efc3bf69387f3b9d5a0589b2b8746409Bo Liu                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
54046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
54146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String rsp = mConnector.doCommand(
54246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
54346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String []tok = rsp.split(" ");
54446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int code;
54546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            try {
54646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                code = Integer.parseInt(tok[0]);
54746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } catch (NumberFormatException nfe) {
54846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
54946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                return -1;
5509c5a40623b62737244deb2d04a98830d7ffa8404Leandro Gracia Gil            }
5519c5a40623b62737244deb2d04a98830d7ffa8404Leandro Gracia Gil            if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
552edb98e3c667e37b00f338b51fb2e5d6bece4c447Ben Murdoch                    !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
55346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                Slog.e(TAG, String.format("Unexpected response code %d", code));
55446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                return -1;
55546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
55646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            return Long.parseLong(tok[1]);
557ea844f60b1b559788566fe6e004b1eeca53a8039Jonathan Dixon        } catch (Exception e) {
5587db34d3dcaac936566f912e1b0b21f3f103029ffJonathan Dixon            Slog.e(TAG, String.format(
5597db34d3dcaac936566f912e1b0b21f3f103029ffJonathan Dixon                    "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
5607db34d3dcaac936566f912e1b0b21f3f103029ffJonathan Dixon        }
5617db34d3dcaac936566f912e1b0b21f3f103029ffJonathan Dixon        return -1;
5627cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba    }
56346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
56446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public long getInterfaceRxCounter(String iface) {
56546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return getInterfaceCounter(iface, true);
56646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
5677cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba
56846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public long getInterfaceTxCounter(String iface) {
56946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return getInterfaceCounter(iface, false);
57046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
57146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
57246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
573420c0da3a4e06e1ac5574091e7c9c286ef012369Mikhail Naganov        mContext.enforceCallingOrSelfPermission(
57446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
57546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mConnector.doCommand(String.format(
57646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
57746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
57846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
57946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    private int getInterfaceThrottle(String iface, boolean rx) {
58046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        mContext.enforceCallingOrSelfPermission(
58146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
58246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        try {
58346f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            String rsp = mConnector.doCommand(
58446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    String.format("interface getthrottle %s %s", iface,(rx ? "rx" : "tx"))).get(0);
5857cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba            String []tok = rsp.split(" ");
58646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            int code;
58746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            try {
58846f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                code = Integer.parseInt(tok[0]);
58946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            } catch (NumberFormatException nfe) {
590e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixon                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
591e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixon                return -1;
592e78d6e40e4e78671e6621ba8cf49835568704899Jonathan Dixon            }
593420c0da3a4e06e1ac5574091e7c9c286ef012369Mikhail Naganov            if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
59446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
59546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                Slog.e(TAG, String.format("Unexpected response code %d", code));
59646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                return -1;
59746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            }
5987cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba            return Integer.parseInt(tok[1]);
59946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        } catch (Exception e) {
60046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)            Slog.e(TAG, String.format(
60146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)                    "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
60246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        }
6037cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba        return -1;
60446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
60546f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
60646f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public int getInterfaceRxThrottle(String iface) {
60746f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return getInterfaceThrottle(iface, true);
6087cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba    }
60946f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)
61046f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    public int getInterfaceTxThrottle(String iface) {
61146f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)        return getInterfaceThrottle(iface, false);
61246f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)    }
6137cb3dd1c0aca371b628b80afa69c58638de30fa1Martin Kosiba}
61446f104289826e85ba76a1a2139d7ecc7daca07b1Torne (Richard Coles)