NetworkManagementService.java revision e325392c257a5460de6327420c81729f4e687881
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
19873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.app.PendingIntent;
20873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.BroadcastReceiver;
21873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.Context;
22873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.Intent;
23873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.IntentFilter;
24873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.res.Resources;
25873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.pm.PackageManager;
26873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.net.Uri;
27ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehatimport android.net.InterfaceConfiguration;
284d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehatimport android.net.INetworkManagementEventObserver;
29873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.os.INetworkManagementService;
30873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.os.Handler;
31873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.text.TextUtils;
32873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.util.Log;
33873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.util.ArrayList;
34ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehatimport java.util.StringTokenizer;
35873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.provider.Settings;
36873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.content.ContentResolver;
37873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport android.database.ContentObserver;
38873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
39873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.io.File;
40873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.io.FileReader;
41873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.lang.IllegalStateException;
42873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
43873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.net.InetAddress;
44873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatimport java.net.UnknownHostException;
45873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
46873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat/**
47873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat * @hide
48873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat */
49873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehatclass NetworkManagementService extends INetworkManagementService.Stub {
50873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
51873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private static final String TAG = "NetworkManagmentService";
52873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
53873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    class NetdResponseCode {
54873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int InterfaceListResult       = 110;
55873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int TetherInterfaceListResult = 111;
56873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int TetherDnsFwdTgtListResult = 112;
5772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        public static final int TtyListResult             = 113;
58873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
59873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int TetherStatusResult        = 210;
60873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public static final int IpFwdStatusResult         = 211;
61ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        public static final int InterfaceGetCfgResult     = 213;
62e325392c257a5460de6327420c81729f4e687881Robert Greenwalt        public static final int SoftapStatusResult        = 214;
63e325392c257a5460de6327420c81729f4e687881Robert Greenwalt        public static final int UsbRNDISStatusResult      = 215;
64e325392c257a5460de6327420c81729f4e687881Robert Greenwalt
65e325392c257a5460de6327420c81729f4e687881Robert Greenwalt        public static final int InterfaceChange           = 600;
66873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
67873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
68873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
69873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * Binder context for this service
70873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
71873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private Context mContext;
72873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
73873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
74873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * connector object for communicating with netd
75873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
76873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private NativeDaemonConnector mConnector;
77873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
784d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private ArrayList<INetworkManagementEventObserver> mObservers;
794d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
80873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
81873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * Constructs a new NetworkManagementService instance
82873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     *
83873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * @param context  Binder context for this service
84873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
85d1df8ac6d076ef15ba8857211da2e447b6505fb3San Mehat    public NetworkManagementService(Context context) {
86873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext = context;
87873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
884d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers = new ArrayList<INetworkManagementEventObserver>();
894d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
90873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector = new NativeDaemonConnector(
91873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
92873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
93873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        thread.start();
94873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
95873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
964d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    public void registerObserver(INetworkManagementEventObserver obs) {
974d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        Log.d(TAG, "Registering observer");
984d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers.add(obs);
994d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1004d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1014d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    public void unregisterObserver(INetworkManagementEventObserver obs) {
1024d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        Log.d(TAG, "Unregistering observer");
1034d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers.remove(mObservers.indexOf(obs));
1044d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1054d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1064d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1074d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface link status change
1084d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
1094d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
1104d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
1114d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
1124d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceLinkStatusChanged(iface, link);
1134d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
1144d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                Log.w(TAG, "Observer notifier failed", ex);
1154d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
1164d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
1174d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1184d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1194d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1204d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface addition.
1214d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
1224d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceAdded(String iface) {
1234d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
1244d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
1254d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceAdded(iface);
1264d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
1274d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                Log.w(TAG, "Observer notifier failed", ex);
1284d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
1294d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
1304d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1314d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1324d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1334d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface removal.
1344d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
1354d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceRemoved(String iface) {
1364d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
1374d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
1384d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceRemoved(iface);
1394d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
1404d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                Log.w(TAG, "Observer notifier failed", ex);
1414d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
1424d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
1434d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1444d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1454d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
146873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
147873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    // Netd Callback handling
148873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
149873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
150873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
151873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public void onDaemonConnected() {
152873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            new Thread() {
153873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                public void run() {
154873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                }
155873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }.start();
156873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
157873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public boolean onEvent(int code, String raw, String[] cooked) {
158e325392c257a5460de6327420c81729f4e687881Robert Greenwalt            if (code == NetdResponseCode.InterfaceChange) {
159e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                /*
160e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                 * a network interface change occured
161e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                 * Format: "NNN Iface added <name>"
162e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                 *         "NNN Iface removed <name>"
163e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                 *         "NNN Iface changed <name> <up/down>"
164e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                 */
165e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                if (cooked.length < 4 || !cooked[1].equals("Iface")) {
166e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    throw new IllegalStateException(
167e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                            String.format("Invalid event from daemon (%s)", raw));
168e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                }
169e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                if (cooked[2].equals("added")) {
170e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    notifyInterfaceAdded(cooked[3]);
171e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    return true;
172e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                } else if (cooked[2].equals("removed")) {
173e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    notifyInterfaceRemoved(cooked[3]);
174e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    return true;
175e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                } else if (cooked[2].equals("changed") && cooked.length == 5) {
176e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
177e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                    return true;
178e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                }
179e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                throw new IllegalStateException(
180e325392c257a5460de6327420c81729f4e687881Robert Greenwalt                        String.format("Invalid event from daemon (%s)", raw));
181e325392c257a5460de6327420c81729f4e687881Robert Greenwalt            }
182e325392c257a5460de6327420c81729f4e687881Robert Greenwalt            return false;
183873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
184873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
185873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
186ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    private static int stringToIpAddr(String addrString) throws UnknownHostException {
187ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
188ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            String[] parts = addrString.split("\\.");
189ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            if (parts.length != 4) {
190ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                throw new UnknownHostException(addrString);
191ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            }
192ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
193ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int a = Integer.parseInt(parts[0])      ;
194ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int b = Integer.parseInt(parts[1]) <<  8;
195ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int c = Integer.parseInt(parts[2]) << 16;
196ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int d = Integer.parseInt(parts[3]) << 24;
197ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
198ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            return a | b | c | d;
199ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (NumberFormatException ex) {
200ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            throw new UnknownHostException(addrString);
201ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
202ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
203ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
204ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public static String intToIpString(int i) {
205ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >>  8 ) & 0xFF) + "." +
206ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat               (i & 0xFF);
207ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
208ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
209873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
210873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    // INetworkManagementService members
211873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
212873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
213873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] listInterfaces() throws IllegalStateException {
214873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
215873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
216873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
217ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
218ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
219ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
220ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
221ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        String rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
222ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        Log.d(TAG, String.format("rsp <%s>", rsp));
223ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
224ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
225ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        StringTokenizer st = new StringTokenizer(rsp);
226ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
227ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
228ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int code = Integer.parseInt(st.nextToken(" "));
229ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            if (code != NetdResponseCode.InterfaceGetCfgResult) {
230ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                throw new IllegalStateException(
231ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                    String.format("Expected code %d, but got %d",
232ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                            NetdResponseCode.InterfaceGetCfgResult, code));
233ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            }
234ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (NumberFormatException nfe) {
235ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            throw new IllegalStateException(
236ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                    String.format("Invalid response from daemon (%s)", rsp));
237ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
238ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
239ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        InterfaceConfiguration cfg = new InterfaceConfiguration();
240ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        cfg.hwAddr = st.nextToken(" ");
241ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
242ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
243ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (UnknownHostException uhe) {
244ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            Log.e(TAG, "Failed to parse ipaddr", uhe);
245ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.ipAddr = 0;
246ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
247ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
248ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
249ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.netmask = stringToIpAddr(st.nextToken(" "));
250ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (UnknownHostException uhe) {
251ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            Log.e(TAG, "Failed to parse netmask", uhe);
252ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.netmask = 0;
253ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
254ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        cfg.interfaceFlags = st.nextToken("]");
255ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        Log.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
256ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return cfg;
257ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
258ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
259ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public void setInterfaceConfig(
260ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            String iface, InterfaceConfiguration cfg) throws IllegalStateException {
261ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        String cmd = String.format("interface setcfg %s %s %s", iface,
262ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
263ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        mConnector.doCommand(cmd);
264873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
265873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
266873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void shutdown() {
267873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        if (mContext.checkCallingOrSelfPermission(
268873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.SHUTDOWN)
269873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                != PackageManager.PERMISSION_GRANTED) {
270873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throw new SecurityException("Requires SHUTDOWN permission");
271873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
272873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
273873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        Log.d(TAG, "Shutting down");
274873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
275873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
276873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public boolean getIpForwardingEnabled() throws IllegalStateException{
277873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
278873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
279873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
280873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
281873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
282873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        for (String line : rsp) {
283873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            String []tok = line.split(" ");
284873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            int code = Integer.parseInt(tok[0]);
285873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            if (code == NetdResponseCode.IpFwdStatusResult) {
286873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                // 211 Forwarding <enabled/disabled>
287873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                if (tok.length !=2) {
288873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    throw new IllegalStateException(
289873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                            String.format("Malformatted list entry '%s'", line));
290873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                }
291873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                if (tok[2].equals("enabled"))
292873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    return true;
293873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                return false;
294873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            } else {
295873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
296873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
297873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
298873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        throw new IllegalStateException("Got an empty response");
299873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
300873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
301873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
302873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
303873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
304873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
305873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
306873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
307873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void startTethering(String dhcpRangeStart, String dhcpRangeEnd)
308873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat             throws IllegalStateException {
309873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
310873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
311873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd));
312873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
313873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
314873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void stopTethering() throws IllegalStateException {
315873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
316873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
317873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand("tether stop");
318873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
319873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
320873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public boolean isTetheringStarted() throws IllegalStateException {
321873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
322873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
323873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
324873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        ArrayList<String> rsp = mConnector.doCommand("tether status");
325873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
326873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        for (String line : rsp) {
327873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            String []tok = line.split(" ");
328873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            int code = Integer.parseInt(tok[0]);
329873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            if (code == NetdResponseCode.TetherStatusResult) {
330873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                // XXX: Tethering services <started/stopped> <TBD>...
331873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                if (tok[2].equals("started"))
332873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    return true;
333873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                return false;
334873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            } else {
335873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
336873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
337873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
338873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        throw new IllegalStateException("Got an empty response");
339873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
340873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
341873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void tetherInterface(String iface) throws IllegalStateException {
342873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
343873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
344873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand("tether interface add " + iface);
345873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
346873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
347873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void untetherInterface(String iface) {
348873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
349873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
350873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand("tether interface remove " + iface);
351873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
352873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
353873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] listTetheredInterfaces() throws IllegalStateException {
354873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
355873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
35672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        return mConnector.doListCommand(
35772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                "tether interface list", NetdResponseCode.TetherInterfaceListResult);
358873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
359873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
360873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void setDnsForwarders(String[] dns) throws IllegalStateException {
361873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
362873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
363873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        try {
364d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            String cmd = "tether dns set";
365873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            for (String s : dns) {
366d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                cmd += " " + InetAddress.getByName(s).getHostAddress();
367873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
368873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            mConnector.doCommand(cmd);
369873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        } catch (UnknownHostException e) {
370873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throw new IllegalStateException("Error resolving dns name", e);
371873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
372873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
373873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
374873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] getDnsForwarders() throws IllegalStateException {
375873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
376873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
37772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        return mConnector.doListCommand(
37872759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
379873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
380873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
381873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void enableNat(String internalInterface, String externalInterface)
382873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throws IllegalStateException {
383873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
384873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
385873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(
386873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                String.format("nat enable %s %s", internalInterface, externalInterface));
387873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
388873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
389873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void disableNat(String internalInterface, String externalInterface)
390873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throws IllegalStateException {
391873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
392873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
393873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(
394873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                String.format("nat disable %s %s", internalInterface, externalInterface));
395873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
39672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
39772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    public String[] listTtys() throws IllegalStateException {
39872759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mContext.enforceCallingOrSelfPermission(
39972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
40072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
40172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
40272759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
403d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
404d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            String dns2Addr) throws IllegalStateException {
40572759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        try {
40672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat            mContext.enforceCallingOrSelfPermission(
40772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                    android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
408d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
409d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(localAddr).getHostAddress(),
410d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(remoteAddr).getHostAddress(),
411d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(dns1Addr).getHostAddress(),
412d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(dns2Addr).getHostAddress()));
41372759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        } catch (UnknownHostException e) {
41472759df749bb8557269db86c2e3b2a8a0343cc26San Mehat            throw new IllegalStateException("Error resolving addr", e);
41572759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        }
41672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
41772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
41872759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    public void detachPppd(String tty) throws IllegalStateException {
41972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mContext.enforceCallingOrSelfPermission(
42072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
42172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mConnector.doCommand(String.format("pppd detach %s", tty));
42272759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
423873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat}
424