///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity / Netstack
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
using System;
namespace Drivers.Net
{
///
/// Structure representing an Ethernet address.
///
public struct EthernetAddress : IComparable
{
///
/// Length of an Ethernet address in bytes.
///
public const int Length = 6;
private uint u03; // bytes 0-3
private ushort u45; // bytes 4-5
///
/// Ethernet broadcast address.
///
public static readonly EthernetAddress Broadcast =
new EthernetAddress(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
///
/// The all-zeros address.
///
public static readonly EthernetAddress Zero =
new EthernetAddress(0, 0, 0, 0, 0, 0);
///
/// Bridge Group Address.
/// Reserved by IEEE 802.1D, Table 7-9, 1998 Edition:
/// ...-00 is the Bridge Group Address, used for Spanning Tree Protocol
///
public static readonly EthernetAddress Bridge =
new EthernetAddress(0x01, 0x80, 0xC2, 0x00, 0x00, 0x00);
///
/// Full Duplex PAUSE operation address.
///
public static readonly EthernetAddress PAUSE =
new EthernetAddress(0x01, 0x80, 0xC2, 0x00, 0x00, 0x01);
///
/// Constructor.
///
/// Most significant byte
/// Second most significant byte
///
///
///
/// Least significant byte
public EthernetAddress(byte pa0, byte pa1, byte pa2,
byte pa3, byte pa4, byte pa5)
{
u03 = ((uint)pa0) << 24;
u03 |= ((uint)pa1) << 16;
u03 |= ((uint)pa2) << 8;
u03 |= ((uint)pa3);
u45 = (ushort)((int)pa4 << 8);
u45 |= (ushort)pa5;
}
public EthernetAddress(byte [] addressBytes)
{
if (addressBytes == null) {
throw new ArgumentNullException();
}
if (addressBytes.Length != Length) {
throw new ArgumentException();
}
u03 = ((uint)addressBytes[0]) << 24;
u03 |= ((uint)addressBytes[1]) << 16;
u03 |= ((uint)addressBytes[2]) << 8;
u03 |= ((uint)addressBytes[3]);
u45 = (ushort)((int)addressBytes[4] << 8);
u45 |= (ushort)addressBytes[5];
}
private EthernetAddress(uint u03, ushort u45)
{
this.u03 = u03;
this.u45 = u45;
}
public EthernetAddress(EthernetAddress other)
{
this.u03 = other.u03;
this.u45 = other.u45;
}
public static bool operator < (EthernetAddress lhs,
EthernetAddress rhs)
{
if (lhs.u03 != rhs.u03)
return lhs.u03 < rhs.u03;
return lhs.u45 < rhs.u45;
}
public static bool operator <= (EthernetAddress lhs,
EthernetAddress rhs)
{
if (lhs.u03 > rhs.u03)
return false;
return lhs.u45 <= rhs.u45;
}
public static bool operator > (EthernetAddress lhs,
EthernetAddress rhs)
{
if (lhs.u03 != rhs.u03)
return lhs.u03 > rhs.u03;
return lhs.u45 > rhs.u45;
}
public static bool operator >= (EthernetAddress lhs,
EthernetAddress rhs)
{
if (lhs.u03 < rhs.u03)
return false;
return lhs.u45 >= rhs.u45;
}
public static bool operator == (EthernetAddress lhs,
EthernetAddress rhs)
{
return (lhs.u03 == rhs.u03) && (lhs.u45 == rhs.u45);
}
public static bool operator != (EthernetAddress lhs,
EthernetAddress rhs)
{
return !(lhs == rhs);
}
public static EthernetAddress operator & (EthernetAddress lhs,
EthernetAddress rhs)
{
return new EthernetAddress(lhs.u03 & rhs.u03,
(ushort) (lhs.u45 & rhs.u45));
}
public static EthernetAddress operator | (EthernetAddress lhs,
EthernetAddress rhs)
{
return new EthernetAddress(lhs.u03 | rhs.u03,
(ushort) (lhs.u45 | rhs.u45));
}
public static EthernetAddress operator ^ (EthernetAddress lhs,
EthernetAddress rhs)
{
return new EthernetAddress(lhs.u03 ^ rhs.u03,
(ushort) (lhs.u45 ^ rhs.u45));
}
public static EthernetAddress operator ~ (EthernetAddress ea)
{
return new EthernetAddress(~ea.u03, (ushort) (~ea.u45));
}
public static EthernetAddress operator ++ (EthernetAddress ea)
{
ushort u45 = (ushort) (ea.u45 + 1);
if (u45 > ea.u45)
return new EthernetAddress(ea.u03, u45);
uint u03 = ea.u03 + 1;
return new EthernetAddress(u03, u45);
}
public static EthernetAddress operator -- (EthernetAddress ea)
{
ushort u45 = (ushort) (ea.u45 - 1);
if (u45 < ea.u45)
return new EthernetAddress(ea.u03, u45);
uint u03 = ea.u03 - 1;
return new EthernetAddress(u03, u45);
}
public override bool Equals(object o)
{
if (o is EthernetAddress) {
return this == (EthernetAddress) o;
}
return false;
}
public byte[]! GetAddressBytes()
{
return new byte[6] {
(byte)(u03 >> 24), (byte)(u03 >> 16), (byte)(u03 >> 8),
(byte)(u03), (byte)(u45 >> 8), (byte)(u45)
};
}
public override int GetHashCode()
{
return (int)u03 ^ (int)u45;
}
public override string! ToString()
{
return String.Format("{0:x2}:{1:x2}:{2:x2}:{3:x2}:{4:x2}:{5:x2}",
(byte)(u03 >> 24), (byte)(u03 >> 16),
(byte)(u03 >> 8), (byte)(u03),
(byte)(u45 >> 8), (byte)(u45));
}
// returns the address with custom separator, so it can
// be used as a filename.
public string ToString(string separator)
{
return String.Format("{0:x2}{6}{1:x2}{6}{2:x2}{6}" +
"{3:x2}{6}{4:x2}{6}{5:x2}",
(byte)(u03 >> 24), (byte)(u03 >> 16),
(byte)(u03 >> 8), (byte)(u03),
(byte)(u45 >> 8), (byte)(u45),
separator);
}
// accepts either aa:bb:cc:dd:ee:ff (widely used) or
// aa-bb-cc-dd-ee-ff (IEEE) formats
public static EthernetAddress Parse(string raw)
{
const string hexdigits = "00112233445566778899aAbBcCdDeEfF";
char [] separators = {'-', ':'};
if (raw == null)
throw new ArgumentNullException();
byte [] b = new byte[6];
string [] tokens = raw.Split(separators);
if (tokens.Length != 6)
throw new FormatException();
for (int i = 0; i < 6; i++) {
string ti = (!)tokens[i];
if (ti.Length != 2)
throw new FormatException();
int u = hexdigits.IndexOf(ti[0]);
int l = hexdigits.IndexOf(ti[1]);
if ((u < 0) || (l < 0))
throw new FormatException();
// Note there are 32 digits in hexdigits so we divide by 2
u >>= 1;
l >>= 1;
b[i] = (byte)(((u << 4) & 0xf0) | l);
}
return new EthernetAddress(b);
}
///
/// Converts an string into an EthernetAddress instance.
///
/// Thrown if
/// macString is null.
/// true on success, false on failure.
public static bool Parse(string macString, out EthernetAddress address)
{
try {
address = Parse(macString);
}
catch (FormatException) {
address = EthernetAddress.Zero;
return false;
}
return true;
}
public static EthernetAddress ParseBytes(byte[] data, int offset)
{
if (data == null) {
throw new ArgumentNullException();
}
if (data.Length - offset < Length) {
throw new ArgumentException("Byte array too short.");
}
return new EthernetAddress(data[offset], data[offset + 1],
data[offset + 2], data[offset + 3],
data[offset + 4], data[offset + 5]);
}
public static EthernetAddress ParseBytes(byte[] data)
{
return new EthernetAddress(data);
}
public int CopyOut(byte []! buffer, int outputOffset)
{
buffer[outputOffset + 0] = (byte)(u03 >> 24);
buffer[outputOffset + 1] = (byte)(u03 >> 16);
buffer[outputOffset + 2] = (byte)(u03 >> 8);
buffer[outputOffset + 3] = (byte)(u03);
buffer[outputOffset + 4] = (byte)(u45 >> 8);
buffer[outputOffset + 5] = (byte)(u45);
return Length;
}
public int CompareTo(object other)
{
if (other == null)
return 1;
if (other is EthernetAddress) {
EthernetAddress value = (EthernetAddress) other;
if (this < value) return -1;
if (this > value) return + 1;
return 0;
}
throw new ArgumentException ("Arg_MustBeEthernetAddress");
}
}
} // namespace Drivers.Net