1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using System.Net.NetworkInformation; 10 using System.Globalization; 11 using Antmicro.Renode.Utilities; 12 13 namespace Antmicro.Renode.Core.Structure 14 { 15 [Convertible] 16 public struct MACAddress : IEquatable<MACAddress> 17 { 18 public byte A { get; private set; } 19 20 public byte B { get; private set; } 21 22 public byte C { get; private set; } 23 24 public byte D { get; private set; } 25 26 public byte E { get; private set; } 27 28 public byte F { get; private set; } 29 30 public byte[] Bytes { get { return new [] { A, B, C, D, E, F }; } } 31 MACAddressAntmicro.Renode.Core.Structure.MACAddress32 public MACAddress(ulong address) : this() 33 { 34 A = (byte)(address >> 40); 35 B = (byte)(address >> 32); 36 C = (byte)(address >> 24); 37 D = (byte)(address >> 16); 38 E = (byte)(address >> 8); 39 F = (byte)address; 40 } 41 42 public static MACAddress Default { get { return new MACAddress(); } } 43 44 public MACAddress WithNewOctets(byte? a = null, byte? b = null, byte? c = null, byte? d = null, byte? e = null, byte? f = null) 45 { 46 var result = new MACAddress(); 47 result.A = a ?? A; 48 result.B = b ?? B; 49 result.C = c ?? C; 50 result.D = d ?? D; 51 result.E = e ?? E; 52 result.F = f ?? F; 53 return result; 54 } 55 NextAntmicro.Renode.Core.Structure.MACAddress56 public MACAddress Next(int count = 1) 57 { 58 for(var i = 0; i < count; i++) 59 { 60 InnerNext(); 61 } 62 63 return this; 64 } 65 PreviousAntmicro.Renode.Core.Structure.MACAddress66 public MACAddress Previous() 67 { 68 var result = this; 69 70 var cp = 5; 71 while(true) 72 { 73 if(result.GetByte(cp) == 0) 74 { 75 if(cp == 0) 76 { 77 throw new OverflowException(); 78 } 79 cp--; 80 } 81 else 82 { 83 result.SetByte(cp, (byte)(result.GetByte(cp) - 1)); 84 for(int i = cp + 1; i < 6; i++) 85 { 86 result.SetByte(i, byte.MaxValue); 87 } 88 break; 89 } 90 } 91 92 return result; 93 } 94 GetBytesAntmicro.Renode.Core.Structure.MACAddress95 public byte[] GetBytes() 96 { 97 var bytes = new byte[6]; 98 for(var i = 0; i < 6; ++i) 99 { 100 bytes[i] = GetByte(i); 101 } 102 return bytes; 103 } 104 EqualsAntmicro.Renode.Core.Structure.MACAddress105 public override bool Equals(object obj) 106 { 107 if(obj == null) 108 { 109 return false; 110 } 111 if(obj.GetType() != typeof(MACAddress)) 112 { 113 return false; 114 } 115 var other = (MACAddress)obj; 116 return this == other; 117 } 118 GetHashCodeAntmicro.Renode.Core.Structure.MACAddress119 public override int GetHashCode() 120 { 121 unchecked 122 { 123 return A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode() ^ E.GetHashCode() ^ F.GetHashCode(); 124 } 125 } 126 TryParseAntmicro.Renode.Core.Structure.MACAddress127 public static bool TryParse(string str, out MACAddress result) 128 { 129 result = default(MACAddress); 130 131 var splits = str.Split(':'); 132 if(splits.Length != 6) 133 { 134 return false; 135 } 136 137 for(var i = 0; i < 6; i++) 138 { 139 result.SetByte(i, byte.Parse(splits[i], NumberStyles.HexNumber)); 140 } 141 142 return true; 143 } 144 ParseAntmicro.Renode.Core.Structure.MACAddress145 public static MACAddress Parse(string str) 146 { 147 if(!TryParse(str, out var result)) 148 { 149 throw new FormatException(); 150 } 151 152 return result; 153 } 154 FromBytesAntmicro.Renode.Core.Structure.MACAddress155 public static MACAddress FromBytes(byte[] array, int startingIndex = 0) 156 { 157 var result = new MACAddress(); 158 for(var i = 0; i < 6; i++) 159 { 160 result.SetByte(i, array[startingIndex + i]); 161 } 162 return result; 163 } 164 165 public bool IsBroadcast 166 { 167 get 168 { 169 return A == 0xFF && B == 0xFF && C == 0xFF && D == 0xFF && E == 0xFF && F == 0xFF; 170 } 171 } 172 173 public bool IsMulticast 174 { 175 get 176 { 177 return A == 0x01 && B == 0x00 && C == 0x5E; 178 } 179 } 180 181 public bool IsUnicast 182 { 183 get 184 { 185 return !IsBroadcast && !IsMulticast; 186 } 187 } 188 ToStringAntmicro.Renode.Core.Structure.MACAddress189 public override string ToString() 190 { 191 return string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", A, B, C, D, E, F); 192 } 193 operator MACAddressAntmicro.Renode.Core.Structure.MACAddress194 public static explicit operator MACAddress(PhysicalAddress address) 195 { 196 return MACAddress.FromBytes(address.GetAddressBytes()); 197 } 198 operator PhysicalAddressAntmicro.Renode.Core.Structure.MACAddress199 public static explicit operator PhysicalAddress(MACAddress address) 200 { 201 return new PhysicalAddress(address.GetBytes()); 202 } 203 operator stringAntmicro.Renode.Core.Structure.MACAddress204 public static explicit operator string(MACAddress m) 205 { 206 return m.ToString(); 207 } 208 operator MACAddressAntmicro.Renode.Core.Structure.MACAddress209 public static explicit operator MACAddress(string input) 210 { 211 return MACAddress.Parse(input); 212 } 213 EqualsAntmicro.Renode.Core.Structure.MACAddress214 public bool Equals(MACAddress other) 215 { 216 return this == other; 217 } 218 operator ==Antmicro.Renode.Core.Structure.MACAddress219 public static bool operator ==(MACAddress a, MACAddress b) 220 { 221 return a.A == b.A && a.B == b.B && a.C == b.C && a.D == b.D && a.E == b.E && a.F == b.F; 222 } 223 operator !=Antmicro.Renode.Core.Structure.MACAddress224 public static bool operator !=(MACAddress a, MACAddress b) 225 { 226 return !(a == b); 227 } 228 InnerNextAntmicro.Renode.Core.Structure.MACAddress229 private void InnerNext() 230 { 231 var cp = 5; 232 while(true) 233 { 234 if(this.GetByte(cp) == byte.MaxValue) 235 { 236 if(cp == 0) 237 { 238 throw new OverflowException(); 239 } 240 cp--; 241 } 242 else 243 { 244 this.SetByte(cp, (byte)(this.GetByte(cp) + 1)); 245 for(int i = cp + 1; i < 6; i++) 246 { 247 this.SetByte(i, 0); 248 } 249 break; 250 } 251 } 252 } 253 GetByteAntmicro.Renode.Core.Structure.MACAddress254 private byte GetByte(int index) 255 { 256 switch(index) 257 { 258 case 0: 259 return A; 260 case 1: 261 return B; 262 case 2: 263 return C; 264 case 3: 265 return D; 266 case 4: 267 return E; 268 case 5: 269 return F; 270 default: 271 throw new ArgumentException(); 272 } 273 } 274 SetByteAntmicro.Renode.Core.Structure.MACAddress275 private void SetByte(int index, byte value) 276 { 277 switch(index) 278 { 279 case 0: 280 A = value; 281 break; 282 case 1: 283 B = value; 284 break; 285 case 2: 286 C = value; 287 break; 288 case 3: 289 D = value; 290 break; 291 case 4: 292 E = value; 293 break; 294 case 5: 295 F = value; 296 break; 297 default: 298 throw new ArgumentException(); 299 } 300 } 301 } 302 } 303 304