| /* |
| * Copyright 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.util; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.net.MacAddress; |
| |
| import java.security.SecureRandom; |
| import java.util.Arrays; |
| import java.util.Objects; |
| import java.util.Random; |
| |
| /** |
| * Collection of MAC address utilities. |
| * @hide |
| */ |
| public final class MacAddressUtils { |
| |
| private static final long VALID_LONG_MASK = (1L << 48) - 1; |
| private static final long LOCALLY_ASSIGNED_MASK = longAddrFromByteAddr( |
| MacAddress.fromString("2:0:0:0:0:0").toByteArray()); |
| private static final long MULTICAST_MASK = longAddrFromByteAddr( |
| MacAddress.fromString("1:0:0:0:0:0").toByteArray()); |
| private static final long OUI_MASK = longAddrFromByteAddr( |
| MacAddress.fromString("ff:ff:ff:0:0:0").toByteArray()); |
| private static final long NIC_MASK = longAddrFromByteAddr( |
| MacAddress.fromString("0:0:0:ff:ff:ff").toByteArray()); |
| // Matches WifiInfo.DEFAULT_MAC_ADDRESS |
| private static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; |
| private static final int ETHER_ADDR_LEN = 6; |
| |
| /** |
| * @return true if this MacAddress is a multicast address. |
| */ |
| public static boolean isMulticastAddress(@NonNull MacAddress address) { |
| return (longAddrFromByteAddr(address.toByteArray()) & MULTICAST_MASK) != 0; |
| } |
| |
| /** |
| * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the |
| * unicast bit, are randomly selected. |
| * |
| * The locally assigned bit is always set to 1. The multicast bit is always set to 0. |
| * |
| * @return a random locally assigned, unicast MacAddress. |
| */ |
| public static @NonNull MacAddress createRandomUnicastAddress() { |
| return createRandomUnicastAddress(null, new SecureRandom()); |
| } |
| |
| /** |
| * Returns a randomly generated MAC address using the given Random object and the same |
| * OUI values as the given MacAddress. |
| * |
| * The locally assigned bit is always set to 1. The multicast bit is always set to 0. |
| * |
| * @param base a base MacAddress whose OUI is used for generating the random address. |
| * If base == null then the OUI will also be randomized. |
| * @param r a standard Java Random object used for generating the random address. |
| * @return a random locally assigned MacAddress. |
| */ |
| public static @NonNull MacAddress createRandomUnicastAddress(@Nullable MacAddress base, |
| @NonNull Random r) { |
| long addr; |
| |
| if (base == null) { |
| addr = r.nextLong() & VALID_LONG_MASK; |
| } else { |
| addr = (longAddrFromByteAddr(base.toByteArray()) & OUI_MASK) |
| | (NIC_MASK & r.nextLong()); |
| } |
| addr |= LOCALLY_ASSIGNED_MASK; |
| addr &= ~MULTICAST_MASK; |
| MacAddress mac = MacAddress.fromBytes(byteAddrFromLongAddr(addr)); |
| if (mac.equals(DEFAULT_MAC_ADDRESS)) { |
| return createRandomUnicastAddress(base, r); |
| } |
| return mac; |
| } |
| |
| /** |
| * Convert a byte address to long address. |
| */ |
| public static long longAddrFromByteAddr(byte[] addr) { |
| Objects.requireNonNull(addr); |
| if (!isMacAddress(addr)) { |
| throw new IllegalArgumentException( |
| Arrays.toString(addr) + " was not a valid MAC address"); |
| } |
| long longAddr = 0; |
| for (byte b : addr) { |
| final int uint8Byte = b & 0xff; |
| longAddr = (longAddr << 8) + uint8Byte; |
| } |
| return longAddr; |
| } |
| |
| /** |
| * Convert a long address to byte address. |
| */ |
| public static byte[] byteAddrFromLongAddr(long addr) { |
| byte[] bytes = new byte[ETHER_ADDR_LEN]; |
| int index = ETHER_ADDR_LEN; |
| while (index-- > 0) { |
| bytes[index] = (byte) addr; |
| addr = addr >> 8; |
| } |
| return bytes; |
| } |
| |
| /** |
| * Returns true if the given byte array is a valid MAC address. |
| * A valid byte array representation for a MacAddress is a non-null array of length 6. |
| * |
| * @param addr a byte array. |
| * @return true if the given byte array is not null and has the length of a MAC address. |
| * |
| */ |
| public static boolean isMacAddress(byte[] addr) { |
| return addr != null && addr.length == ETHER_ADDR_LEN; |
| } |
| } |