• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.android.networkstack.tethering.util;
17 
18 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
19 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
21 import static android.net.NetworkCapabilities.TRANSPORT_USB;
22 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
23 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
24 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
25 import static android.net.TetheringManager.TETHERING_ETHERNET;
26 import static android.net.TetheringManager.TETHERING_NCM;
27 import static android.net.TetheringManager.TETHERING_USB;
28 import static android.net.TetheringManager.TETHERING_VIRTUAL;
29 import static android.net.TetheringManager.TETHERING_WIFI;
30 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
31 import static android.net.TetheringManager.TETHERING_WIGIG;
32 
33 import android.net.TetherStatsParcel;
34 import android.net.TetheringManager.TetheringRequest;
35 import android.util.Log;
36 
37 import androidx.annotation.NonNull;
38 
39 import com.android.net.module.util.JniUtil;
40 import com.android.net.module.util.bpf.TetherStatsValue;
41 
42 import java.io.FileDescriptor;
43 import java.net.Inet6Address;
44 import java.net.SocketException;
45 import java.net.UnknownHostException;
46 import java.util.Arrays;
47 
48 /**
49  * The classes and the methods for tethering utilization.
50  *
51  * {@hide}
52  */
53 public class TetheringUtils {
54     static {
getTetheringJniLibraryName()55         System.loadLibrary(getTetheringJniLibraryName());
56     }
57 
58     public static final byte[] ALL_NODES = new byte[] {
59         (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
60     };
61 
62     /** The name should be com_android_networkstack_tethering_util_jni. */
getTetheringJniLibraryName()63     public static String getTetheringJniLibraryName() {
64         return JniUtil.getJniLibraryName(TetheringUtils.class.getPackage());
65     }
66 
67     /**
68      * Configures a socket for receiving and sending ICMPv6 neighbor advertisments.
69      * @param fd the socket's {@link FileDescriptor}.
70      */
setupNaSocket(FileDescriptor fd)71     public static native void setupNaSocket(FileDescriptor fd)
72             throws SocketException;
73 
74     /**
75      * Configures a socket for receiving and sending ICMPv6 neighbor solicitations.
76      * @param fd the socket's {@link FileDescriptor}.
77      */
setupNsSocket(FileDescriptor fd)78     public static native void setupNsSocket(FileDescriptor fd)
79             throws SocketException;
80 
81     /**
82      *  The object which records offload Tx/Rx forwarded bytes/packets.
83      *  TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
84      *  this class as well.
85      */
86     public static class ForwardedStats {
87         public final long rxBytes;
88         public final long rxPackets;
89         public final long txBytes;
90         public final long txPackets;
91 
ForwardedStats()92         public ForwardedStats() {
93             rxBytes = 0;
94             rxPackets = 0;
95             txBytes = 0;
96             txPackets = 0;
97         }
98 
ForwardedStats(long rxBytes, long txBytes)99         public ForwardedStats(long rxBytes, long txBytes) {
100             this.rxBytes = rxBytes;
101             this.rxPackets = 0;
102             this.txBytes = txBytes;
103             this.txPackets = 0;
104         }
105 
ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets)106         public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) {
107             this.rxBytes = rxBytes;
108             this.rxPackets = rxPackets;
109             this.txBytes = txBytes;
110             this.txPackets = txPackets;
111         }
112 
ForwardedStats(@onNull TetherStatsParcel tetherStats)113         public ForwardedStats(@NonNull TetherStatsParcel tetherStats) {
114             rxBytes = tetherStats.rxBytes;
115             rxPackets = tetherStats.rxPackets;
116             txBytes = tetherStats.txBytes;
117             txPackets = tetherStats.txPackets;
118         }
119 
ForwardedStats(@onNull TetherStatsValue tetherStats)120         public ForwardedStats(@NonNull TetherStatsValue tetherStats) {
121             rxBytes = tetherStats.rxBytes;
122             rxPackets = tetherStats.rxPackets;
123             txBytes = tetherStats.txBytes;
124             txPackets = tetherStats.txPackets;
125         }
126 
ForwardedStats(@onNull ForwardedStats other)127         public ForwardedStats(@NonNull ForwardedStats other) {
128             rxBytes = other.rxBytes;
129             rxPackets = other.rxPackets;
130             txBytes = other.txBytes;
131             txPackets = other.txPackets;
132         }
133 
134         /** Add Tx/Rx bytes/packets and return the result as a new object. */
135         @NonNull
add(@onNull ForwardedStats other)136         public ForwardedStats add(@NonNull ForwardedStats other) {
137             return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets,
138                     txBytes + other.txBytes, txPackets + other.txPackets);
139         }
140 
141         /** Subtract Tx/Rx bytes/packets and return the result as a new object. */
142         @NonNull
subtract(@onNull ForwardedStats other)143         public ForwardedStats subtract(@NonNull ForwardedStats other) {
144             // TODO: Perhaps throw an exception if any negative difference value just in case.
145             final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0);
146             final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0);
147             final long txBytesDiff = Math.max(txBytes - other.txBytes, 0);
148             final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0);
149             return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff);
150         }
151 
152         /** Returns the string representation of this object. */
153         @NonNull
toString()154         public String toString() {
155             return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes,
156                     rxPackets, txBytes, txPackets);
157         }
158     }
159 
160     /**
161      * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
162      * @param fd the socket's {@link FileDescriptor}.
163      * @param ifIndex the interface index.
164      */
setupRaSocket(FileDescriptor fd, int ifIndex)165     public static native void setupRaSocket(FileDescriptor fd, int ifIndex)
166             throws SocketException;
167 
168     /**
169      * Read s as an unsigned 16-bit integer.
170      */
uint16(short s)171     public static int uint16(short s) {
172         return s & 0xffff;
173     }
174 
175     /** Get inet6 address for all nodes given scope ID. */
getAllNodesForScopeId(int scopeId)176     public static Inet6Address getAllNodesForScopeId(int scopeId) {
177         try {
178             return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
179         } catch (UnknownHostException uhe) {
180             Log.wtf("TetheringUtils", "Failed to construct Inet6Address from "
181                     + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId);
182             return null;
183         }
184     }
185 
186     /**
187      * Create a legacy tethering request for calls to the legacy tether() API, which doesn't take an
188      * explicit request. These are always CONNECTIVITY_SCOPE_GLOBAL, per historical behavior.
189      */
190     @NonNull
createLegacyGlobalScopeTetheringRequest(int type)191     public static TetheringRequest createLegacyGlobalScopeTetheringRequest(int type) {
192         final TetheringRequest request = new TetheringRequest.Builder(type).build();
193         request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY;
194         request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
195         return request;
196     }
197 
198     /**
199      * Create a local-only implicit tethering request. This is used for Wifi local-only hotspot and
200      * Wifi P2P, which start tethering based on the WIFI_(AP/P2P)_STATE_CHANGED broadcasts.
201      */
202     @NonNull
createImplicitLocalOnlyTetheringRequest(int type)203     public static TetheringRequest createImplicitLocalOnlyTetheringRequest(int type) {
204         final TetheringRequest request = new TetheringRequest.Builder(type).build();
205         request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_IMPLICIT;
206         request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_LOCAL;
207         return request;
208     }
209 
210     /**
211      * Create a placeholder request. This is used in case we try to find a pending request but there
212      * is none (e.g. stopTethering removed a pending request), or for cases where we only have the
213      * tethering type (e.g. stopTethering(int)).
214      */
215     @NonNull
createPlaceholderRequest(int type)216     public static TetheringRequest createPlaceholderRequest(int type) {
217         final TetheringRequest request = new TetheringRequest.Builder(type).build();
218         request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_PLACEHOLDER;
219         request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
220         return request;
221     }
222 
223     /**
224      * Returns the transport type for the given interface type.
225      *
226      * @param interfaceType The interface type.
227      * @return The transport type.
228      * @throws IllegalArgumentException if the interface type is invalid.
229      */
getTransportTypeForTetherableType(int interfaceType)230     public static int getTransportTypeForTetherableType(int interfaceType) {
231         switch (interfaceType) {
232             case TETHERING_WIFI:
233             case TETHERING_WIGIG:
234             case TETHERING_WIFI_P2P:
235                 return TRANSPORT_WIFI;
236             case TETHERING_USB:
237             case TETHERING_NCM:
238                 return TRANSPORT_USB;
239             case TETHERING_BLUETOOTH:
240                 return TRANSPORT_BLUETOOTH;
241             case TETHERING_ETHERNET:
242             case TETHERING_VIRTUAL: // For virtual machines.
243                 return TRANSPORT_ETHERNET;
244             default:
245                 throw new IllegalArgumentException("Invalid interface type: " + interfaceType);
246         }
247     }
248 }
249