Home | History | Annotate | Download | only in tethering
      1 /*
      2  * Copyright (C) 2018 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.connectivity.tethering;
     18 
     19 import android.annotation.Nullable;
     20 import android.net.LinkProperties;
     21 import android.net.NetworkCapabilities;
     22 import android.net.NetworkState;
     23 import android.net.RouteInfo;
     24 import android.net.util.InterfaceSet;
     25 
     26 import java.net.Inet4Address;
     27 import java.net.Inet6Address;
     28 import java.net.InetAddress;
     29 
     30 /**
     31  * @hide
     32  */
     33 public final class TetheringInterfaceUtils {
     34     /**
     35      * Get upstream interfaces for tethering based on default routes for IPv4/IPv6.
     36      * @return null if there is no usable interface, or a set of at least one interface otherwise.
     37      */
     38     public static @Nullable InterfaceSet getTetheringInterfaces(NetworkState ns) {
     39         if (ns == null) {
     40             return null;
     41         }
     42 
     43         final LinkProperties lp = ns.linkProperties;
     44         final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY);
     45         final String if6 = getIPv6Interface(ns);
     46 
     47         return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6);
     48     }
     49 
     50     /**
     51      * Get the upstream interface for IPv6 tethering.
     52      * @return null if there is no usable interface, or the interface name otherwise.
     53      */
     54     public static @Nullable String getIPv6Interface(NetworkState ns) {
     55         // Broadly speaking:
     56         //
     57         //     [1] does the upstream have an IPv6 default route?
     58         //
     59         // and
     60         //
     61         //     [2] does the upstream have one or more global IPv6 /64s
     62         //         dedicated to this device?
     63         //
     64         // In lieu of Prefix Delegation and other evaluation of whether a
     65         // prefix may or may not be dedicated to this device, for now just
     66         // check whether the upstream is TRANSPORT_CELLULAR. This works
     67         // because "[t]he 3GPP network allocates each default bearer a unique
     68         // /64 prefix", per RFC 6459, Section 5.2.
     69         final boolean canTether =
     70                 (ns != null) && (ns.network != null) &&
     71                 (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
     72                 // At least one upstream DNS server:
     73                 ns.linkProperties.hasIPv6DnsServer() &&
     74                 // Minimal amount of IPv6 provisioning:
     75                 ns.linkProperties.hasGlobalIPv6Address() &&
     76                 // Temporary approximation of "dedicated prefix":
     77                 ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
     78 
     79         return canTether
     80                 ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY)
     81                 : null;
     82     }
     83 
     84     private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
     85         final RouteInfo ri = (lp != null)
     86                 ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
     87                 : null;
     88         return (ri != null) ? ri.getInterface() : null;
     89     }
     90 }
     91