Add IPv6 link-local address generation from EUI-48

Add a utility method to convert an EUI-48 to an IPv6 link-local
address based on RFC 4291 (EUI-64 generation) followed by RFC 4862.

Bug: 117605977
Test: atest MacAddressTest
Merged-In: I80b683e69da6beff3b37fc345fc15aa9610d09b7
Change-Id: I80b683e69da6beff3b37fc345fc15aa9610d09b7
This commit is contained in:
Etan Cohen
2018-11-02 15:07:20 -07:00
parent 822d2b5991
commit ec1c466cb0
2 changed files with 51 additions and 3 deletions

View File

@@ -18,6 +18,7 @@ package android.net;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@@ -27,6 +28,8 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
@@ -393,4 +396,34 @@ public final class MacAddress implements Parcelable {
} }
return out; return out;
} }
/**
* Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted
* to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local
* IPv6 address per RFC 4862.
*
* @return A link-local Inet6Address constructed from the MAC address.
* @hide
*/
public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() {
byte[] macEui48Bytes = toByteArray();
byte[] addr = new byte[16];
addr[0] = (byte) 0xfe;
addr[1] = (byte) 0x80;
addr[8] = (byte) (macEui48Bytes[0] ^ (byte) 0x02); // flip the link-local bit
addr[9] = macEui48Bytes[1];
addr[10] = macEui48Bytes[2];
addr[11] = (byte) 0xff;
addr[12] = (byte) 0xfe;
addr[13] = macEui48Bytes[3];
addr[14] = macEui48Bytes[4];
addr[15] = macEui48Bytes[5];
try {
return Inet6Address.getByAddress(null, addr, 0);
} catch (UnknownHostException e) {
return null;
}
}
} }

View File

@@ -16,6 +16,7 @@
package android.net; package android.net;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@@ -24,12 +25,13 @@ import static org.junit.Assert.fail;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import java.util.Arrays;
import java.util.Random;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import java.net.Inet6Address;
import java.util.Arrays;
import java.util.Random;
@SmallTest @SmallTest
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class MacAddressTest { public class MacAddressTest {
@@ -252,6 +254,19 @@ public class MacAddressTest {
} }
} }
/**
* Tests that link-local address generation from MAC is valid.
*/
@Test
public void testLinkLocalFromMacGeneration() {
MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74,
(byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
assertTrue(llv6.isLinkLocalAddress());
assertArrayEquals(inet6ll, llv6.getAddress());
}
static byte[] toByteArray(int... in) { static byte[] toByteArray(int... in) {
byte[] out = new byte[in.length]; byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) { for (int i = 0; i < in.length; i++) {