336 lines
11 KiB
C#
336 lines
11 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity / Netstack
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: EthernetAddress.cs
|
||
|
//
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
|
||
|
namespace Drivers.Net
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Structure representing an Ethernet address.
|
||
|
/// </summary>
|
||
|
public struct EthernetAddress : IComparable
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Length of an Ethernet address in bytes.
|
||
|
/// </summary>
|
||
|
public const int Length = 6;
|
||
|
|
||
|
private uint u03; // bytes 0-3
|
||
|
private ushort u45; // bytes 4-5
|
||
|
|
||
|
/// <summary>
|
||
|
/// Ethernet broadcast address.
|
||
|
/// </summary>
|
||
|
public static readonly EthernetAddress Broadcast =
|
||
|
new EthernetAddress(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
|
||
|
|
||
|
/// <summary>
|
||
|
/// The all-zeros address.
|
||
|
/// </summary>
|
||
|
public static readonly EthernetAddress Zero =
|
||
|
new EthernetAddress(0, 0, 0, 0, 0, 0);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Bridge Group Address.
|
||
|
/// Reserved by IEEE 802.1D, Table 7-9, 1998 Edition:
|
||
|
/// ...-00 is the Bridge Group Address, used for Spanning Tree Protocol
|
||
|
/// </summary>
|
||
|
public static readonly EthernetAddress Bridge =
|
||
|
new EthernetAddress(0x01, 0x80, 0xC2, 0x00, 0x00, 0x00);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Full Duplex PAUSE operation address.
|
||
|
/// </summary>
|
||
|
public static readonly EthernetAddress PAUSE =
|
||
|
new EthernetAddress(0x01, 0x80, 0xC2, 0x00, 0x00, 0x01);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor.
|
||
|
/// </summary>
|
||
|
/// <param name="pa0">Most significant byte</param>
|
||
|
/// <param name="pa1">Second most significant byte</param>
|
||
|
/// <param name="pa2"></param>
|
||
|
/// <param name="pa3"></param>
|
||
|
/// <param name="pa4"></param>
|
||
|
/// <param name="pa5">Least significant byte</param>
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts an string into an EthernetAddress instance.
|
||
|
/// </summary>
|
||
|
/// <exception cref="ArgumentNullException">Thrown if
|
||
|
/// <c>macString</c> is null.</exception>
|
||
|
/// <returns> <c>true</c> on success, <c>false</c> on failure.</returns>
|
||
|
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
|