1 /* 2 * Copyright 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 17 package com.android.net.module.util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.net.MacAddress; 22 23 import java.security.SecureRandom; 24 import java.util.Arrays; 25 import java.util.Objects; 26 import java.util.Random; 27 28 /** 29 * Collection of MAC address utilities. 30 * @hide 31 */ 32 public final class MacAddressUtils { 33 34 private static final long VALID_LONG_MASK = (1L << 48) - 1; 35 private static final long LOCALLY_ASSIGNED_MASK = longAddrFromByteAddr( 36 MacAddress.fromString("2:0:0:0:0:0").toByteArray()); 37 private static final long MULTICAST_MASK = longAddrFromByteAddr( 38 MacAddress.fromString("1:0:0:0:0:0").toByteArray()); 39 private static final long OUI_MASK = longAddrFromByteAddr( 40 MacAddress.fromString("ff:ff:ff:0:0:0").toByteArray()); 41 private static final long NIC_MASK = longAddrFromByteAddr( 42 MacAddress.fromString("0:0:0:ff:ff:ff").toByteArray()); 43 // Matches WifiInfo.DEFAULT_MAC_ADDRESS 44 private static final MacAddress DEFAULT_MAC_ADDRESS = 45 MacAddress.fromString("02:00:00:00:00:00"); 46 private static final int ETHER_ADDR_LEN = 6; 47 48 /** 49 * @return true if this MacAddress is a multicast address. 50 */ isMulticastAddress(@onNull MacAddress address)51 public static boolean isMulticastAddress(@NonNull MacAddress address) { 52 return (longAddrFromByteAddr(address.toByteArray()) & MULTICAST_MASK) != 0; 53 } 54 55 /** 56 * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the 57 * unicast bit, are randomly selected. 58 * 59 * The locally assigned bit is always set to 1. The multicast bit is always set to 0. 60 * 61 * @return a random locally assigned, unicast MacAddress. 62 */ createRandomUnicastAddress()63 public static @NonNull MacAddress createRandomUnicastAddress() { 64 return createRandomUnicastAddress(null, new SecureRandom()); 65 } 66 67 /** 68 * Returns a randomly generated MAC address using the given Random object and the same 69 * OUI values as the given MacAddress. 70 * 71 * The locally assigned bit is always set to 1. The multicast bit is always set to 0. 72 * 73 * @param base a base MacAddress whose OUI is used for generating the random address. 74 * If base == null then the OUI will also be randomized. 75 * @param r a standard Java Random object used for generating the random address. 76 * @return a random locally assigned MacAddress. 77 */ createRandomUnicastAddress(@ullable MacAddress base, @NonNull Random r)78 public static @NonNull MacAddress createRandomUnicastAddress(@Nullable MacAddress base, 79 @NonNull Random r) { 80 long addr; 81 82 if (base == null) { 83 addr = r.nextLong() & VALID_LONG_MASK; 84 } else { 85 addr = (longAddrFromByteAddr(base.toByteArray()) & OUI_MASK) 86 | (NIC_MASK & r.nextLong()); 87 } 88 addr |= LOCALLY_ASSIGNED_MASK; 89 addr &= ~MULTICAST_MASK; 90 MacAddress mac = MacAddress.fromBytes(byteAddrFromLongAddr(addr)); 91 if (mac.equals(DEFAULT_MAC_ADDRESS)) { 92 return createRandomUnicastAddress(base, r); 93 } 94 return mac; 95 } 96 97 /** 98 * Convert a byte address to long address. 99 */ longAddrFromByteAddr(byte[] addr)100 public static long longAddrFromByteAddr(byte[] addr) { 101 Objects.requireNonNull(addr); 102 if (!isMacAddress(addr)) { 103 throw new IllegalArgumentException( 104 Arrays.toString(addr) + " was not a valid MAC address"); 105 } 106 long longAddr = 0; 107 for (byte b : addr) { 108 final int uint8Byte = b & 0xff; 109 longAddr = (longAddr << 8) + uint8Byte; 110 } 111 return longAddr; 112 } 113 114 /** 115 * Convert a long address to byte address. 116 */ byteAddrFromLongAddr(long addr)117 public static byte[] byteAddrFromLongAddr(long addr) { 118 byte[] bytes = new byte[ETHER_ADDR_LEN]; 119 int index = ETHER_ADDR_LEN; 120 while (index-- > 0) { 121 bytes[index] = (byte) addr; 122 addr = addr >> 8; 123 } 124 return bytes; 125 } 126 127 /** 128 * Returns true if the given byte array is a valid MAC address. 129 * A valid byte array representation for a MacAddress is a non-null array of length 6. 130 * 131 * @param addr a byte array. 132 * @return true if the given byte array is not null and has the length of a MAC address. 133 * 134 */ isMacAddress(byte[] addr)135 public static boolean isMacAddress(byte[] addr) { 136 return addr != null && addr.length == ETHER_ADDR_LEN; 137 } 138 } 139