NetworkManagementService.java revision f336d722c773855402d91a227fc290eafca23335
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
20import static android.Manifest.permission.DUMP;
21import static android.Manifest.permission.SHUTDOWN;
22import static android.net.NetworkStats.SET_DEFAULT;
23import static android.net.NetworkStats.TAG_NONE;
24import static android.net.NetworkStats.UID_ALL;
25import static android.net.TrafficStats.UID_TETHERING;
26import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
27import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
28import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
29import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
30import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
31import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
32import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
33import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsResult;
34import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
35import static com.android.server.NetworkManagementService.NetdResponseCode.GetMarkResult;
36import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
37
38import android.content.Context;
39import android.net.INetworkManagementEventObserver;
40import android.net.InterfaceConfiguration;
41import android.net.LinkAddress;
42import android.net.NetworkStats;
43import android.net.NetworkUtils;
44import android.net.RouteInfo;
45import android.net.wifi.WifiConfiguration;
46import android.net.wifi.WifiConfiguration.KeyMgmt;
47import android.os.BatteryStats;
48import android.os.Binder;
49import android.os.Handler;
50import android.os.INetworkManagementService;
51import android.os.Process;
52import android.os.RemoteCallbackList;
53import android.os.RemoteException;
54import android.os.ServiceManager;
55import android.os.SystemClock;
56import android.os.SystemProperties;
57import android.util.Log;
58import android.util.Slog;
59import android.util.SparseBooleanArray;
60
61import com.android.internal.app.IBatteryStats;
62import com.android.internal.net.NetworkStatsFactory;
63import com.android.internal.util.Preconditions;
64import com.android.server.NativeDaemonConnector.Command;
65import com.android.server.NativeDaemonConnector.SensitiveArg;
66import com.android.server.net.LockdownVpnTracker;
67import com.google.android.collect.Maps;
68
69import java.io.BufferedReader;
70import java.io.DataInputStream;
71import java.io.File;
72import java.io.FileDescriptor;
73import java.io.FileInputStream;
74import java.io.IOException;
75import java.io.InputStreamReader;
76import java.io.PrintWriter;
77import java.net.Inet4Address;
78import java.net.InetAddress;
79import java.net.InterfaceAddress;
80import java.net.NetworkInterface;
81import java.net.SocketException;
82import java.util.ArrayList;
83import java.util.Collection;
84import java.util.HashMap;
85import java.util.Map;
86import java.util.NoSuchElementException;
87import java.util.StringTokenizer;
88import java.util.concurrent.CountDownLatch;
89
90/**
91 * @hide
92 */
93public class NetworkManagementService extends INetworkManagementService.Stub
94        implements Watchdog.Monitor {
95    private static final String TAG = "NetworkManagementService";
96    private static final boolean DBG = false;
97    private static final String NETD_TAG = "NetdConnector";
98
99    private static final String ADD = "add";
100    private static final String REMOVE = "remove";
101
102    private static final String ALLOW = "allow";
103    private static final String DENY = "deny";
104
105    private static final String DEFAULT = "default";
106    private static final String SECONDARY = "secondary";
107
108    /**
109     * Name representing {@link #setGlobalAlert(long)} limit when delivered to
110     * {@link INetworkManagementEventObserver#limitReached(String, String)}.
111     */
112    public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
113
114    class NetdResponseCode {
115        /* Keep in sync with system/netd/ResponseCode.h */
116        public static final int InterfaceListResult       = 110;
117        public static final int TetherInterfaceListResult = 111;
118        public static final int TetherDnsFwdTgtListResult = 112;
119        public static final int TtyListResult             = 113;
120
121        public static final int TetherStatusResult        = 210;
122        public static final int IpFwdStatusResult         = 211;
123        public static final int InterfaceGetCfgResult     = 213;
124        public static final int SoftapStatusResult        = 214;
125        public static final int InterfaceRxCounterResult  = 216;
126        public static final int InterfaceTxCounterResult  = 217;
127        public static final int QuotaCounterResult        = 220;
128        public static final int TetheringStatsResult      = 221;
129        public static final int DnsProxyQueryResult       = 222;
130        public static final int ClatdStatusResult         = 223;
131        public static final int GetMarkResult             = 225;
132
133        public static final int InterfaceChange           = 600;
134        public static final int BandwidthControl          = 601;
135        public static final int InterfaceClassActivity    = 613;
136    }
137
138    /**
139     * Binder context for this service
140     */
141    private Context mContext;
142
143    /**
144     * connector object for communicating with netd
145     */
146    private NativeDaemonConnector mConnector;
147
148    private final Handler mMainHandler = new Handler();
149
150    private Thread mThread;
151    private CountDownLatch mConnectedSignal = new CountDownLatch(1);
152
153    private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
154            new RemoteCallbackList<INetworkManagementEventObserver>();
155
156    private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
157
158    private Object mQuotaLock = new Object();
159    /** Set of interfaces with active quotas. */
160    private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
161    /** Set of interfaces with active alerts. */
162    private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
163    /** Set of UIDs with active reject rules. */
164    private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
165
166    private Object mIdleTimerLock = new Object();
167    /** Set of interfaces with active idle timers. */
168    private static class IdleTimerParams {
169        public final int timeout;
170        public final String label;
171        public int networkCount;
172
173        IdleTimerParams(int timeout, String label) {
174            this.timeout = timeout;
175            this.label = label;
176            this.networkCount = 1;
177        }
178    }
179    private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
180
181    private volatile boolean mBandwidthControlEnabled;
182    private volatile boolean mFirewallEnabled;
183
184    /**
185     * Constructs a new NetworkManagementService instance
186     *
187     * @param context  Binder context for this service
188     */
189    private NetworkManagementService(Context context) {
190        mContext = context;
191
192        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
193            return;
194        }
195
196        mConnector = new NativeDaemonConnector(
197                new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160);
198        mThread = new Thread(mConnector, NETD_TAG);
199
200        // Add ourself to the Watchdog monitors.
201        Watchdog.getInstance().addMonitor(this);
202    }
203
204    public static NetworkManagementService create(Context context) throws InterruptedException {
205        final NetworkManagementService service = new NetworkManagementService(context);
206        final CountDownLatch connectedSignal = service.mConnectedSignal;
207        if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
208        service.mThread.start();
209        if (DBG) Slog.d(TAG, "Awaiting socket connection");
210        connectedSignal.await();
211        if (DBG) Slog.d(TAG, "Connected");
212        return service;
213    }
214
215    public void systemReady() {
216        prepareNativeDaemon();
217        if (DBG) Slog.d(TAG, "Prepared");
218    }
219
220    @Override
221    public void registerObserver(INetworkManagementEventObserver observer) {
222        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
223        mObservers.register(observer);
224    }
225
226    @Override
227    public void unregisterObserver(INetworkManagementEventObserver observer) {
228        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
229        mObservers.unregister(observer);
230    }
231
232    /**
233     * Notify our observers of an interface status change
234     */
235    private void notifyInterfaceStatusChanged(String iface, boolean up) {
236        final int length = mObservers.beginBroadcast();
237        for (int i = 0; i < length; i++) {
238            try {
239                mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
240            } catch (RemoteException e) {
241            } catch (RuntimeException e) {
242            }
243        }
244        mObservers.finishBroadcast();
245    }
246
247    /**
248     * Notify our observers of an interface link state change
249     * (typically, an Ethernet cable has been plugged-in or unplugged).
250     */
251    private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
252        final int length = mObservers.beginBroadcast();
253        for (int i = 0; i < length; i++) {
254            try {
255                mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
256            } catch (RemoteException e) {
257            } catch (RuntimeException e) {
258            }
259        }
260        mObservers.finishBroadcast();
261    }
262
263    /**
264     * Notify our observers of an interface addition.
265     */
266    private void notifyInterfaceAdded(String iface) {
267        final int length = mObservers.beginBroadcast();
268        for (int i = 0; i < length; i++) {
269            try {
270                mObservers.getBroadcastItem(i).interfaceAdded(iface);
271            } catch (RemoteException e) {
272            } catch (RuntimeException e) {
273            }
274        }
275        mObservers.finishBroadcast();
276    }
277
278    /**
279     * Notify our observers of an interface removal.
280     */
281    private void notifyInterfaceRemoved(String iface) {
282        // netd already clears out quota and alerts for removed ifaces; update
283        // our sanity-checking state.
284        mActiveAlerts.remove(iface);
285        mActiveQuotas.remove(iface);
286
287        final int length = mObservers.beginBroadcast();
288        for (int i = 0; i < length; i++) {
289            try {
290                mObservers.getBroadcastItem(i).interfaceRemoved(iface);
291            } catch (RemoteException e) {
292            } catch (RuntimeException e) {
293            }
294        }
295        mObservers.finishBroadcast();
296    }
297
298    /**
299     * Notify our observers of a limit reached.
300     */
301    private void notifyLimitReached(String limitName, String iface) {
302        final int length = mObservers.beginBroadcast();
303        for (int i = 0; i < length; i++) {
304            try {
305                mObservers.getBroadcastItem(i).limitReached(limitName, iface);
306            } catch (RemoteException e) {
307            } catch (RuntimeException e) {
308            }
309        }
310        mObservers.finishBroadcast();
311    }
312
313    /**
314     * Notify our observers of a change in the data activity state of the interface
315     */
316    private void notifyInterfaceClassActivity(String label, boolean active) {
317        final int length = mObservers.beginBroadcast();
318        for (int i = 0; i < length; i++) {
319            try {
320                mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(label, active);
321            } catch (RemoteException e) {
322            } catch (RuntimeException e) {
323            }
324        }
325        mObservers.finishBroadcast();
326    }
327
328    /**
329     * Prepare native daemon once connected, enabling modules and pushing any
330     * existing in-memory rules.
331     */
332    private void prepareNativeDaemon() {
333        mBandwidthControlEnabled = false;
334
335        // only enable bandwidth control when support exists
336        final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
337        if (hasKernelSupport) {
338            Slog.d(TAG, "enabling bandwidth control");
339            try {
340                mConnector.execute("bandwidth", "enable");
341                mBandwidthControlEnabled = true;
342            } catch (NativeDaemonConnectorException e) {
343                Log.wtf(TAG, "problem enabling bandwidth controls", e);
344            }
345        } else {
346            Slog.d(TAG, "not enabling bandwidth control");
347        }
348
349        SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
350
351        if (mBandwidthControlEnabled) {
352            try {
353                IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME))
354                        .noteNetworkStatsEnabled();
355            } catch (RemoteException e) {
356            }
357        }
358
359        // push any existing quota or UID rules
360        synchronized (mQuotaLock) {
361            int size = mActiveQuotas.size();
362            if (size > 0) {
363                Slog.d(TAG, "pushing " + size + " active quota rules");
364                final HashMap<String, Long> activeQuotas = mActiveQuotas;
365                mActiveQuotas = Maps.newHashMap();
366                for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
367                    setInterfaceQuota(entry.getKey(), entry.getValue());
368                }
369            }
370
371            size = mActiveAlerts.size();
372            if (size > 0) {
373                Slog.d(TAG, "pushing " + size + " active alert rules");
374                final HashMap<String, Long> activeAlerts = mActiveAlerts;
375                mActiveAlerts = Maps.newHashMap();
376                for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
377                    setInterfaceAlert(entry.getKey(), entry.getValue());
378                }
379            }
380
381            size = mUidRejectOnQuota.size();
382            if (size > 0) {
383                Slog.d(TAG, "pushing " + size + " active uid rules");
384                final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
385                mUidRejectOnQuota = new SparseBooleanArray();
386                for (int i = 0; i < uidRejectOnQuota.size(); i++) {
387                    setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
388                }
389            }
390        }
391
392        // TODO: Push any existing firewall state
393        setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
394    }
395
396    //
397    // Netd Callback handling
398    //
399
400    private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
401        @Override
402        public void onDaemonConnected() {
403            // event is dispatched from internal NDC thread, so we prepare the
404            // daemon back on main thread.
405            if (mConnectedSignal != null) {
406                mConnectedSignal.countDown();
407                mConnectedSignal = null;
408            } else {
409                mMainHandler.post(new Runnable() {
410                    @Override
411                    public void run() {
412                        prepareNativeDaemon();
413                    }
414                });
415            }
416        }
417
418        @Override
419        public boolean onEvent(int code, String raw, String[] cooked) {
420            switch (code) {
421            case NetdResponseCode.InterfaceChange:
422                    /*
423                     * a network interface change occured
424                     * Format: "NNN Iface added <name>"
425                     *         "NNN Iface removed <name>"
426                     *         "NNN Iface changed <name> <up/down>"
427                     *         "NNN Iface linkstatus <name> <up/down>"
428                     */
429                    if (cooked.length < 4 || !cooked[1].equals("Iface")) {
430                        throw new IllegalStateException(
431                                String.format("Invalid event from daemon (%s)", raw));
432                    }
433                    if (cooked[2].equals("added")) {
434                        notifyInterfaceAdded(cooked[3]);
435                        return true;
436                    } else if (cooked[2].equals("removed")) {
437                        notifyInterfaceRemoved(cooked[3]);
438                        return true;
439                    } else if (cooked[2].equals("changed") && cooked.length == 5) {
440                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
441                        return true;
442                    } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
443                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
444                        return true;
445                    }
446                    throw new IllegalStateException(
447                            String.format("Invalid event from daemon (%s)", raw));
448                    // break;
449            case NetdResponseCode.BandwidthControl:
450                    /*
451                     * Bandwidth control needs some attention
452                     * Format: "NNN limit alert <alertName> <ifaceName>"
453                     */
454                    if (cooked.length < 5 || !cooked[1].equals("limit")) {
455                        throw new IllegalStateException(
456                                String.format("Invalid event from daemon (%s)", raw));
457                    }
458                    if (cooked[2].equals("alert")) {
459                        notifyLimitReached(cooked[3], cooked[4]);
460                        return true;
461                    }
462                    throw new IllegalStateException(
463                            String.format("Invalid event from daemon (%s)", raw));
464                    // break;
465            case NetdResponseCode.InterfaceClassActivity:
466                    /*
467                     * An network interface class state changed (active/idle)
468                     * Format: "NNN IfaceClass <active/idle> <label>"
469                     */
470                    if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
471                        throw new IllegalStateException(
472                                String.format("Invalid event from daemon (%s)", raw));
473                    }
474                    boolean isActive = cooked[2].equals("active");
475                    notifyInterfaceClassActivity(cooked[3], isActive);
476                    return true;
477                    // break;
478            default: break;
479            }
480            return false;
481        }
482    }
483
484
485    //
486    // INetworkManagementService members
487    //
488
489    @Override
490    public String[] listInterfaces() {
491        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
492        try {
493            return NativeDaemonEvent.filterMessageList(
494                    mConnector.executeForList("interface", "list"), InterfaceListResult);
495        } catch (NativeDaemonConnectorException e) {
496            throw e.rethrowAsParcelableException();
497        }
498    }
499
500    @Override
501    public InterfaceConfiguration getInterfaceConfig(String iface) {
502        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
503
504        final NativeDaemonEvent event;
505        try {
506            event = mConnector.execute("interface", "getcfg", iface);
507        } catch (NativeDaemonConnectorException e) {
508            throw e.rethrowAsParcelableException();
509        }
510
511        event.checkCode(InterfaceGetCfgResult);
512
513        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
514        final StringTokenizer st = new StringTokenizer(event.getMessage());
515
516        InterfaceConfiguration cfg;
517        try {
518            cfg = new InterfaceConfiguration();
519            cfg.setHardwareAddress(st.nextToken(" "));
520            InetAddress addr = null;
521            int prefixLength = 0;
522            try {
523                addr = NetworkUtils.numericToInetAddress(st.nextToken());
524            } catch (IllegalArgumentException iae) {
525                Slog.e(TAG, "Failed to parse ipaddr", iae);
526            }
527
528            try {
529                prefixLength = Integer.parseInt(st.nextToken());
530            } catch (NumberFormatException nfe) {
531                Slog.e(TAG, "Failed to parse prefixLength", nfe);
532            }
533
534            cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
535            while (st.hasMoreTokens()) {
536                cfg.setFlag(st.nextToken());
537            }
538        } catch (NoSuchElementException nsee) {
539            throw new IllegalStateException("Invalid response from daemon: " + event);
540        }
541        return cfg;
542    }
543
544    @Override
545    public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
546        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
547        LinkAddress linkAddr = cfg.getLinkAddress();
548        if (linkAddr == null || linkAddr.getAddress() == null) {
549            throw new IllegalStateException("Null LinkAddress given");
550        }
551
552        final Command cmd = new Command("interface", "setcfg", iface,
553                linkAddr.getAddress().getHostAddress(),
554                linkAddr.getNetworkPrefixLength());
555        for (String flag : cfg.getFlags()) {
556            cmd.appendArg(flag);
557        }
558
559        try {
560            mConnector.execute(cmd);
561        } catch (NativeDaemonConnectorException e) {
562            throw e.rethrowAsParcelableException();
563        }
564    }
565
566    @Override
567    public void setInterfaceDown(String iface) {
568        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
569        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
570        ifcg.setInterfaceDown();
571        setInterfaceConfig(iface, ifcg);
572    }
573
574    @Override
575    public void setInterfaceUp(String iface) {
576        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
577        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
578        ifcg.setInterfaceUp();
579        setInterfaceConfig(iface, ifcg);
580    }
581
582    @Override
583    public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
584        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
585        try {
586            mConnector.execute(
587                    "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
588        } catch (NativeDaemonConnectorException e) {
589            throw e.rethrowAsParcelableException();
590        }
591    }
592
593    /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
594       IPv6 addresses on interface down, but we need to do full clean up here */
595    @Override
596    public void clearInterfaceAddresses(String iface) {
597        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
598        try {
599            mConnector.execute("interface", "clearaddrs", iface);
600        } catch (NativeDaemonConnectorException e) {
601            throw e.rethrowAsParcelableException();
602        }
603    }
604
605    @Override
606    public void enableIpv6(String iface) {
607        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
608        try {
609            mConnector.execute("interface", "ipv6", iface, "enable");
610        } catch (NativeDaemonConnectorException e) {
611            throw e.rethrowAsParcelableException();
612        }
613    }
614
615    @Override
616    public void disableIpv6(String iface) {
617        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
618        try {
619            mConnector.execute("interface", "ipv6", iface, "disable");
620        } catch (NativeDaemonConnectorException e) {
621            throw e.rethrowAsParcelableException();
622        }
623    }
624
625    @Override
626    public void addRoute(String interfaceName, RouteInfo route) {
627        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
628        modifyRoute(interfaceName, ADD, route, DEFAULT);
629    }
630
631    @Override
632    public void removeRoute(String interfaceName, RouteInfo route) {
633        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
634        modifyRoute(interfaceName, REMOVE, route, DEFAULT);
635    }
636
637    @Override
638    public void addSecondaryRoute(String interfaceName, RouteInfo route) {
639        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
640        modifyRoute(interfaceName, ADD, route, SECONDARY);
641    }
642
643    @Override
644    public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
645        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
646        modifyRoute(interfaceName, REMOVE, route, SECONDARY);
647    }
648
649    private void modifyRoute(String interfaceName, String action, RouteInfo route, String type) {
650        final Command cmd = new Command("interface", "route", action, interfaceName, type);
651
652        // create triplet: dest-ip-addr prefixlength gateway-ip-addr
653        final LinkAddress la = route.getDestination();
654        cmd.appendArg(la.getAddress().getHostAddress());
655        cmd.appendArg(la.getNetworkPrefixLength());
656
657        if (route.getGateway() == null) {
658            if (la.getAddress() instanceof Inet4Address) {
659                cmd.appendArg("0.0.0.0");
660            } else {
661                cmd.appendArg("::0");
662            }
663        } else {
664            cmd.appendArg(route.getGateway().getHostAddress());
665        }
666
667        try {
668            mConnector.execute(cmd);
669        } catch (NativeDaemonConnectorException e) {
670            throw e.rethrowAsParcelableException();
671        }
672    }
673
674    private ArrayList<String> readRouteList(String filename) {
675        FileInputStream fstream = null;
676        ArrayList<String> list = new ArrayList<String>();
677
678        try {
679            fstream = new FileInputStream(filename);
680            DataInputStream in = new DataInputStream(fstream);
681            BufferedReader br = new BufferedReader(new InputStreamReader(in));
682            String s;
683
684            // throw away the title line
685
686            while (((s = br.readLine()) != null) && (s.length() != 0)) {
687                list.add(s);
688            }
689        } catch (IOException ex) {
690            // return current list, possibly empty
691        } finally {
692            if (fstream != null) {
693                try {
694                    fstream.close();
695                } catch (IOException ex) {}
696            }
697        }
698
699        return list;
700    }
701
702    @Override
703    public RouteInfo[] getRoutes(String interfaceName) {
704        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
705        ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
706
707        // v4 routes listed as:
708        // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
709        for (String s : readRouteList("/proc/net/route")) {
710            String[] fields = s.split("\t");
711
712            if (fields.length > 7) {
713                String iface = fields[0];
714
715                if (interfaceName.equals(iface)) {
716                    String dest = fields[1];
717                    String gate = fields[2];
718                    String flags = fields[3]; // future use?
719                    String mask = fields[7];
720                    try {
721                        // address stored as a hex string, ex: 0014A8C0
722                        InetAddress destAddr =
723                                NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
724                        int prefixLength =
725                                NetworkUtils.netmaskIntToPrefixLength(
726                                (int)Long.parseLong(mask, 16));
727                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
728
729                        // address stored as a hex string, ex 0014A8C0
730                        InetAddress gatewayAddr =
731                                NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
732
733                        RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
734                        routes.add(route);
735                    } catch (Exception e) {
736                        Log.e(TAG, "Error parsing route " + s + " : " + e);
737                        continue;
738                    }
739                }
740            }
741        }
742
743        // v6 routes listed as:
744        // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
745        for (String s : readRouteList("/proc/net/ipv6_route")) {
746            String[]fields = s.split("\\s+");
747            if (fields.length > 9) {
748                String iface = fields[9].trim();
749                if (interfaceName.equals(iface)) {
750                    String dest = fields[0];
751                    String prefix = fields[1];
752                    String gate = fields[4];
753
754                    try {
755                        // prefix length stored as a hex string, ex 40
756                        int prefixLength = Integer.parseInt(prefix, 16);
757
758                        // address stored as a 32 char hex string
759                        // ex fe800000000000000000000000000000
760                        InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
761                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
762
763                        InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
764
765                        RouteInfo route = new RouteInfo(linkAddress, gateAddr);
766                        routes.add(route);
767                    } catch (Exception e) {
768                        Log.e(TAG, "Error parsing route " + s + " : " + e);
769                        continue;
770                    }
771                }
772            }
773        }
774        return routes.toArray(new RouteInfo[routes.size()]);
775    }
776
777    @Override
778    public void shutdown() {
779        // TODO: remove from aidl if nobody calls externally
780        mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
781
782        Slog.d(TAG, "Shutting down");
783    }
784
785    @Override
786    public boolean getIpForwardingEnabled() throws IllegalStateException{
787        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
788
789        final NativeDaemonEvent event;
790        try {
791            event = mConnector.execute("ipfwd", "status");
792        } catch (NativeDaemonConnectorException e) {
793            throw e.rethrowAsParcelableException();
794        }
795
796        // 211 Forwarding enabled
797        event.checkCode(IpFwdStatusResult);
798        return event.getMessage().endsWith("enabled");
799    }
800
801    @Override
802    public void setIpForwardingEnabled(boolean enable) {
803        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
804        try {
805            mConnector.execute("ipfwd", enable ? "enable" : "disable");
806        } catch (NativeDaemonConnectorException e) {
807            throw e.rethrowAsParcelableException();
808        }
809    }
810
811    @Override
812    public void startTethering(String[] dhcpRange) {
813        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
814        // cmd is "tether start first_start first_stop second_start second_stop ..."
815        // an odd number of addrs will fail
816
817        final Command cmd = new Command("tether", "start");
818        for (String d : dhcpRange) {
819            cmd.appendArg(d);
820        }
821
822        try {
823            mConnector.execute(cmd);
824        } catch (NativeDaemonConnectorException e) {
825            throw e.rethrowAsParcelableException();
826        }
827    }
828
829    @Override
830    public void stopTethering() {
831        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
832        try {
833            mConnector.execute("tether", "stop");
834        } catch (NativeDaemonConnectorException e) {
835            throw e.rethrowAsParcelableException();
836        }
837    }
838
839    @Override
840    public boolean isTetheringStarted() {
841        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
842
843        final NativeDaemonEvent event;
844        try {
845            event = mConnector.execute("tether", "status");
846        } catch (NativeDaemonConnectorException e) {
847            throw e.rethrowAsParcelableException();
848        }
849
850        // 210 Tethering services started
851        event.checkCode(TetherStatusResult);
852        return event.getMessage().endsWith("started");
853    }
854
855    @Override
856    public void tetherInterface(String iface) {
857        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
858        try {
859            mConnector.execute("tether", "interface", "add", iface);
860        } catch (NativeDaemonConnectorException e) {
861            throw e.rethrowAsParcelableException();
862        }
863    }
864
865    @Override
866    public void untetherInterface(String iface) {
867        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
868        try {
869            mConnector.execute("tether", "interface", "remove", iface);
870        } catch (NativeDaemonConnectorException e) {
871            throw e.rethrowAsParcelableException();
872        }
873    }
874
875    @Override
876    public String[] listTetheredInterfaces() {
877        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
878        try {
879            return NativeDaemonEvent.filterMessageList(
880                    mConnector.executeForList("tether", "interface", "list"),
881                    TetherInterfaceListResult);
882        } catch (NativeDaemonConnectorException e) {
883            throw e.rethrowAsParcelableException();
884        }
885    }
886
887    @Override
888    public void setDnsForwarders(String[] dns) {
889        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
890
891        final Command cmd = new Command("tether", "dns", "set");
892        for (String s : dns) {
893            cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
894        }
895
896        try {
897            mConnector.execute(cmd);
898        } catch (NativeDaemonConnectorException e) {
899            throw e.rethrowAsParcelableException();
900        }
901    }
902
903    @Override
904    public String[] getDnsForwarders() {
905        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
906        try {
907            return NativeDaemonEvent.filterMessageList(
908                    mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
909        } catch (NativeDaemonConnectorException e) {
910            throw e.rethrowAsParcelableException();
911        }
912    }
913
914    private void modifyNat(String action, String internalInterface, String externalInterface)
915            throws SocketException {
916        final Command cmd = new Command("nat", action, internalInterface, externalInterface);
917
918        final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
919                internalInterface);
920        if (internalNetworkInterface == null) {
921            cmd.appendArg("0");
922        } else {
923            Collection<InterfaceAddress> interfaceAddresses = internalNetworkInterface
924                    .getInterfaceAddresses();
925            cmd.appendArg(interfaceAddresses.size());
926            for (InterfaceAddress ia : interfaceAddresses) {
927                InetAddress addr = NetworkUtils.getNetworkPart(
928                        ia.getAddress(), ia.getNetworkPrefixLength());
929                cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
930            }
931        }
932
933        try {
934            mConnector.execute(cmd);
935        } catch (NativeDaemonConnectorException e) {
936            throw e.rethrowAsParcelableException();
937        }
938    }
939
940    @Override
941    public void enableNat(String internalInterface, String externalInterface) {
942        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
943        try {
944            modifyNat("enable", internalInterface, externalInterface);
945        } catch (SocketException e) {
946            throw new IllegalStateException(e);
947        }
948    }
949
950    @Override
951    public void disableNat(String internalInterface, String externalInterface) {
952        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
953        try {
954            modifyNat("disable", internalInterface, externalInterface);
955        } catch (SocketException e) {
956            throw new IllegalStateException(e);
957        }
958    }
959
960    @Override
961    public String[] listTtys() {
962        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
963        try {
964            return NativeDaemonEvent.filterMessageList(
965                    mConnector.executeForList("list_ttys"), TtyListResult);
966        } catch (NativeDaemonConnectorException e) {
967            throw e.rethrowAsParcelableException();
968        }
969    }
970
971    @Override
972    public void attachPppd(
973            String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
974        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
975        try {
976            mConnector.execute("pppd", "attach", tty,
977                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
978                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
979                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
980                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
981        } catch (NativeDaemonConnectorException e) {
982            throw e.rethrowAsParcelableException();
983        }
984    }
985
986    @Override
987    public void detachPppd(String tty) {
988        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
989        try {
990            mConnector.execute("pppd", "detach", tty);
991        } catch (NativeDaemonConnectorException e) {
992            throw e.rethrowAsParcelableException();
993        }
994    }
995
996    @Override
997    public void startAccessPoint(
998            WifiConfiguration wifiConfig, String wlanIface) {
999        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1000        try {
1001            wifiFirmwareReload(wlanIface, "AP");
1002            if (wifiConfig == null) {
1003                mConnector.execute("softap", "set", wlanIface);
1004            } else {
1005                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1006                                   "broadcast", "6", getSecurityType(wifiConfig),
1007                                   new SensitiveArg(wifiConfig.preSharedKey));
1008            }
1009            mConnector.execute("softap", "startap");
1010        } catch (NativeDaemonConnectorException e) {
1011            throw e.rethrowAsParcelableException();
1012        }
1013    }
1014
1015    private static String getSecurityType(WifiConfiguration wifiConfig) {
1016        switch (wifiConfig.getAuthType()) {
1017            case KeyMgmt.WPA_PSK:
1018                return "wpa-psk";
1019            case KeyMgmt.WPA2_PSK:
1020                return "wpa2-psk";
1021            default:
1022                return "open";
1023        }
1024    }
1025
1026    /* @param mode can be "AP", "STA" or "P2P" */
1027    @Override
1028    public void wifiFirmwareReload(String wlanIface, String mode) {
1029        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1030        try {
1031            mConnector.execute("softap", "fwreload", wlanIface, mode);
1032        } catch (NativeDaemonConnectorException e) {
1033            throw e.rethrowAsParcelableException();
1034        }
1035    }
1036
1037    @Override
1038    public void stopAccessPoint(String wlanIface) {
1039        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1040        try {
1041            mConnector.execute("softap", "stopap");
1042            wifiFirmwareReload(wlanIface, "STA");
1043        } catch (NativeDaemonConnectorException e) {
1044            throw e.rethrowAsParcelableException();
1045        }
1046    }
1047
1048    @Override
1049    public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1050        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1051        try {
1052            if (wifiConfig == null) {
1053                mConnector.execute("softap", "set", wlanIface);
1054            } else {
1055                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1056                                   "broadcast", "6", getSecurityType(wifiConfig),
1057                                   new SensitiveArg(wifiConfig.preSharedKey));
1058            }
1059        } catch (NativeDaemonConnectorException e) {
1060            throw e.rethrowAsParcelableException();
1061        }
1062    }
1063
1064    @Override
1065    public void addIdleTimer(String iface, int timeout, String label) {
1066        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1067
1068        if (DBG) Slog.d(TAG, "Adding idletimer");
1069
1070        synchronized (mIdleTimerLock) {
1071            IdleTimerParams params = mActiveIdleTimers.get(iface);
1072            if (params != null) {
1073                // the interface already has idletimer, update network count
1074                params.networkCount++;
1075                return;
1076            }
1077
1078            try {
1079                mConnector.execute("idletimer", "add", iface, Integer.toString(timeout), label);
1080            } catch (NativeDaemonConnectorException e) {
1081                throw e.rethrowAsParcelableException();
1082            }
1083            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, label));
1084        }
1085    }
1086
1087    @Override
1088    public void removeIdleTimer(String iface) {
1089        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1090
1091        if (DBG) Slog.d(TAG, "Removing idletimer");
1092
1093        synchronized (mIdleTimerLock) {
1094            IdleTimerParams params = mActiveIdleTimers.get(iface);
1095            if (params == null || --(params.networkCount) > 0) {
1096                return;
1097            }
1098
1099            try {
1100                mConnector.execute("idletimer", "remove", iface,
1101                        Integer.toString(params.timeout), params.label);
1102            } catch (NativeDaemonConnectorException e) {
1103                throw e.rethrowAsParcelableException();
1104            }
1105            mActiveIdleTimers.remove(iface);
1106        }
1107    }
1108
1109    @Override
1110    public NetworkStats getNetworkStatsSummaryDev() {
1111        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1112        try {
1113            return mStatsFactory.readNetworkStatsSummaryDev();
1114        } catch (IOException e) {
1115            throw new IllegalStateException(e);
1116        }
1117    }
1118
1119    @Override
1120    public NetworkStats getNetworkStatsSummaryXt() {
1121        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1122        try {
1123            return mStatsFactory.readNetworkStatsSummaryXt();
1124        } catch (IOException e) {
1125            throw new IllegalStateException(e);
1126        }
1127    }
1128
1129    @Override
1130    public NetworkStats getNetworkStatsDetail() {
1131        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1132        try {
1133            return mStatsFactory.readNetworkStatsDetail(UID_ALL);
1134        } catch (IOException e) {
1135            throw new IllegalStateException(e);
1136        }
1137    }
1138
1139    @Override
1140    public void setInterfaceQuota(String iface, long quotaBytes) {
1141        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1142
1143        // silently discard when control disabled
1144        // TODO: eventually migrate to be always enabled
1145        if (!mBandwidthControlEnabled) return;
1146
1147        synchronized (mQuotaLock) {
1148            if (mActiveQuotas.containsKey(iface)) {
1149                throw new IllegalStateException("iface " + iface + " already has quota");
1150            }
1151
1152            try {
1153                // TODO: support quota shared across interfaces
1154                mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1155                mActiveQuotas.put(iface, quotaBytes);
1156            } catch (NativeDaemonConnectorException e) {
1157                throw e.rethrowAsParcelableException();
1158            }
1159        }
1160    }
1161
1162    @Override
1163    public void removeInterfaceQuota(String iface) {
1164        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1165
1166        // silently discard when control disabled
1167        // TODO: eventually migrate to be always enabled
1168        if (!mBandwidthControlEnabled) return;
1169
1170        synchronized (mQuotaLock) {
1171            if (!mActiveQuotas.containsKey(iface)) {
1172                // TODO: eventually consider throwing
1173                return;
1174            }
1175
1176            mActiveQuotas.remove(iface);
1177            mActiveAlerts.remove(iface);
1178
1179            try {
1180                // TODO: support quota shared across interfaces
1181                mConnector.execute("bandwidth", "removeiquota", iface);
1182            } catch (NativeDaemonConnectorException e) {
1183                throw e.rethrowAsParcelableException();
1184            }
1185        }
1186    }
1187
1188    @Override
1189    public void setInterfaceAlert(String iface, long alertBytes) {
1190        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1191
1192        // silently discard when control disabled
1193        // TODO: eventually migrate to be always enabled
1194        if (!mBandwidthControlEnabled) return;
1195
1196        // quick sanity check
1197        if (!mActiveQuotas.containsKey(iface)) {
1198            throw new IllegalStateException("setting alert requires existing quota on iface");
1199        }
1200
1201        synchronized (mQuotaLock) {
1202            if (mActiveAlerts.containsKey(iface)) {
1203                throw new IllegalStateException("iface " + iface + " already has alert");
1204            }
1205
1206            try {
1207                // TODO: support alert shared across interfaces
1208                mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1209                mActiveAlerts.put(iface, alertBytes);
1210            } catch (NativeDaemonConnectorException e) {
1211                throw e.rethrowAsParcelableException();
1212            }
1213        }
1214    }
1215
1216    @Override
1217    public void removeInterfaceAlert(String iface) {
1218        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1219
1220        // silently discard when control disabled
1221        // TODO: eventually migrate to be always enabled
1222        if (!mBandwidthControlEnabled) return;
1223
1224        synchronized (mQuotaLock) {
1225            if (!mActiveAlerts.containsKey(iface)) {
1226                // TODO: eventually consider throwing
1227                return;
1228            }
1229
1230            try {
1231                // TODO: support alert shared across interfaces
1232                mConnector.execute("bandwidth", "removeinterfacealert", iface);
1233                mActiveAlerts.remove(iface);
1234            } catch (NativeDaemonConnectorException e) {
1235                throw e.rethrowAsParcelableException();
1236            }
1237        }
1238    }
1239
1240    @Override
1241    public void setGlobalAlert(long alertBytes) {
1242        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1243
1244        // silently discard when control disabled
1245        // TODO: eventually migrate to be always enabled
1246        if (!mBandwidthControlEnabled) return;
1247
1248        try {
1249            mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1250        } catch (NativeDaemonConnectorException e) {
1251            throw e.rethrowAsParcelableException();
1252        }
1253    }
1254
1255    @Override
1256    public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1257        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1258
1259        // silently discard when control disabled
1260        // TODO: eventually migrate to be always enabled
1261        if (!mBandwidthControlEnabled) return;
1262
1263        synchronized (mQuotaLock) {
1264            final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1265            if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1266                // TODO: eventually consider throwing
1267                return;
1268            }
1269
1270            try {
1271                mConnector.execute("bandwidth",
1272                        rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
1273                if (rejectOnQuotaInterfaces) {
1274                    mUidRejectOnQuota.put(uid, true);
1275                } else {
1276                    mUidRejectOnQuota.delete(uid);
1277                }
1278            } catch (NativeDaemonConnectorException e) {
1279                throw e.rethrowAsParcelableException();
1280            }
1281        }
1282    }
1283
1284    @Override
1285    public boolean isBandwidthControlEnabled() {
1286        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1287        return mBandwidthControlEnabled;
1288    }
1289
1290    @Override
1291    public NetworkStats getNetworkStatsUidDetail(int uid) {
1292        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1293        try {
1294            return mStatsFactory.readNetworkStatsDetail(uid);
1295        } catch (IOException e) {
1296            throw new IllegalStateException(e);
1297        }
1298    }
1299
1300    @Override
1301    public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
1302        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1303
1304        if (ifacePairs.length % 2 != 0) {
1305            throw new IllegalArgumentException(
1306                    "unexpected ifacePairs; length=" + ifacePairs.length);
1307        }
1308
1309        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1310        for (int i = 0; i < ifacePairs.length; i += 2) {
1311            final String ifaceIn = ifacePairs[i];
1312            final String ifaceOut = ifacePairs[i + 1];
1313            if (ifaceIn != null && ifaceOut != null) {
1314                stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
1315            }
1316        }
1317        return stats;
1318    }
1319
1320    private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
1321        final NativeDaemonEvent event;
1322        try {
1323            event = mConnector.execute("bandwidth", "gettetherstats", ifaceIn, ifaceOut);
1324        } catch (NativeDaemonConnectorException e) {
1325            throw e.rethrowAsParcelableException();
1326        }
1327
1328        event.checkCode(TetheringStatsResult);
1329
1330        // 221 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1331        final StringTokenizer tok = new StringTokenizer(event.getMessage());
1332        tok.nextToken();
1333        tok.nextToken();
1334
1335        try {
1336            final NetworkStats.Entry entry = new NetworkStats.Entry();
1337            entry.iface = ifaceIn;
1338            entry.uid = UID_TETHERING;
1339            entry.set = SET_DEFAULT;
1340            entry.tag = TAG_NONE;
1341            entry.rxBytes = Long.parseLong(tok.nextToken());
1342            entry.rxPackets = Long.parseLong(tok.nextToken());
1343            entry.txBytes = Long.parseLong(tok.nextToken());
1344            entry.txPackets = Long.parseLong(tok.nextToken());
1345            return entry;
1346        } catch (NumberFormatException e) {
1347            throw new IllegalStateException(
1348                    "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
1349        }
1350    }
1351
1352    @Override
1353    public void setDefaultInterfaceForDns(String iface) {
1354        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1355        try {
1356            mConnector.execute("resolver", "setdefaultif", iface);
1357        } catch (NativeDaemonConnectorException e) {
1358            throw e.rethrowAsParcelableException();
1359        }
1360    }
1361
1362    @Override
1363    public void setDnsServersForInterface(String iface, String[] servers, String domains) {
1364        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1365
1366        final Command cmd = new Command("resolver", "setifdns", iface,
1367                (domains == null ? "" : domains));
1368
1369        for (String s : servers) {
1370            InetAddress a = NetworkUtils.numericToInetAddress(s);
1371            if (a.isAnyLocalAddress() == false) {
1372                cmd.appendArg(a.getHostAddress());
1373            }
1374        }
1375
1376        try {
1377            mConnector.execute(cmd);
1378        } catch (NativeDaemonConnectorException e) {
1379            throw e.rethrowAsParcelableException();
1380        }
1381    }
1382
1383    @Override
1384    public void setUidRangeRoute(String iface, int uid_start, int uid_end) {
1385        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1386        try {
1387            mConnector.execute("interface", "fwmark",
1388                    "uid", "add", iface, uid_start, uid_end);
1389        } catch (NativeDaemonConnectorException e) {
1390            throw e.rethrowAsParcelableException();
1391        }
1392    }
1393
1394    @Override
1395    public void clearUidRangeRoute(String iface, int uid_start, int uid_end) {
1396        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1397        try {
1398            mConnector.execute("interface", "fwmark",
1399                    "uid", "remove", iface, uid_start, uid_end);
1400        } catch (NativeDaemonConnectorException e) {
1401            throw e.rethrowAsParcelableException();
1402        }
1403    }
1404
1405    @Override
1406    public void setMarkedForwarding(String iface) {
1407        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1408        try {
1409            mConnector.execute("interface", "fwmark", "rule", "add", iface);
1410        } catch (NativeDaemonConnectorException e) {
1411            throw e.rethrowAsParcelableException();
1412        }
1413    }
1414
1415    @Override
1416    public void clearMarkedForwarding(String iface) {
1417        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1418        try {
1419            mConnector.execute("interface", "fwmark", "rule", "remove", iface);
1420        } catch (NativeDaemonConnectorException e) {
1421            throw e.rethrowAsParcelableException();
1422        }
1423    }
1424
1425    @Override
1426    public int getMarkForUid(int uid) {
1427        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1428        final NativeDaemonEvent event;
1429        try {
1430            event = mConnector.execute("interface", "fwmark", "get", "mark", uid);
1431        } catch (NativeDaemonConnectorException e) {
1432            throw e.rethrowAsParcelableException();
1433        }
1434        event.checkCode(GetMarkResult);
1435        return Integer.parseInt(event.getMessage());
1436    }
1437
1438    @Override
1439    public int getMarkForProtect() {
1440        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1441        final NativeDaemonEvent event;
1442        try {
1443            event = mConnector.execute("interface", "fwmark", "get", "protect");
1444        } catch (NativeDaemonConnectorException e) {
1445            throw e.rethrowAsParcelableException();
1446        }
1447        event.checkCode(GetMarkResult);
1448        return Integer.parseInt(event.getMessage());
1449    }
1450
1451    @Override
1452    public void setMarkedForwardingRoute(String iface, RouteInfo route) {
1453        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1454        try {
1455            LinkAddress dest = route.getDestination();
1456            mConnector.execute("interface", "fwmark", "route", "add", iface,
1457                    dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
1458        } catch (NativeDaemonConnectorException e) {
1459            throw e.rethrowAsParcelableException();
1460        }
1461    }
1462
1463    @Override
1464    public void clearMarkedForwardingRoute(String iface, RouteInfo route) {
1465        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1466        try {
1467            LinkAddress dest = route.getDestination();
1468            mConnector.execute("interface", "fwmark", "route", "remove", iface,
1469                    dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
1470        } catch (NativeDaemonConnectorException e) {
1471            throw e.rethrowAsParcelableException();
1472        }
1473    }
1474
1475    @Override
1476    public void setHostExemption(LinkAddress host) {
1477        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1478        try {
1479            mConnector.execute("interface", "fwmark", "exempt", "add", host);
1480        } catch (NativeDaemonConnectorException e) {
1481            throw e.rethrowAsParcelableException();
1482        }
1483    }
1484
1485    @Override
1486    public void clearHostExemption(LinkAddress host) {
1487        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1488        try {
1489            mConnector.execute("interface", "fwmark", "exempt", "remove", host);
1490        } catch (NativeDaemonConnectorException e) {
1491            throw e.rethrowAsParcelableException();
1492        }
1493    }
1494
1495    @Override
1496    public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
1497        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1498        try {
1499            mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end);
1500        } catch (NativeDaemonConnectorException e) {
1501            throw e.rethrowAsParcelableException();
1502        }
1503    }
1504
1505    @Override
1506    public void clearDnsInterfaceForUidRange(int uid_start, int uid_end) {
1507        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1508        try {
1509            mConnector.execute("resolver", "clearifaceforuidrange", uid_start, uid_end);
1510        } catch (NativeDaemonConnectorException e) {
1511            throw e.rethrowAsParcelableException();
1512        }
1513    }
1514
1515    @Override
1516    public void clearDnsInterfaceMaps() {
1517        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1518        try {
1519            mConnector.execute("resolver", "clearifacemapping");
1520        } catch (NativeDaemonConnectorException e) {
1521            throw e.rethrowAsParcelableException();
1522        }
1523    }
1524
1525
1526    @Override
1527    public void flushDefaultDnsCache() {
1528        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1529        try {
1530            mConnector.execute("resolver", "flushdefaultif");
1531        } catch (NativeDaemonConnectorException e) {
1532            throw e.rethrowAsParcelableException();
1533        }
1534    }
1535
1536    @Override
1537    public void flushInterfaceDnsCache(String iface) {
1538        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1539        try {
1540            mConnector.execute("resolver", "flushif", iface);
1541        } catch (NativeDaemonConnectorException e) {
1542            throw e.rethrowAsParcelableException();
1543        }
1544    }
1545
1546    @Override
1547    public void setFirewallEnabled(boolean enabled) {
1548        enforceSystemUid();
1549        try {
1550            mConnector.execute("firewall", enabled ? "enable" : "disable");
1551            mFirewallEnabled = enabled;
1552        } catch (NativeDaemonConnectorException e) {
1553            throw e.rethrowAsParcelableException();
1554        }
1555    }
1556
1557    @Override
1558    public boolean isFirewallEnabled() {
1559        enforceSystemUid();
1560        return mFirewallEnabled;
1561    }
1562
1563    @Override
1564    public void setFirewallInterfaceRule(String iface, boolean allow) {
1565        enforceSystemUid();
1566        Preconditions.checkState(mFirewallEnabled);
1567        final String rule = allow ? ALLOW : DENY;
1568        try {
1569            mConnector.execute("firewall", "set_interface_rule", iface, rule);
1570        } catch (NativeDaemonConnectorException e) {
1571            throw e.rethrowAsParcelableException();
1572        }
1573    }
1574
1575    @Override
1576    public void setFirewallEgressSourceRule(String addr, boolean allow) {
1577        enforceSystemUid();
1578        Preconditions.checkState(mFirewallEnabled);
1579        final String rule = allow ? ALLOW : DENY;
1580        try {
1581            mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
1582        } catch (NativeDaemonConnectorException e) {
1583            throw e.rethrowAsParcelableException();
1584        }
1585    }
1586
1587    @Override
1588    public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
1589        enforceSystemUid();
1590        Preconditions.checkState(mFirewallEnabled);
1591        final String rule = allow ? ALLOW : DENY;
1592        try {
1593            mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
1594        } catch (NativeDaemonConnectorException e) {
1595            throw e.rethrowAsParcelableException();
1596        }
1597    }
1598
1599    @Override
1600    public void setFirewallUidRule(int uid, boolean allow) {
1601        enforceSystemUid();
1602        Preconditions.checkState(mFirewallEnabled);
1603        final String rule = allow ? ALLOW : DENY;
1604        try {
1605            mConnector.execute("firewall", "set_uid_rule", uid, rule);
1606        } catch (NativeDaemonConnectorException e) {
1607            throw e.rethrowAsParcelableException();
1608        }
1609    }
1610
1611    private static void enforceSystemUid() {
1612        final int uid = Binder.getCallingUid();
1613        if (uid != Process.SYSTEM_UID) {
1614            throw new SecurityException("Only available to AID_SYSTEM");
1615        }
1616    }
1617
1618    @Override
1619    public void setDnsInterfaceForPid(String iface, int pid) throws IllegalStateException {
1620        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1621        try {
1622            mConnector.execute("resolver", "setifaceforpid", iface, pid);
1623        } catch (NativeDaemonConnectorException e) {
1624            throw new IllegalStateException(
1625                    "Error communicating with native deamon to set interface for pid" + iface, e);
1626        }
1627    }
1628
1629    @Override
1630    public void clearDnsInterfaceForPid(int pid) throws IllegalStateException {
1631        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1632        try {
1633            mConnector.execute("resolver", "clearifaceforpid", pid);
1634        } catch (NativeDaemonConnectorException e) {
1635            throw new IllegalStateException(
1636                    "Error communicating with native deamon to clear interface for pid " + pid, e);
1637        }
1638    }
1639
1640    @Override
1641    public void startClatd(String interfaceName) throws IllegalStateException {
1642        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1643
1644        try {
1645            mConnector.execute("clatd", "start", interfaceName);
1646        } catch (NativeDaemonConnectorException e) {
1647            throw e.rethrowAsParcelableException();
1648        }
1649    }
1650
1651    @Override
1652    public void stopClatd() throws IllegalStateException {
1653        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1654
1655        try {
1656            mConnector.execute("clatd", "stop");
1657        } catch (NativeDaemonConnectorException e) {
1658            throw e.rethrowAsParcelableException();
1659        }
1660    }
1661
1662    @Override
1663    public boolean isClatdStarted() {
1664        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1665
1666        final NativeDaemonEvent event;
1667        try {
1668            event = mConnector.execute("clatd", "status");
1669        } catch (NativeDaemonConnectorException e) {
1670            throw e.rethrowAsParcelableException();
1671        }
1672
1673        event.checkCode(ClatdStatusResult);
1674        return event.getMessage().endsWith("started");
1675    }
1676
1677    /** {@inheritDoc} */
1678    @Override
1679    public void monitor() {
1680        if (mConnector != null) {
1681            mConnector.monitor();
1682        }
1683    }
1684
1685    @Override
1686    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1687        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1688
1689        pw.println("NetworkManagementService NativeDaemonConnector Log:");
1690        mConnector.dump(fd, pw, args);
1691        pw.println();
1692
1693        pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
1694
1695        synchronized (mQuotaLock) {
1696            pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1697            pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
1698        }
1699
1700        synchronized (mUidRejectOnQuota) {
1701            pw.print("UID reject on quota ifaces: [");
1702            final int size = mUidRejectOnQuota.size();
1703            for (int i = 0; i < size; i++) {
1704                pw.print(mUidRejectOnQuota.keyAt(i));
1705                if (i < size - 1) pw.print(",");
1706            }
1707            pw.println("]");
1708        }
1709
1710        pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
1711    }
1712}
1713