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 android.net.util; 17 18 import android.net.TetherStatsParcel; 19 import android.net.TetheringRequestParcel; 20 import android.util.Log; 21 22 import androidx.annotation.NonNull; 23 24 import com.android.networkstack.tethering.TetherStatsValue; 25 26 import java.io.FileDescriptor; 27 import java.net.Inet6Address; 28 import java.net.SocketException; 29 import java.net.UnknownHostException; 30 import java.util.Arrays; 31 import java.util.Objects; 32 33 /** 34 * The classes and the methods for tethering utilization. 35 * 36 * {@hide} 37 */ 38 public class TetheringUtils { 39 static { 40 System.loadLibrary("tetherutilsjni"); 41 } 42 43 public static final byte[] ALL_NODES = new byte[] { 44 (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 45 }; 46 47 /** 48 * Configures a socket for receiving and sending ICMPv6 neighbor advertisments. 49 * @param fd the socket's {@link FileDescriptor}. 50 */ setupNaSocket(FileDescriptor fd)51 public static native void setupNaSocket(FileDescriptor fd) 52 throws SocketException; 53 54 /** 55 * Configures a socket for receiving and sending ICMPv6 neighbor solicitations. 56 * @param fd the socket's {@link FileDescriptor}. 57 */ setupNsSocket(FileDescriptor fd)58 public static native void setupNsSocket(FileDescriptor fd) 59 throws SocketException; 60 61 /** 62 * The object which records offload Tx/Rx forwarded bytes/packets. 63 * TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with 64 * this class as well. 65 */ 66 public static class ForwardedStats { 67 public final long rxBytes; 68 public final long rxPackets; 69 public final long txBytes; 70 public final long txPackets; 71 ForwardedStats()72 public ForwardedStats() { 73 rxBytes = 0; 74 rxPackets = 0; 75 txBytes = 0; 76 txPackets = 0; 77 } 78 ForwardedStats(long rxBytes, long txBytes)79 public ForwardedStats(long rxBytes, long txBytes) { 80 this.rxBytes = rxBytes; 81 this.rxPackets = 0; 82 this.txBytes = txBytes; 83 this.txPackets = 0; 84 } 85 ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets)86 public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) { 87 this.rxBytes = rxBytes; 88 this.rxPackets = rxPackets; 89 this.txBytes = txBytes; 90 this.txPackets = txPackets; 91 } 92 ForwardedStats(@onNull TetherStatsParcel tetherStats)93 public ForwardedStats(@NonNull TetherStatsParcel tetherStats) { 94 rxBytes = tetherStats.rxBytes; 95 rxPackets = tetherStats.rxPackets; 96 txBytes = tetherStats.txBytes; 97 txPackets = tetherStats.txPackets; 98 } 99 ForwardedStats(@onNull TetherStatsValue tetherStats)100 public ForwardedStats(@NonNull TetherStatsValue tetherStats) { 101 rxBytes = tetherStats.rxBytes; 102 rxPackets = tetherStats.rxPackets; 103 txBytes = tetherStats.txBytes; 104 txPackets = tetherStats.txPackets; 105 } 106 ForwardedStats(@onNull ForwardedStats other)107 public ForwardedStats(@NonNull ForwardedStats other) { 108 rxBytes = other.rxBytes; 109 rxPackets = other.rxPackets; 110 txBytes = other.txBytes; 111 txPackets = other.txPackets; 112 } 113 114 /** Add Tx/Rx bytes/packets and return the result as a new object. */ 115 @NonNull add(@onNull ForwardedStats other)116 public ForwardedStats add(@NonNull ForwardedStats other) { 117 return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets, 118 txBytes + other.txBytes, txPackets + other.txPackets); 119 } 120 121 /** Subtract Tx/Rx bytes/packets and return the result as a new object. */ 122 @NonNull subtract(@onNull ForwardedStats other)123 public ForwardedStats subtract(@NonNull ForwardedStats other) { 124 // TODO: Perhaps throw an exception if any negative difference value just in case. 125 final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0); 126 final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0); 127 final long txBytesDiff = Math.max(txBytes - other.txBytes, 0); 128 final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0); 129 return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff); 130 } 131 132 /** Returns the string representation of this object. */ 133 @NonNull toString()134 public String toString() { 135 return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes, 136 rxPackets, txBytes, txPackets); 137 } 138 } 139 140 /** 141 * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. 142 * @param fd the socket's {@link FileDescriptor}. 143 * @param ifIndex the interface index. 144 */ setupRaSocket(FileDescriptor fd, int ifIndex)145 public static native void setupRaSocket(FileDescriptor fd, int ifIndex) 146 throws SocketException; 147 148 /** 149 * Read s as an unsigned 16-bit integer. 150 */ uint16(short s)151 public static int uint16(short s) { 152 return s & 0xffff; 153 } 154 155 /** Check whether two TetheringRequestParcels are the same. */ isTetheringRequestEquals(final TetheringRequestParcel request, final TetheringRequestParcel otherRequest)156 public static boolean isTetheringRequestEquals(final TetheringRequestParcel request, 157 final TetheringRequestParcel otherRequest) { 158 if (request == otherRequest) return true; 159 160 return request != null && otherRequest != null 161 && request.tetheringType == otherRequest.tetheringType 162 && Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address) 163 && Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress) 164 && request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck 165 && request.showProvisioningUi == otherRequest.showProvisioningUi 166 && request.connectivityScope == otherRequest.connectivityScope; 167 } 168 169 /** Get inet6 address for all nodes given scope ID. */ getAllNodesForScopeId(int scopeId)170 public static Inet6Address getAllNodesForScopeId(int scopeId) { 171 try { 172 return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId); 173 } catch (UnknownHostException uhe) { 174 Log.wtf("TetheringUtils", "Failed to construct Inet6Address from " 175 + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId); 176 return null; 177 } 178 } 179 } 180