Rev 21 | Rev 23 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 21 | Rev 22 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * MAC (EUI-48 and EUI-64) utils for PHP |
4 | * MAC (EUI-48 and EUI-64) utils for PHP |
5 | * Copyright 2017 - 2023 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2017 - 2023 Daniel Marschall, ViaThinkSoft |
6 | * Version 2023-05-04 |
6 | * Version 2023-05-05 |
7 | * |
7 | * |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | * you may not use this file except in compliance with the License. |
9 | * you may not use this file except in compliance with the License. |
10 | * You may obtain a copy of the License at |
10 | * You may obtain a copy of the License at |
11 | * |
11 | * |
Line 110... | Line 110... | ||
110 | 110 | ||
111 | $x = explode("\n", $x); |
111 | $x = explode("\n", $x); |
112 | 112 | ||
113 | $ra_len = strlen(dechex($end-$beg)); |
113 | $ra_len = strlen(dechex($end-$beg)); |
114 | 114 | ||
115 | $out = sprintf("%-32s 0x%s\n", "IEEE $oui_name part:", substr($mac, 0, 12-$ra_len)); |
115 | $out = sprintf("%-32s 0x%s\n", "IEEE $oui_name:", substr($mac, 0, 12-$ra_len)); |
116 | $out .= sprintf("%-32s 0x%s\n", "NIC specific part:", substr($mac, 12-$ra_len)); |
116 | $out .= sprintf("%-32s 0x%s\n", "Vendor-specific part:", substr($mac, 12-$ra_len)); |
117 | $out .= sprintf("%-32s %s\n", "Registrant:", $x[0]); |
117 | $out .= sprintf("%-32s %s\n", "Registrant:", $x[0]); |
118 | foreach ($x as $n => $y) { |
118 | foreach ($x as $n => $y) { |
119 | if ($n == 0) continue; |
119 | if ($n == 0) continue; |
120 | else if ($n == 1) $out .= sprintf("%-32s %s\n", "Address of registrant:", $y); |
120 | else if ($n == 1) $out .= sprintf("%-32s %s\n", "Address of registrant:", $y); |
121 | else if ($n >= 2) $out .= sprintf("%-32s %s\n", "", $y); |
121 | else if ($n >= 2) $out .= sprintf("%-32s %s\n", "", $y); |
Line 265... | Line 265... | ||
265 | 265 | ||
266 | /** |
266 | /** |
267 | * |
267 | * |
268 | * ZYXM |
268 | * ZYXM |
269 | * 0 0000 EUI (OUI) |
269 | * 0 0000 EUI (OUI) |
270 | * 1 0001 |
270 | * 1 0001 [Multicast] |
271 | * 2 0010 AAI |
271 | * 2 0010 AAI |
272 | * 3 0011 |
272 | * 3 0011 [Multicast] |
273 | * 4 0100 EUI (OUI) |
273 | * 4 0100 EUI (OUI) |
274 | * 5 0101 |
274 | * 5 0101 [Multicast] |
275 | * 6 0110 Reserved |
275 | * 6 0110 Reserved |
276 | * 7 0111 |
276 | * 7 0111 [Multicast] |
277 | * 8 1000 EUI (OUI) |
277 | * 8 1000 EUI (OUI) |
278 | * 9 1001 |
278 | * 9 1001 [Multicast] |
279 | * A 1010 ELI (CID) |
279 | * A 1010 ELI (CID) |
280 | * B 1011 |
280 | * B 1011 [Multicast] |
281 | * C 1100 EUI (OUI) |
281 | * C 1100 EUI (OUI) |
282 | * D 1101 |
282 | * D 1101 [Multicast] |
283 | * E 1110 SAI |
283 | * E 1110 SAI |
284 | * F 1111 |
284 | * F 1111 [Multicast] |
285 | * |
285 | * |
286 | */ |
286 | */ |
287 | 287 | ||
288 | $type = ''; |
288 | $type = ''; |
289 | $tmp = ipv6linklocal_to_mac48($mac); |
289 | $tmp = ipv6linklocal_to_mac48($mac); |
Line 291... | Line 291... | ||
291 | $mac = $tmp; |
291 | $mac = $tmp; |
292 | $type = 'IPv6-Link-Local'; |
292 | $type = 'IPv6-Link-Local'; |
293 | } |
293 | } |
294 | if (!mac_valid($mac)) throw new Exception("Invalid MAC address"); |
294 | if (!mac_valid($mac)) throw new Exception("Invalid MAC address"); |
295 | if ($tmp === false) { |
295 | if ($tmp === false) { |
296 | if ($mac[1] == '2') { |
296 | if (($mac[1] == '2') || ($mac[1] == '3')) { |
297 | /* |
297 | /* |
298 | * AAI: Administratively Assigned Identifier |
298 | * AAI: Administratively Assigned Identifier |
299 | * Administrators who wish to assign local MAC addresses in an |
299 | * Administrators who wish to assign local MAC addresses in an |
300 | * arbitrary fashion (for example, randomly) and yet maintain |
300 | * arbitrary fashion (for example, randomly) and yet maintain |
301 | * compatibility with other assignment protocols operating under the |
301 | * compatibility with other assignment protocols operating under the |
302 | * SLAP on the same LAN may assign a local MAC address as AAI. |
302 | * SLAP on the same LAN may assign a local MAC address as AAI. |
303 | */ |
303 | */ |
304 | $type = 'AAI-' . eui_bits($mac).' (Administratively Assigned Identifier)'; |
304 | $type = 'AAI-' . eui_bits($mac).' (Administratively Assigned Identifier)'; |
305 | } else if ($mac[1] == '6') { |
305 | } else if (($mac[1] == '6') || ($mac[1] == '7')) { |
306 | /* |
306 | /* |
307 | * Reserved |
307 | * Reserved |
308 | * may be administratively used and assigned in accordance with the |
308 | * may be administratively used and assigned in accordance with the |
309 | * considerations specified for AAI usage, without effect on SLAP |
309 | * considerations specified for AAI usage, without effect on SLAP |
310 | * assignments. However, administrators should be cognizant of |
310 | * assignments. However, administrators should be cognizant of |
311 | * possible future specifications… that would render administrative |
311 | * possible future specifications… that would render administrative |
312 | * assignment incompatible with the SLAP. |
312 | * assignment incompatible with the SLAP. |
313 | */ |
313 | */ |
314 | $type = 'Reserved-' . eui_bits($mac); |
314 | $type = 'Reserved-' . eui_bits($mac); |
315 | } else if ($mac[1] == 'A') { |
315 | } else if (($mac[1] == 'A') || ($mac[1] == 'B')) { |
316 | /* |
316 | /* |
317 | * ELI: Extended Local Identifier |
317 | * ELI: Extended Local Identifier |
318 | * An ELI is based on a 24 bit CID |
318 | * An ELI is based on a 24 bit CID |
319 | * A CID has ZYXM bits set to 1010 (0b1010 = 0xA) |
319 | * A CID has ZYXM bits set to 1010 (0b1010 = 0xA) |
320 | * Since X=1 (U/L=1), the CID cannot be used to form a universal UAA MAC (only a local LAA MAC) |
320 | * Since X=1 (U/L=1), the CID cannot be used to form a universal UAA MAC (only a local LAA MAC) |
321 | */ |
321 | */ |
322 | $type = 'ELI-' . eui_bits($mac).' (Extended Local Identifier)'; |
322 | $type = 'ELI-' . eui_bits($mac).' (Extended Local Identifier)'; |
323 | } else if ($mac[1] == 'E') { |
323 | } else if (($mac[1] == 'E') || ($mac[1] == 'F')) { |
324 | /* |
324 | /* |
325 | * SAI: Standard Assigned Identifier |
325 | * SAI: Standard Assigned Identifier |
326 | * Specification of the use of the SAI quadrant for SLAP address |
326 | * Specification of the use of the SAI quadrant for SLAP address |
327 | * assignments is reserved for the standard forthcoming from IEEE |
327 | * assignments is reserved for the standard forthcoming from IEEE |
328 | * P802.1CQ. |
328 | * P802.1CQ. |
Line 335... | Line 335... | ||
335 | * and bridges that recognize the specific SAI assignment protocol, as |
335 | * and bridges that recognize the specific SAI assignment protocol, as |
336 | * identified by the subspace of the SAI. The functionality of receivers |
336 | * identified by the subspace of the SAI. The functionality of receivers |
337 | * and bridges that do not recognize the protocol is not affected. |
337 | * and bridges that do not recognize the protocol is not affected. |
338 | */ |
338 | */ |
339 | $type = 'SAI-' . eui_bits($mac).' (Standard Assigned Identifier)'; |
339 | $type = 'SAI-' . eui_bits($mac).' (Standard Assigned Identifier)'; |
340 | } else if ((hexdec($mac[1])&1) == 1) { |
340 | } else { |
341 | $type = 'Multicast MAC-'.eui_bits($mac); |
- | |
342 | } else if (($mac[1] == '0') || ($mac[1] == '4') || ($mac[1] == '8') || ($mac[1] == 'C')) { |
- | |
343 | /* |
341 | /* |
344 | * Extended Unique Identifier |
342 | * Extended Unique Identifier |
345 | * Based on an OUI-24, OUI-28, or OUI-36 |
343 | * Based on an OUI-24, OUI-28, or OUI-36 |
346 | */ |
344 | */ |
347 | if (eui_bits($mac) == 48) { |
345 | if (eui_bits($mac) == 48) { |
Line 363... | Line 361... | ||
363 | } else { |
361 | } else { |
364 | assert(false); /** @phpstan-ignore-line */ |
362 | assert(false); /** @phpstan-ignore-line */ |
365 | } |
363 | } |
366 | } |
364 | } |
367 | } |
365 | } |
- | 366 | ||
- | 367 | if ((hexdec($mac[1])&1) == 1) { |
|
- | 368 | // Question: https://networkengineering.stackexchange.com/questions/83121/can-eli-aai-sai-addresses-be-multicast |
|
- | 369 | // Are there "Multicast ELI", "Multicast AAI", "Multicast SAI"? |
|
- | 370 | // Some documents of IEEE suggest this, but I am not 100% sure! |
|
- | 371 | ||
- | 372 | /* https://standards.ieee.org/wp-content/uploads/import/documents/tutorials/eui.pdf writes: |
|
- | 373 | * - The assignee of an OUI or OUI-36 is exclusively authorized to assign group |
|
- | 374 | * MAC addresses, with I/G=1, by extending a modified version of the assigned |
|
- | 375 | * OUI or OUI-36 in which the M bit is set to 1. Such addresses are not EUIs and |
|
- | 376 | * do not globally identify hardware instances, even though U/L=0. |
|
- | 377 | * - The assignee of a CID may assign local group MAC addresses by extending a modified version of |
|
- | 378 | * the assigned CID by setting the M bit to 1 (so that I/G=1). The resulting |
|
- | 379 | * extended identifier is an ELI. |
|
- | 380 | */ |
|
- | 381 | ||
- | 382 | // TODO: If "Multicast EUI" is not an EUI, how should we name it instead?! |
|
- | 383 | $type = "Multicast $type"; |
|
- | 384 | } |
|
- | 385 | ||
368 | return $type; |
386 | return $type; |
369 | } |
387 | } |
370 | 388 | ||
371 | /** |
389 | /** |
372 | * Prints information about an IPv6-Link-Local address, MAC, EUI, ELI, AAI, or SAI. |
390 | * Prints information about an IPv6-Link-Local address, MAC, EUI, ELI, AAI, or SAI. |
Line 375... | Line 393... | ||
375 | * @throws Exception |
393 | * @throws Exception |
376 | */ |
394 | */ |
377 | function decode_mac(string $mac) { |
395 | function decode_mac(string $mac) { |
378 | 396 | ||
379 | // TODO: Should we decode Multicast MAC to its IP (see https://ipcisco.com/lesson/multicast-mac-addresses/)? |
397 | // TODO: Should we decode Multicast MAC to its IP (see https://ipcisco.com/lesson/multicast-mac-addresses/)? |
380 | // TODO: Is an ELI with M=1 a Multicast-ELI, or isn't it an ELI anymore? Same question for SAI and AAI |
- | |
381 | 398 | ||
382 | echo sprintf("%-32s %s\n", "Input:", $mac); |
399 | echo sprintf("%-32s %s\n", "Input:", $mac); |
383 | 400 | ||
384 | // Format MAC for machine readability |
401 | // Format MAC for machine readability |
385 | $mac = mac_canonize($mac, ''); |
402 | $mac = mac_canonize($mac, ''); |
Line 423... | Line 440... | ||
423 | $ig_ = ($ig == 0) ? '[0] Unicast (Individual)' : '[1] Multicast (Group)'; |
440 | $ig_ = ($ig == 0) ? '[0] Unicast (Individual)' : '[1] Multicast (Group)'; |
424 | echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_); |
441 | echo sprintf("%-32s %s\n", "Transmission type (I/G flag):", $ig_); |
425 | 442 | ||
426 | // Query IEEE registries |
443 | // Query IEEE registries |
427 | if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) { |
444 | if (count(glob(IEEE_MAC_REGISTRY.DIRECTORY_SEPARATOR.'*.txt')) > 0) { |
- | 445 | $alt_mac = $mac; |
|
- | 446 | $alt_mac[1] = dechex(hexdec($alt_mac[1])^1); // switch Unicat<=>Multicast in order to find the vendor |
|
- | 447 | ||
428 | if ($mac[1] == 'A') { |
448 | if ($mac[1] == 'A') { |
429 | // Query the CID registry |
449 | // Query the CID registry |
430 | if ( |
450 | if ( |
431 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $mac)) |
451 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $mac)) || |
- | 452 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'cid.txt', 'CID', $alt_mac)) |
|
432 | ) { |
453 | ) { |
433 | echo $x; |
454 | echo $x; |
434 | } |
455 | } |
435 | } else { |
456 | } else { |
436 | // Query the OUI registries |
457 | // Query the OUI registries |
437 | // TODO: Should we try to convert Unicast<=>Multicast if one of them can't be found? |
- | |
438 | if ( |
458 | if ( |
439 | # The IEEE Registration Authority distinguishes between IABs and OUI-36 values. Both are 36-bit values which may be used to generate EUI-48 values, but IABs may not be used to generate EUI-64 values.[6] |
459 | # The IEEE Registration Authority distinguishes between IABs and OUI-36 values. Both are 36-bit values which may be used to generate EUI-48 values, but IABs may not be used to generate EUI-64 values.[6] |
440 | # Note: The Individual Address Block (IAB) is an inactive registry activity, which has been replaced by the MA-S registry product as of January 1, 2014. |
460 | # Note: The Individual Address Block (IAB) is an inactive registry activity, which has been replaced by the MA-S registry product as of January 1, 2014. |
441 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) || |
461 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $mac)) || |
442 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $mac)) || |
462 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $mac)) || |
- | 463 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', '28 bit identifier (MA-M)', $mac)) || |
|
443 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', 'OUI-28 (MA-M)', $mac)) || |
464 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI (MA-L)', $mac)) || |
- | 465 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'iab.txt', 'IAB', $alt_mac)) || |
|
- | 466 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui36.txt', 'OUI-36 (MA-S)', $alt_mac)) || |
|
- | 467 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'mam.txt', '28 bit identifier (MA-M)', $alt_mac)) || |
|
444 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI-24 (MA-L)', $mac)) |
468 | ($x = _lookup_ieee_registry(IEEE_MAC_REGISTRY . DIRECTORY_SEPARATOR . 'oui.txt', 'OUI (MA-L)', $alt_mac)) |
445 | ) { |
469 | ) { |
446 | echo $x; |
470 | echo $x; |
447 | } |
471 | } |
448 | } |
472 | } |
449 | } |
473 | } |