1 /* 2 * Copyright 2017 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 android.net; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 25 import android.os.Build; 26 27 import androidx.test.filters.SmallTest; 28 29 import com.android.net.module.util.MacAddressUtils; 30 import com.android.testutils.DevSdkIgnoreRule; 31 import com.android.testutils.DevSdkIgnoreRunner; 32 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 36 import java.net.Inet6Address; 37 import java.util.Arrays; 38 import java.util.Random; 39 40 @SmallTest 41 @RunWith(DevSdkIgnoreRunner.class) 42 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 43 public class MacAddressTest { 44 45 static class AddrTypeTestCase { 46 byte[] addr; 47 int expectedType; 48 of(int expectedType, int... addr)49 static AddrTypeTestCase of(int expectedType, int... addr) { 50 AddrTypeTestCase t = new AddrTypeTestCase(); 51 t.expectedType = expectedType; 52 t.addr = toByteArray(addr); 53 return t; 54 } 55 } 56 57 @Test testMacAddrTypes()58 public void testMacAddrTypes() { 59 AddrTypeTestCase[] testcases = { 60 AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN), 61 AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 0), 62 AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5), 63 AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5, 6, 7), 64 AddrTypeTestCase.of(MacAddress.TYPE_UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0), 65 AddrTypeTestCase.of(MacAddress.TYPE_BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), 66 AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 1, 2, 3, 4, 5, 6), 67 AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 11, 22, 33, 44, 55, 66), 68 AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd) 69 }; 70 71 for (AddrTypeTestCase t : testcases) { 72 int got = MacAddress.macAddressType(t.addr); 73 String msg = String.format("expected type of %s to be %s, but got %s", 74 Arrays.toString(t.addr), t.expectedType, got); 75 assertEquals(msg, t.expectedType, got); 76 77 if (got != MacAddress.TYPE_UNKNOWN) { 78 assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType()); 79 } 80 } 81 } 82 83 @Test testToOuiString()84 public void testToOuiString() { 85 String[][] macs = { 86 {"07:00:d3:56:8a:c4", "07:00:d3"}, 87 {"33:33:aa:bb:cc:dd", "33:33:aa"}, 88 {"06:00:00:00:00:00", "06:00:00"}, 89 {"07:00:d3:56:8a:c4", "07:00:d3"} 90 }; 91 92 for (String[] pair : macs) { 93 String mac = pair[0]; 94 String expected = pair[1]; 95 assertEquals(expected, MacAddress.fromString(mac).toOuiString()); 96 } 97 } 98 99 @Test testHexPaddingWhenPrinting()100 public void testHexPaddingWhenPrinting() { 101 String[] macs = { 102 "07:00:d3:56:8a:c4", 103 "33:33:aa:bb:cc:dd", 104 "06:00:00:00:00:00", 105 "07:00:d3:56:8a:c4" 106 }; 107 108 for (String mac : macs) { 109 assertEquals(mac, MacAddress.fromString(mac).toString()); 110 assertEquals(mac, 111 MacAddress.stringAddrFromByteAddr(MacAddress.byteAddrFromStringAddr(mac))); 112 } 113 } 114 115 @Test testIsMulticastAddress()116 public void testIsMulticastAddress() { 117 MacAddress[] multicastAddresses = { 118 MacAddress.BROADCAST_ADDRESS, 119 MacAddress.fromString("07:00:d3:56:8a:c4"), 120 MacAddress.fromString("33:33:aa:bb:cc:dd"), 121 }; 122 MacAddress[] unicastAddresses = { 123 MacAddress.ALL_ZEROS_ADDRESS, 124 MacAddress.fromString("00:01:44:55:66:77"), 125 MacAddress.fromString("08:00:22:33:44:55"), 126 MacAddress.fromString("06:00:00:00:00:00"), 127 }; 128 129 for (MacAddress mac : multicastAddresses) { 130 String msg = mac.toString() + " expected to be a multicast address"; 131 assertTrue(msg, MacAddressUtils.isMulticastAddress(mac)); 132 } 133 for (MacAddress mac : unicastAddresses) { 134 String msg = mac.toString() + " expected not to be a multicast address"; 135 assertFalse(msg, MacAddressUtils.isMulticastAddress(mac)); 136 } 137 } 138 139 @Test testIsLocallyAssignedAddress()140 public void testIsLocallyAssignedAddress() { 141 MacAddress[] localAddresses = { 142 MacAddress.fromString("06:00:00:00:00:00"), 143 MacAddress.fromString("07:00:d3:56:8a:c4"), 144 MacAddress.fromString("33:33:aa:bb:cc:dd"), 145 }; 146 MacAddress[] universalAddresses = { 147 MacAddress.fromString("00:01:44:55:66:77"), 148 MacAddress.fromString("08:00:22:33:44:55"), 149 }; 150 151 for (MacAddress mac : localAddresses) { 152 String msg = mac.toString() + " expected to be a locally assigned address"; 153 assertTrue(msg, mac.isLocallyAssigned()); 154 } 155 for (MacAddress mac : universalAddresses) { 156 String msg = mac.toString() + " expected not to be globally unique address"; 157 assertFalse(msg, mac.isLocallyAssigned()); 158 } 159 } 160 161 @Test testMacAddressConversions()162 public void testMacAddressConversions() { 163 final int iterations = 10000; 164 for (int i = 0; i < iterations; i++) { 165 MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); 166 167 String stringRepr = mac.toString(); 168 byte[] bytesRepr = mac.toByteArray(); 169 170 assertEquals(mac, MacAddress.fromString(stringRepr)); 171 assertEquals(mac, MacAddress.fromBytes(bytesRepr)); 172 173 assertEquals(mac, MacAddress.fromString(MacAddress.stringAddrFromByteAddr(bytesRepr))); 174 assertEquals(mac, MacAddress.fromBytes(MacAddress.byteAddrFromStringAddr(stringRepr))); 175 } 176 } 177 178 @Test testMacAddressRandomGeneration()179 public void testMacAddressRandomGeneration() { 180 final int iterations = 1000; 181 final String expectedAndroidOui = "da:a1:19"; 182 for (int i = 0; i < iterations; i++) { 183 MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase(); 184 String stringRepr = mac.toString(); 185 186 assertTrue(stringRepr + " expected to be a locally assigned address", 187 mac.isLocallyAssigned()); 188 assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui, 189 stringRepr.startsWith(expectedAndroidOui)); 190 } 191 192 final Random r = new Random(); 193 final String anotherOui = "24:5f:78"; 194 final String expectedLocalOui = "26:5f:78"; 195 final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0"); 196 for (int i = 0; i < iterations; i++) { 197 MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r); 198 String stringRepr = mac.toString(); 199 200 assertTrue(stringRepr + " expected to be a locally assigned address", 201 mac.isLocallyAssigned()); 202 assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType()); 203 assertTrue(stringRepr + " expected to begin with " + expectedLocalOui, 204 stringRepr.startsWith(expectedLocalOui)); 205 } 206 207 for (int i = 0; i < iterations; i++) { 208 MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); 209 String stringRepr = mac.toString(); 210 211 assertTrue(stringRepr + " expected to be a locally assigned address", 212 mac.isLocallyAssigned()); 213 assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType()); 214 } 215 } 216 217 @Test testConstructorInputValidation()218 public void testConstructorInputValidation() { 219 String[] invalidStringAddresses = { 220 "", 221 "abcd", 222 "1:2:3:4:5", 223 "1:2:3:4:5:6:7", 224 "10000:2:3:4:5:6", 225 }; 226 227 for (String s : invalidStringAddresses) { 228 try { 229 MacAddress mac = MacAddress.fromString(s); 230 fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac); 231 } catch (IllegalArgumentException excepted) { 232 } 233 } 234 235 try { 236 MacAddress mac = MacAddress.fromString(null); 237 fail("MacAddress.fromString(null) should have failed, but returned " + mac); 238 } catch (NullPointerException excepted) { 239 } 240 241 byte[][] invalidBytesAddresses = { 242 {}, 243 {1,2,3,4,5}, 244 {1,2,3,4,5,6,7}, 245 }; 246 247 for (byte[] b : invalidBytesAddresses) { 248 try { 249 MacAddress mac = MacAddress.fromBytes(b); 250 fail("MacAddress.fromBytes(" + Arrays.toString(b) 251 + ") should have failed, but returned " + mac); 252 } catch (IllegalArgumentException excepted) { 253 } 254 } 255 256 try { 257 MacAddress mac = MacAddress.fromBytes(null); 258 fail("MacAddress.fromBytes(null) should have failed, but returned " + mac); 259 } catch (NullPointerException excepted) { 260 } 261 } 262 263 @Test testMatches()264 public void testMatches() { 265 // match 4 bytes prefix 266 assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( 267 MacAddress.fromString("aa:bb:cc:dd:00:00"), 268 MacAddress.fromString("ff:ff:ff:ff:00:00"))); 269 270 // match bytes 0,1,2 and 5 271 assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( 272 MacAddress.fromString("aa:bb:cc:00:00:11"), 273 MacAddress.fromString("ff:ff:ff:00:00:ff"))); 274 275 // match 34 bit prefix 276 assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( 277 MacAddress.fromString("aa:bb:cc:dd:c0:00"), 278 MacAddress.fromString("ff:ff:ff:ff:c0:00"))); 279 280 // fail to match 36 bit prefix 281 assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( 282 MacAddress.fromString("aa:bb:cc:dd:40:00"), 283 MacAddress.fromString("ff:ff:ff:ff:f0:00"))); 284 285 // match all 6 bytes 286 assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( 287 MacAddress.fromString("aa:bb:cc:dd:ee:11"), 288 MacAddress.fromString("ff:ff:ff:ff:ff:ff"))); 289 290 // match none of 6 bytes 291 assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( 292 MacAddress.fromString("00:00:00:00:00:00"), 293 MacAddress.fromString("00:00:00:00:00:00"))); 294 } 295 296 /** 297 * Tests that link-local address generation from MAC is valid. 298 */ 299 @Test testLinkLocalFromMacGeneration()300 public void testLinkLocalFromMacGeneration() { 301 MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f"); 302 byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74, 303 (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f}; 304 Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac(); 305 assertTrue(llv6.isLinkLocalAddress()); 306 assertArrayEquals(inet6ll, llv6.getAddress()); 307 } 308 toByteArray(int... in)309 static byte[] toByteArray(int... in) { 310 byte[] out = new byte[in.length]; 311 for (int i = 0; i < in.length; i++) { 312 out[i] = (byte) in[i]; 313 } 314 return out; 315 } 316 } 317