NetworkManagementService.java revision d0e18ffb82b59d38aeaf0e552f48e734202719ab
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;
62873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
63873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
64873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
65873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * Binder context for this service
66873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
67873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private Context mContext;
68873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
69873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
70873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * connector object for communicating with netd
71873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
72873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    private NativeDaemonConnector mConnector;
73873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
744d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private ArrayList<INetworkManagementEventObserver> mObservers;
754d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
76873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    /**
77873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * Constructs a new NetworkManagementService instance
78873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     *
79873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     * @param context  Binder context for this service
80873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat     */
81d1df8ac6d076ef15ba8857211da2e447b6505fb3San Mehat    public NetworkManagementService(Context context) {
82873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext = context;
83873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
844d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers = new ArrayList<INetworkManagementEventObserver>();
854d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
86873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector = new NativeDaemonConnector(
87873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
88873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
89873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        thread.start();
90873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
91873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
924d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    public void registerObserver(INetworkManagementEventObserver obs) {
934d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        Log.d(TAG, "Registering observer");
944d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers.add(obs);
954d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
964d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
974d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    public void unregisterObserver(INetworkManagementEventObserver obs) {
984d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        Log.d(TAG, "Unregistering observer");
994d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        mObservers.remove(mObservers.indexOf(obs));
1004d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1014d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1024d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1034d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface link status change
1044d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
1054d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
1064d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
1074d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
1084d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceLinkStatusChanged(iface, link);
1094d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
1104d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                Log.w(TAG, "Observer notifier failed", ex);
1114d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
1124d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
1134d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1144d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1154d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1164d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface addition.
1174d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
1184d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceAdded(String iface) {
1194d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
1204d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
1214d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceAdded(iface);
1224d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
1234d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                Log.w(TAG, "Observer notifier failed", ex);
1244d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
1254d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
1264d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1274d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1284d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    /**
1294d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     * Notify our observers of an interface removal.
1304d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat     */
1314d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    private void notifyInterfaceRemoved(String iface) {
1324d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        for (INetworkManagementEventObserver obs : mObservers) {
1334d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            try {
1344d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                obs.interfaceRemoved(iface);
1354d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            } catch (Exception ex) {
1364d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat                Log.w(TAG, "Observer notifier failed", ex);
1374d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat            }
1384d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat        }
1394d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat    }
1404d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
1414d02d001ef6e06583e858e63e48d1aebf54ba28dSan Mehat
142873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
143873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    // Netd Callback handling
144873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
145873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
146873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
147873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public void onDaemonConnected() {
148873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            new Thread() {
149873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                public void run() {
150873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    // XXX: Run some tests
151873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                }
152873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }.start();
153873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
154873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        public boolean onEvent(int code, String raw, String[] cooked) {
155873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat           return false;
156873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
157873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
158873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
159ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    private static int stringToIpAddr(String addrString) throws UnknownHostException {
160ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
161ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            String[] parts = addrString.split("\\.");
162ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            if (parts.length != 4) {
163ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                throw new UnknownHostException(addrString);
164ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            }
165ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
166ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int a = Integer.parseInt(parts[0])      ;
167ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int b = Integer.parseInt(parts[1]) <<  8;
168ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int c = Integer.parseInt(parts[2]) << 16;
169ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int d = Integer.parseInt(parts[3]) << 24;
170ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
171ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            return a | b | c | d;
172ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (NumberFormatException ex) {
173ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            throw new UnknownHostException(addrString);
174ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
175ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
176ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
177ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public static String intToIpString(int i) {
178ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >>  8 ) & 0xFF) + "." +
179ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat               (i & 0xFF);
180ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
181ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
182873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
183873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    // INetworkManagementService members
184873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    //
185873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
186873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] listInterfaces() throws IllegalStateException {
187873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
188873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
189873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
190ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
191ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
192ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
193ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
194ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        String rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
195ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        Log.d(TAG, String.format("rsp <%s>", rsp));
196ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
197ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
198ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        StringTokenizer st = new StringTokenizer(rsp);
199ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
200ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
201ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            int code = Integer.parseInt(st.nextToken(" "));
202ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            if (code != NetdResponseCode.InterfaceGetCfgResult) {
203ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                throw new IllegalStateException(
204ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                    String.format("Expected code %d, but got %d",
205ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                            NetdResponseCode.InterfaceGetCfgResult, code));
206ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            }
207ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (NumberFormatException nfe) {
208ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            throw new IllegalStateException(
209ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                    String.format("Invalid response from daemon (%s)", rsp));
210ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
211ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
212ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        InterfaceConfiguration cfg = new InterfaceConfiguration();
213ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        cfg.hwAddr = st.nextToken(" ");
214ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
215ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
216ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (UnknownHostException uhe) {
217ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            Log.e(TAG, "Failed to parse ipaddr", uhe);
218ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.ipAddr = 0;
219ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
220ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
221ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        try {
222ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.netmask = stringToIpAddr(st.nextToken(" "));
223ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        } catch (UnknownHostException uhe) {
224ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            Log.e(TAG, "Failed to parse netmask", uhe);
225ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            cfg.netmask = 0;
226ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        }
227ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        cfg.interfaceFlags = st.nextToken("]");
228ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        Log.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
229ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        return cfg;
230ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    }
231ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat
232ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat    public void setInterfaceConfig(
233ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat            String iface, InterfaceConfiguration cfg) throws IllegalStateException {
234ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        String cmd = String.format("interface setcfg %s %s %s", iface,
235ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat                intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
236ed4fc8acc52d89f1d4dec853a29288c6d06717c3San Mehat        mConnector.doCommand(cmd);
237873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
238873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
239873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void shutdown() {
240873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        if (mContext.checkCallingOrSelfPermission(
241873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.SHUTDOWN)
242873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                != PackageManager.PERMISSION_GRANTED) {
243873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throw new SecurityException("Requires SHUTDOWN permission");
244873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
245873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
246873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        Log.d(TAG, "Shutting down");
247873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
248873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
249873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public boolean getIpForwardingEnabled() throws IllegalStateException{
250873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
251873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
252873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
253873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
254873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
255873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        for (String line : rsp) {
256873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            String []tok = line.split(" ");
257873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            int code = Integer.parseInt(tok[0]);
258873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            if (code == NetdResponseCode.IpFwdStatusResult) {
259873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                // 211 Forwarding <enabled/disabled>
260873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                if (tok.length !=2) {
261873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    throw new IllegalStateException(
262873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                            String.format("Malformatted list entry '%s'", line));
263873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                }
264873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                if (tok[2].equals("enabled"))
265873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    return true;
266873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                return false;
267873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            } else {
268873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
269873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
270873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
271873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        throw new IllegalStateException("Got an empty response");
272873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
273873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
274873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
275873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
276873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
277873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
278873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
279873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
280873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void startTethering(String dhcpRangeStart, String dhcpRangeEnd)
281873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat             throws IllegalStateException {
282873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
283873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
284873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd));
285873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
286873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
287873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void stopTethering() throws IllegalStateException {
288873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
289873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
290873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand("tether stop");
291873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
292873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
293873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public boolean isTetheringStarted() throws IllegalStateException {
294873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
295873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
296873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
297873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        ArrayList<String> rsp = mConnector.doCommand("tether status");
298873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
299873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        for (String line : rsp) {
300873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            String []tok = line.split(" ");
301873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            int code = Integer.parseInt(tok[0]);
302873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            if (code == NetdResponseCode.TetherStatusResult) {
303873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                // XXX: Tethering services <started/stopped> <TBD>...
304873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                if (tok[2].equals("started"))
305873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                    return true;
306873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                return false;
307873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            } else {
308873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
309873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
310873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
311873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        throw new IllegalStateException("Got an empty response");
312873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
313873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
314873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void tetherInterface(String iface) throws IllegalStateException {
315873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
316873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
317873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand("tether interface add " + iface);
318873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
319873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
320873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void untetherInterface(String iface) {
321873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
322873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
323873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand("tether interface remove " + iface);
324873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
325873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
326873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] listTetheredInterfaces() throws IllegalStateException {
327873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
328873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
32972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        return mConnector.doListCommand(
33072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                "tether interface list", NetdResponseCode.TetherInterfaceListResult);
331873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
332873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
333873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void setDnsForwarders(String[] dns) throws IllegalStateException {
334873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
335873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
336873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        try {
337d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            String cmd = "tether dns set";
338873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            for (String s : dns) {
339d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                cmd += " " + InetAddress.getByName(s).getHostAddress();
340873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            }
341873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            mConnector.doCommand(cmd);
342873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        } catch (UnknownHostException e) {
343873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throw new IllegalStateException("Error resolving dns name", e);
344873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        }
345873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
346873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
347873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public String[] getDnsForwarders() throws IllegalStateException {
348873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
349873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
35072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        return mConnector.doListCommand(
35172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
352873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
353873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
354873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void enableNat(String internalInterface, String externalInterface)
355873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throws IllegalStateException {
356873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
357873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
358873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(
359873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                String.format("nat enable %s %s", internalInterface, externalInterface));
360873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
361873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat
362873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    public void disableNat(String internalInterface, String externalInterface)
363873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat            throws IllegalStateException {
364873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mContext.enforceCallingOrSelfPermission(
365873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
366873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat        mConnector.doCommand(
367873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat                String.format("nat disable %s %s", internalInterface, externalInterface));
368873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat    }
36972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
37072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    public String[] listTtys() throws IllegalStateException {
37172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mContext.enforceCallingOrSelfPermission(
37272759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
37372759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
37472759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
37572759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
376d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt    public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
377d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            String dns2Addr) throws IllegalStateException {
37872759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        try {
37972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat            mContext.enforceCallingOrSelfPermission(
38072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                    android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
381d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt            mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
382d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(localAddr).getHostAddress(),
383d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(remoteAddr).getHostAddress(),
384d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(dns1Addr).getHostAddress(),
385d0e18ffb82b59d38aeaf0e552f48e734202719abRobert Greenwalt                    InetAddress.getByName(dns2Addr).getHostAddress()));
38672759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        } catch (UnknownHostException e) {
38772759df749bb8557269db86c2e3b2a8a0343cc26San Mehat            throw new IllegalStateException("Error resolving addr", e);
38872759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        }
38972759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
39072759df749bb8557269db86c2e3b2a8a0343cc26San Mehat
39172759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    public void detachPppd(String tty) throws IllegalStateException {
39272759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mContext.enforceCallingOrSelfPermission(
39372759df749bb8557269db86c2e3b2a8a0343cc26San Mehat                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
39472759df749bb8557269db86c2e3b2a8a0343cc26San Mehat        mConnector.doCommand(String.format("pppd detach %s", tty));
39572759df749bb8557269db86c2e3b2a8a0343cc26San Mehat    }
396873f2145941cc28f6931dc18b5e9987bd22e2e19San Mehat}
397