1 /*
2  * Copyright (C) 2014 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 
17 package com.android.server.ethernet;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
20 import static android.net.NetworkCapabilities.TRANSPORT_TEST;
21 
22 import android.annotation.CheckResult;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.content.Context;
26 import android.content.pm.PackageManager;
27 import android.net.EthernetNetworkSpecifier;
28 import android.net.EthernetNetworkUpdateRequest;
29 import android.net.IEthernetManager;
30 import android.net.IEthernetServiceListener;
31 import android.net.INetworkInterfaceOutcomeReceiver;
32 import android.net.ITetheredInterfaceCallback;
33 import android.net.IpConfiguration;
34 import android.net.NetworkCapabilities;
35 import android.net.NetworkSpecifier;
36 import android.os.Handler;
37 import android.os.RemoteException;
38 import android.util.Log;
39 import android.util.PrintWriterPrinter;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.util.IndentingPrintWriter;
43 import com.android.net.module.util.PermissionUtils;
44 
45 import java.io.FileDescriptor;
46 import java.io.PrintWriter;
47 import java.util.List;
48 import java.util.Objects;
49 import java.util.concurrent.atomic.AtomicBoolean;
50 
51 /**
52  * EthernetServiceImpl handles remote Ethernet operation requests by implementing
53  * the IEthernetManager interface.
54  */
55 public class EthernetServiceImpl extends IEthernetManager.Stub {
56     private static final String TAG = "EthernetServiceImpl";
57 
58     @VisibleForTesting
59     final AtomicBoolean mStarted = new AtomicBoolean(false);
60     private final Context mContext;
61     private final Handler mHandler;
62     private final EthernetTracker mTracker;
63 
EthernetServiceImpl(@onNull final Context context, @NonNull final Handler handler, @NonNull final EthernetTracker tracker)64     EthernetServiceImpl(@NonNull final Context context, @NonNull final Handler handler,
65             @NonNull final EthernetTracker tracker) {
66         mContext = context;
67         mHandler = handler;
68         mTracker = tracker;
69     }
70 
enforceAutomotiveDevice(final @NonNull String methodName)71     private void enforceAutomotiveDevice(final @NonNull String methodName) {
72         PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE,
73                 methodName + " is only available on automotive devices.");
74     }
75 
76     @CheckResult
hasUseRestrictedNetworksPermission()77     private boolean hasUseRestrictedNetworksPermission() {
78         return PermissionUtils.hasAnyPermissionOf(mContext,
79                 android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS);
80     }
81 
start()82     public void start() {
83         Log.i(TAG, "Starting Ethernet service");
84         mTracker.start();
85         mStarted.set(true);
86     }
87 
throwIfEthernetNotStarted()88     private void throwIfEthernetNotStarted() {
89         if (!mStarted.get()) {
90             throw new IllegalStateException("System isn't ready to change ethernet configurations");
91         }
92     }
93 
94     @Override
getAvailableInterfaces()95     public String[] getAvailableInterfaces() throws RemoteException {
96         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
97         return mTracker.getClientModeInterfaces(hasUseRestrictedNetworksPermission());
98     }
99 
100     /**
101      * Get Ethernet configuration
102      * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
103      */
104     @Override
getConfiguration(String iface)105     public IpConfiguration getConfiguration(String iface) {
106         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
107         if (mTracker.isRestrictedInterface(iface)) {
108             PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
109         }
110 
111         return new IpConfiguration(mTracker.getIpConfiguration(iface));
112     }
113 
114     /**
115      * Set Ethernet configuration
116      */
117     @Override
setConfiguration(String iface, IpConfiguration config)118     public void setConfiguration(String iface, IpConfiguration config) {
119         throwIfEthernetNotStarted();
120 
121         PermissionUtils.enforceNetworkStackPermission(mContext);
122         if (mTracker.isRestrictedInterface(iface)) {
123             PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
124         }
125 
126         // TODO: this does not check proxy settings, gateways, etc.
127         // Fix this by making IpConfiguration a complete representation of static configuration.
128         mTracker.updateIpConfiguration(iface, new IpConfiguration(config));
129     }
130 
131     /**
132      * Indicates whether given interface is available.
133      */
134     @Override
isAvailable(String iface)135     public boolean isAvailable(String iface) {
136         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
137         if (mTracker.isRestrictedInterface(iface)) {
138             PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
139         }
140 
141         return mTracker.isTrackingInterface(iface);
142     }
143 
144     /**
145      * Adds a listener.
146      * @param listener A {@link IEthernetServiceListener} to add.
147      */
addListener(IEthernetServiceListener listener)148     public void addListener(IEthernetServiceListener listener) throws RemoteException {
149         Objects.requireNonNull(listener, "listener must not be null");
150         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
151         mTracker.addListener(listener, hasUseRestrictedNetworksPermission());
152     }
153 
154     /**
155      * Removes a listener.
156      * @param listener A {@link IEthernetServiceListener} to remove.
157      */
removeListener(IEthernetServiceListener listener)158     public void removeListener(IEthernetServiceListener listener) {
159         if (listener == null) {
160             throw new IllegalArgumentException("listener must not be null");
161         }
162         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
163         mTracker.removeListener(listener);
164     }
165 
166     @Override
setIncludeTestInterfaces(boolean include)167     public void setIncludeTestInterfaces(boolean include) {
168         PermissionUtils.enforceNetworkStackPermissionOr(mContext,
169                 android.Manifest.permission.NETWORK_SETTINGS);
170         mTracker.setIncludeTestInterfaces(include);
171     }
172 
173     @Override
requestTetheredInterface(ITetheredInterfaceCallback callback)174     public void requestTetheredInterface(ITetheredInterfaceCallback callback) {
175         Objects.requireNonNull(callback, "callback must not be null");
176         PermissionUtils.enforceNetworkStackPermissionOr(mContext,
177                 android.Manifest.permission.NETWORK_SETTINGS);
178         mTracker.requestTetheredInterface(callback);
179     }
180 
181     @Override
releaseTetheredInterface(ITetheredInterfaceCallback callback)182     public void releaseTetheredInterface(ITetheredInterfaceCallback callback) {
183         Objects.requireNonNull(callback, "callback must not be null");
184         PermissionUtils.enforceNetworkStackPermissionOr(mContext,
185                 android.Manifest.permission.NETWORK_SETTINGS);
186         mTracker.releaseTetheredInterface(callback);
187     }
188 
189     @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)190     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
191         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
192         if (!PermissionUtils.hasDumpPermission(mContext, TAG, pw)) return;
193 
194         pw.println("Current Ethernet state: ");
195         pw.increaseIndent();
196         mTracker.dump(fd, pw, args);
197         pw.decreaseIndent();
198 
199         pw.println("Handler:");
200         pw.increaseIndent();
201         mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
202         pw.decreaseIndent();
203     }
204 
enforceNetworkManagementPermission()205     private void enforceNetworkManagementPermission() {
206         mContext.enforceCallingOrSelfPermission(
207                 android.Manifest.permission.MANAGE_ETHERNET_NETWORKS,
208                 "EthernetServiceImpl");
209     }
210 
enforceManageTestNetworksPermission()211     private void enforceManageTestNetworksPermission() {
212         mContext.enforceCallingOrSelfPermission(
213                 android.Manifest.permission.MANAGE_TEST_NETWORKS,
214                 "EthernetServiceImpl");
215     }
216 
validateOrSetNetworkSpecifier(String iface, NetworkCapabilities nc)217     private void validateOrSetNetworkSpecifier(String iface, NetworkCapabilities nc) {
218         final NetworkSpecifier spec = nc.getNetworkSpecifier();
219         if (spec == null) {
220             nc.setNetworkSpecifier(new EthernetNetworkSpecifier(iface));
221             return;
222         }
223         if (!(spec instanceof EthernetNetworkSpecifier)) {
224             throw new IllegalArgumentException("Invalid specifier type for request.");
225         }
226         if (!((EthernetNetworkSpecifier) spec).getInterfaceName().matches(iface)) {
227             throw new IllegalArgumentException("Invalid interface name set on specifier.");
228         }
229     }
230 
maybeValidateTestCapabilities(String iface, NetworkCapabilities nc)231     private void maybeValidateTestCapabilities(String iface, NetworkCapabilities nc) {
232         if (!mTracker.isValidTestInterface(iface)) {
233             return;
234         }
235         if (!nc.hasTransport(TRANSPORT_TEST)) {
236             throw new IllegalArgumentException(
237                     "Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST.");
238         }
239     }
240 
maybeValidateEthernetTransport(String iface, NetworkCapabilities nc)241     private void maybeValidateEthernetTransport(String iface, NetworkCapabilities nc) {
242         if (mTracker.isValidTestInterface(iface)) {
243             return;
244         }
245         if (!nc.hasSingleTransport(TRANSPORT_ETHERNET)) {
246             throw new IllegalArgumentException("Invalid transport type for request.");
247         }
248     }
249 
enforceAdminPermission(final String iface, boolean enforceAutomotive, final String logMessage)250     private void enforceAdminPermission(final String iface, boolean enforceAutomotive,
251             final String logMessage) {
252         if (mTracker.isValidTestInterface(iface)) {
253             enforceManageTestNetworksPermission();
254         } else {
255             enforceNetworkManagementPermission();
256             if (enforceAutomotive) {
257                 enforceAutomotiveDevice(logMessage);
258             }
259         }
260     }
261 
262     @Override
updateConfiguration(@onNull final String iface, @NonNull final EthernetNetworkUpdateRequest request, @Nullable final INetworkInterfaceOutcomeReceiver cb)263     public void updateConfiguration(@NonNull final String iface,
264             @NonNull final EthernetNetworkUpdateRequest request,
265             @Nullable final INetworkInterfaceOutcomeReceiver cb) {
266         Objects.requireNonNull(iface);
267         Objects.requireNonNull(request);
268         throwIfEthernetNotStarted();
269 
270         // TODO: validate that iface is listed in overlay config_ethernet_interfaces
271         // only automotive devices are allowed to set the NetworkCapabilities using this API
272         final NetworkCapabilities nc = request.getNetworkCapabilities();
273         enforceAdminPermission(
274                 iface, nc != null, "updateConfiguration() with non-null capabilities");
275         if (nc != null) {
276             validateOrSetNetworkSpecifier(iface, nc);
277             maybeValidateTestCapabilities(iface, nc);
278             maybeValidateEthernetTransport(iface, nc);
279         }
280 
281         mTracker.updateConfiguration(
282                 iface, request.getIpConfiguration(), nc, new EthernetCallback(cb));
283     }
284 
285     @Override
enableInterface(@onNull final String iface, @Nullable final INetworkInterfaceOutcomeReceiver cb)286     public void enableInterface(@NonNull final String iface,
287             @Nullable final INetworkInterfaceOutcomeReceiver cb) {
288         Log.i(TAG, "enableInterface called with: iface=" + iface + ", cb=" + cb);
289         Objects.requireNonNull(iface);
290         throwIfEthernetNotStarted();
291 
292         enforceAdminPermission(iface, false, "enableInterface()");
293 
294         mTracker.setInterfaceEnabled(iface, true /* enabled */, new EthernetCallback(cb));
295     }
296 
297     @Override
disableInterface(@onNull final String iface, @Nullable final INetworkInterfaceOutcomeReceiver cb)298     public void disableInterface(@NonNull final String iface,
299             @Nullable final INetworkInterfaceOutcomeReceiver cb) {
300         Log.i(TAG, "disableInterface called with: iface=" + iface + ", cb=" + cb);
301         Objects.requireNonNull(iface);
302         throwIfEthernetNotStarted();
303 
304         enforceAdminPermission(iface, false, "disableInterface()");
305 
306         mTracker.setInterfaceEnabled(iface, false /* enabled */, new EthernetCallback(cb));
307     }
308 
309     @Override
setEthernetEnabled(boolean enabled)310     public void setEthernetEnabled(boolean enabled) {
311         PermissionUtils.enforceNetworkStackPermissionOr(mContext,
312                 android.Manifest.permission.NETWORK_SETTINGS);
313 
314         mTracker.setEthernetEnabled(enabled);
315     }
316 
317     @Override
getInterfaceList()318     public List<String> getInterfaceList() {
319         PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
320         return mTracker.getInterfaceList();
321     }
322 }
323