package com.netifera.platform.util.addresses;
import java.io.Serializable;
import java.util.Arrays;
/*
* a MAC address is not formally a Network address, it is an Hardware address.
*
* see http://standards.ieee.org/regauth/oui/tutorials/UseOfEUI.html
*/
/**
* Media Access Control address (MAC address) or Ethernet Hardware Address (EHA)
*/
abstract class AbstractMACAddress implements IHardwareAddress,
Serializable {
private static final long serialVersionUID = -6362575938645715808L;
protected static final int OUI_SIZE = 3;
protected final byte[] bytes;
private final int length; /* java bytes */
protected AbstractMACAddress(final int length, final byte[] bytes) {
assert length > OUI_SIZE : "Invalid MAC format";
if (bytes.length != length) {
throw new AddressFormatException("Invalid MAC address length:" +
bytes.length);
}
this.length = length;
this.bytes = bytes.clone();
}
protected AbstractMACAddress(final int length, final String address) {
this.length = length;
this.bytes = parseString(address);
}
public int getDataSize() {
return length * 8;
}
private byte[] parseString(String address) {
String[] parts = null;
if (address.contains(":")) {
parts = address.split(":");
} else if (address.contains("-")) {
parts = address.split("-");
} else if (address.contains(".") && address.startsWith("0x")) {
String[] p = address.substring(2).split("\\.");
if (p.length != length/2) {
throw new AddressFormatException("Invalid MAC address format:"
+ address);
}
parts = new String[length];
for (int i = 0; i < length/2; i++) {
int len = p[i].length();
if (len > 2) {
parts[2 * i] = p[i].substring(0, len - 2);
parts[(2 * i) + 1] = p[i].substring(2);
} else {
parts[2 * i] = "00";
parts[(2 * i) + 1] = p[i];
}
}
}
if (parts == null || parts.length != length) {
throw new AddressFormatException("Invalid MAC address format:" +
address);
}
byte[] bytes = new byte[length];
for (int i=0; i<length; i++) {
bytes[i] = (byte) Integer.parseInt(parts[i], 16);
}
return bytes;
}
public byte[] toBytes() {
return bytes.clone();
}
/**
* The Organizationally Unique Identifier
*/
public byte[] getOUI() {
byte[] oui = new byte[OUI_SIZE];
System.arraycopy(bytes, 0, oui, 0, OUI_SIZE);
return oui;
}
public byte[] getNIC() {
byte[] nic = new byte[length - OUI_SIZE];
System.arraycopy(bytes, OUI_SIZE, nic, 0, length - OUI_SIZE);
return nic;
}
public boolean isUnicast() {
return (bytes[0] & 1) == 0;
}
public boolean isMulticast() {
return (bytes[0] & 1) != 0;
}
public boolean isBroadcast() {
for (byte x: bytes) {
if ((x & 0xFF) != 255) {
return false;
}
}
return true;
}
public boolean isGloballyUnique() {
return (bytes[0] & 2) == 0;
}
public boolean isLocallyAdministered() {
return (bytes[0] & 2) != 0;
}
@Override
public int hashCode() {
int answer = 0;
for (byte x: bytes) {
answer = answer*256 + (x & 0xFF);
}
return answer;
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof AbstractMACAddress)) {
return false;
}
return Arrays.equals(bytes, ((AbstractMACAddress)obj).toBytes());
}
@Override
public String toString() {
return bytesToString(length, bytes);
}
protected static String bytesToString(int length, final byte[] bytes) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < length; i++) {
if (i > 0) {
buffer.append(':');
}
buffer.append(String.format("%02x", Integer.valueOf(bytes[i] & 0xff)));
}
return buffer.toString();
}
}